Patch to add new api to logsys to get priority names from subsystem names.
[openais.git] / lib / util.c
bloba9b23b8c238433137a68c1a31a3b856c75b5f08a
1 /*
2 * vi: set autoindent tabstop=4 shiftwidth=4 :
4 * Copyright (c) 2002-2006 MontaVista Software, Inc.
5 * Copyright (c) 2006 Sun Microsystems, Inc.
7 * All rights reserved.
9 * Author: Steven Dake (sdake@mvista.com)
11 * This software licensed under BSD license, the text of which follows:
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
16 * - Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * - Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * - Neither the name of the MontaVista Software, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <fcntl.h>
44 #include <sys/ioctl.h>
45 #include <sys/types.h>
46 #include <sys/uio.h>
47 #include <sys/socket.h>
48 #include <sys/select.h>
49 #include <sys/time.h>
50 #include <sys/un.h>
51 #include <net/if.h>
52 #include <arpa/inet.h>
53 #include <netinet/in.h>
54 #include <assert.h>
56 #include <saAis.h>
57 #include <ipc_gen.h>
58 #include <ais_util.h>
60 enum SA_HANDLE_STATE {
61 SA_HANDLE_STATE_EMPTY,
62 SA_HANDLE_STATE_PENDINGREMOVAL,
63 SA_HANDLE_STATE_ACTIVE
66 struct saHandle {
67 int state;
68 void *instance;
69 int refCount;
70 uint32_t check;
73 #ifdef OPENAIS_SOLARIS
74 #define MSG_NOSIGNAL 0
75 #endif
77 #if defined(OPENAIS_LINUX) || defined(OPENAIS_SOLARIS)
78 /* SUN_LEN is broken for abstract namespace
80 #define AIS_SUN_LEN(a) sizeof(*(a))
81 #else
82 #define AIS_SUN_LEN(a) SUN_LEN(a)
83 #endif
85 #ifdef OPENAIS_LINUX
86 static char *socketname = "libais.socket";
87 #else
88 static char *socketname = "/var/run/libais.socket";
89 #endif
91 #ifdef SO_NOSIGPIPE
92 void socket_nosigpipe(int s)
94 int on = 1;
95 setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
97 #endif
99 SaAisErrorT
100 saServiceConnect (
101 int *responseOut,
102 int *callbackOut,
103 enum service_types service)
105 int responseFD;
106 int callbackFD;
107 int result;
108 struct sockaddr_un address;
109 mar_req_lib_response_init_t req_lib_response_init;
110 mar_res_lib_response_init_t res_lib_response_init;
111 mar_req_lib_dispatch_init_t req_lib_dispatch_init;
112 mar_res_lib_dispatch_init_t res_lib_dispatch_init;
113 SaAisErrorT error;
114 gid_t egid;
117 * Allow set group id binaries to be authenticated
119 egid = getegid();
120 setregid (egid, -1);
122 memset (&address, 0, sizeof (struct sockaddr_un));
123 #if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
124 address.sun_len = sizeof(struct sockaddr_un);
125 #endif
126 address.sun_family = PF_UNIX;
127 #if defined(OPENAIS_LINUX)
128 strcpy (address.sun_path + 1, socketname);
129 #else
130 strcpy (address.sun_path, socketname);
131 #endif
132 responseFD = socket (PF_UNIX, SOCK_STREAM, 0);
133 if (responseFD == -1) {
134 return (SA_AIS_ERR_NO_RESOURCES);
137 socket_nosigpipe (responseFD);
139 result = connect (responseFD, (struct sockaddr *)&address, AIS_SUN_LEN(&address));
140 if (result == -1) {
141 close (responseFD);
142 return (SA_AIS_ERR_TRY_AGAIN);
145 req_lib_response_init.resdis_header.size = sizeof (req_lib_response_init);
146 req_lib_response_init.resdis_header.id = MESSAGE_REQ_RESPONSE_INIT;
147 req_lib_response_init.resdis_header.service = service;
149 error = saSendRetry (responseFD, &req_lib_response_init,
150 sizeof (mar_req_lib_response_init_t));
151 if (error != SA_AIS_OK) {
152 goto error_exit;
154 error = saRecvRetry (responseFD, &res_lib_response_init,
155 sizeof (mar_res_lib_response_init_t));
156 if (error != SA_AIS_OK) {
157 goto error_exit;
161 * Check for security errors
163 if (res_lib_response_init.header.error != SA_AIS_OK) {
164 error = res_lib_response_init.header.error;
165 goto error_exit;
168 *responseOut = responseFD;
170 /* if I comment out the 4 lines below the executive crashes */
171 callbackFD = socket (PF_UNIX, SOCK_STREAM, 0);
172 if (callbackFD == -1) {
173 close (responseFD);
174 return (SA_AIS_ERR_NO_RESOURCES);
177 socket_nosigpipe (callbackFD);
179 result = connect (callbackFD, (struct sockaddr *)&address, AIS_SUN_LEN(&address));
180 if (result == -1) {
181 close (callbackFD);
182 close (responseFD);
183 return (SA_AIS_ERR_TRY_AGAIN);
186 req_lib_dispatch_init.resdis_header.size = sizeof (req_lib_dispatch_init);
187 req_lib_dispatch_init.resdis_header.id = MESSAGE_REQ_DISPATCH_INIT;
188 req_lib_dispatch_init.resdis_header.service = service;
190 req_lib_dispatch_init.conn_info = res_lib_response_init.conn_info;
192 error = saSendRetry (callbackFD, &req_lib_dispatch_init,
193 sizeof (mar_req_lib_dispatch_init_t));
194 if (error != SA_AIS_OK) {
195 goto error_exit_two;
197 error = saRecvRetry (callbackFD, &res_lib_dispatch_init,
198 sizeof (mar_res_lib_dispatch_init_t));
199 if (error != SA_AIS_OK) {
200 goto error_exit_two;
204 * Check for security errors
206 if (res_lib_dispatch_init.header.error != SA_AIS_OK) {
207 error = res_lib_dispatch_init.header.error;
208 goto error_exit;
211 *callbackOut = callbackFD;
212 return (SA_AIS_OK);
214 error_exit_two:
215 close (callbackFD);
216 error_exit:
217 close (responseFD);
218 return (error);
221 SaAisErrorT
222 saRecvRetry (
223 int s,
224 void *msg,
225 size_t len)
227 SaAisErrorT error = SA_AIS_OK;
228 int result;
229 struct msghdr msg_recv;
230 struct iovec iov_recv;
231 char *rbuf = (char *)msg;
232 int processed = 0;
234 msg_recv.msg_iov = &iov_recv;
235 msg_recv.msg_iovlen = 1;
236 msg_recv.msg_name = 0;
237 msg_recv.msg_namelen = 0;
238 #ifndef OPENAIS_SOLARIS
239 msg_recv.msg_control = 0;
240 msg_recv.msg_controllen = 0;
241 msg_recv.msg_flags = 0;
242 #else
243 msg_recv.msg_accrights = NULL;
244 msg_recv.msg_accrightslen = 0;
245 #endif
247 retry_recv:
248 iov_recv.iov_base = (void *)&rbuf[processed];
249 iov_recv.iov_len = len - processed;
251 result = recvmsg (s, &msg_recv, MSG_NOSIGNAL);
252 if (result == -1 && errno == EINTR) {
253 goto retry_recv;
255 if (result == -1 && errno == EAGAIN) {
256 goto retry_recv;
258 #if defined(OPENAIS_SOLARIS) || defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
259 /* On many OS poll never return POLLHUP or POLLERR.
260 * EOF is detected when recvmsg return 0.
262 if (result == 0) {
263 error = SA_AIS_ERR_LIBRARY;
264 goto error_exit;
266 #endif
267 if (result == -1 || result == 0) {
268 error = SA_AIS_ERR_LIBRARY;
269 goto error_exit;
271 processed += result;
272 if (processed != len) {
273 goto retry_recv;
275 assert (processed == len);
276 error_exit:
277 return (error);
280 SaAisErrorT
281 saSendRetry (
282 int s,
283 const void *msg,
284 size_t len)
286 SaAisErrorT error = SA_AIS_OK;
287 int result;
288 struct msghdr msg_send;
289 struct iovec iov_send;
290 char *rbuf = (char *)msg;
291 int processed = 0;
293 msg_send.msg_iov = &iov_send;
294 msg_send.msg_iovlen = 1;
295 msg_send.msg_name = 0;
296 msg_send.msg_namelen = 0;
297 #ifndef OPENAIS_SOLARIS
298 msg_send.msg_control = 0;
299 msg_send.msg_controllen = 0;
300 msg_send.msg_flags = 0;
301 #else
302 msg_send.msg_accrights = NULL;
303 msg_send.msg_accrightslen = 0;
304 #endif
306 retry_send:
307 iov_send.iov_base = (void *)&rbuf[processed];
308 iov_send.iov_len = len - processed;
310 result = sendmsg (s, &msg_send, MSG_NOSIGNAL);
313 * return immediately on any kind of syscall error that maps to
314 * SA_AIS_ERR if no part of message has been sent
316 if (result == -1 && processed == 0) {
317 if (errno == EINTR) {
318 error = SA_AIS_ERR_TRY_AGAIN;
319 goto error_exit;
321 if (errno == EAGAIN) {
322 error = SA_AIS_ERR_TRY_AGAIN;
323 goto error_exit;
325 if (errno == EFAULT) {
326 error = SA_AIS_ERR_INVALID_PARAM;
327 goto error_exit;
332 * retry read operations that are already started except
333 * for fault in that case, return ERR_LIBRARY
335 if (result == -1 && processed > 0) {
336 if (errno == EINTR) {
337 goto retry_send;
339 if (errno == EAGAIN) {
340 goto retry_send;
342 if (errno == EFAULT) {
343 error = SA_AIS_ERR_LIBRARY;
344 goto error_exit;
349 * return ERR_LIBRARY on any other syscall error
351 if (result == -1) {
352 error = SA_AIS_ERR_LIBRARY;
353 goto error_exit;
356 processed += result;
357 if (processed != len) {
358 goto retry_send;
361 error_exit:
362 return (error);
365 SaAisErrorT saSendMsgRetry (
366 int s,
367 struct iovec *iov,
368 int iov_len)
370 SaAisErrorT error = SA_AIS_OK;
371 int result;
372 int total_size = 0;
373 int i;
374 int csize;
375 int csize_cntr;
376 int total_sent = 0;
377 int iov_len_sendmsg = iov_len;
378 struct iovec *iov_sendmsg = iov;
379 struct iovec iovec_save;
380 int iovec_saved_position = -1;
382 struct msghdr msg_send;
384 for (i = 0; i < iov_len; i++) {
385 total_size += iov[i].iov_len;
387 msg_send.msg_iov = iov_sendmsg;
388 msg_send.msg_iovlen = iov_len_sendmsg;
389 msg_send.msg_name = 0;
390 msg_send.msg_namelen = 0;
391 #ifndef OPENAIS_SOLARIS
392 msg_send.msg_control = 0;
393 msg_send.msg_controllen = 0;
394 msg_send.msg_flags = 0;
395 #else
396 msg_send.msg_accrights = NULL;
397 msg_send.msg_accrightslen = 0;
398 #endif
400 retry_sendmsg:
401 result = sendmsg (s, &msg_send, MSG_NOSIGNAL);
403 * Can't send now, and message not committed, so don't retry send
405 if (result == -1 && iovec_saved_position == -1) {
406 if (errno == EINTR) {
407 error = SA_AIS_ERR_TRY_AGAIN;
408 goto error_exit;
410 if (errno == EAGAIN) {
411 error = SA_AIS_ERR_TRY_AGAIN;
412 goto error_exit;
414 if (errno == EFAULT) {
415 error = SA_AIS_ERR_INVALID_PARAM;
416 goto error_exit;
421 * Retry (and block) if portion of message has already been written
423 if (result == -1 && iovec_saved_position != -1) {
424 if (errno == EINTR) {
425 goto retry_sendmsg;
427 if (errno == EAGAIN) {
428 goto retry_sendmsg;
430 if (errno == EFAULT) {
431 error = SA_AIS_ERR_LIBRARY;
432 goto error_exit;
437 * ERR_LIBRARY for any other syscall error
439 if (result == -1) {
440 error = SA_AIS_ERR_LIBRARY;
441 goto error_exit;
444 if (iovec_saved_position != -1) {
445 memcpy (&iov[iovec_saved_position], &iovec_save, sizeof (struct iovec));
448 total_sent += result;
449 if (total_sent != total_size) {
450 for (i = 0, csize = 0, csize_cntr = 0; i < iov_len; i++) {
451 csize += iov[i].iov_len;
452 if (csize > total_sent) {
453 break;
456 csize_cntr += iov[i].iov_len;
458 memcpy (&iovec_save, &iov[i], sizeof (struct iovec));
459 iovec_saved_position = i;
460 iov[i].iov_base = ((char *)(iov[i].iov_base)) +
461 (total_sent - csize_cntr);
462 iov[i].iov_len = total_size - total_sent;
463 msg_send.msg_iov = &iov[i];
464 msg_send.msg_iovlen = iov_len - i;
466 goto retry_sendmsg;
469 error_exit:
470 return (error);
473 SaAisErrorT saSendMsgReceiveReply (
474 int s,
475 struct iovec *iov,
476 int iov_len,
477 void *responseMessage,
478 int responseLen)
480 SaAisErrorT error = SA_AIS_OK;
482 error = saSendMsgRetry (s, iov, iov_len);
483 if (error != SA_AIS_OK) {
484 goto error_exit;
487 error = saRecvRetry (s, responseMessage, responseLen);
488 if (error != SA_AIS_OK) {
489 goto error_exit;
492 error_exit:
493 return (error);
496 SaAisErrorT saSendReceiveReply (
497 int s,
498 void *requestMessage,
499 int requestLen,
500 void *responseMessage,
501 int responseLen)
503 SaAisErrorT error = SA_AIS_OK;
505 error = saSendRetry (s, requestMessage, requestLen);
506 if (error != SA_AIS_OK) {
507 goto error_exit;
510 error = saRecvRetry (s, responseMessage, responseLen);
511 if (error != SA_AIS_OK) {
512 goto error_exit;
515 error_exit:
516 return (error);
519 SaAisErrorT
520 saPollRetry (
521 struct pollfd *ufds,
522 unsigned int nfds,
523 int timeout)
525 SaAisErrorT error = SA_AIS_OK;
526 int result;
528 retry_poll:
529 result = poll (ufds, nfds, timeout);
530 if (result == -1 && errno == EINTR) {
531 goto retry_poll;
533 if (result == -1) {
534 error = SA_AIS_ERR_LIBRARY;
537 return (error);
541 SaAisErrorT
542 saHandleCreate (
543 struct saHandleDatabase *handleDatabase,
544 int instanceSize,
545 SaUint64T *handleOut)
547 uint32_t handle;
548 uint32_t check;
549 void *newHandles;
550 int found = 0;
551 void *instance;
552 int i;
554 pthread_mutex_lock (&handleDatabase->mutex);
556 for (handle = 0; handle < handleDatabase->handleCount; handle++) {
557 if (handleDatabase->handles[handle].state == SA_HANDLE_STATE_EMPTY) {
558 found = 1;
559 break;
563 if (found == 0) {
564 handleDatabase->handleCount += 1;
565 newHandles = (struct saHandle *)realloc (handleDatabase->handles,
566 sizeof (struct saHandle) * handleDatabase->handleCount);
567 if (newHandles == NULL) {
568 pthread_mutex_unlock (&handleDatabase->mutex);
569 return (SA_AIS_ERR_NO_MEMORY);
571 handleDatabase->handles = newHandles;
574 instance = malloc (instanceSize);
575 if (instance == 0) {
576 free (newHandles);
577 pthread_mutex_unlock (&handleDatabase->mutex);
578 return (SA_AIS_ERR_NO_MEMORY);
583 * This code makes sure the random number isn't zero
584 * We use 0 to specify an invalid handle out of the 1^64 address space
585 * If we get 0 200 times in a row, the RNG may be broken
587 for (i = 0; i < 200; i++) {
588 check = random();
589 if (check != 0) {
590 break;
594 memset (instance, 0, instanceSize);
596 handleDatabase->handles[handle].state = SA_HANDLE_STATE_ACTIVE;
598 handleDatabase->handles[handle].instance = instance;
600 handleDatabase->handles[handle].refCount = 1;
602 handleDatabase->handles[handle].check = check;
604 *handleOut = (SaUint64T)((uint64_t)check << 32 | handle);
606 pthread_mutex_unlock (&handleDatabase->mutex);
608 return (SA_AIS_OK);
612 SaAisErrorT
613 saHandleDestroy (
614 struct saHandleDatabase *handleDatabase,
615 SaUint64T inHandle)
617 SaAisErrorT error = SA_AIS_OK;
618 uint32_t check = inHandle >> 32;
619 uint32_t handle = inHandle & 0xffffffff;
621 pthread_mutex_lock (&handleDatabase->mutex);
623 if (check != handleDatabase->handles[handle].check) {
624 pthread_mutex_unlock (&handleDatabase->mutex);
625 error = SA_AIS_ERR_BAD_HANDLE;
626 return (error);
629 handleDatabase->handles[handle].state = SA_HANDLE_STATE_PENDINGREMOVAL;
631 pthread_mutex_unlock (&handleDatabase->mutex);
633 saHandleInstancePut (handleDatabase, inHandle);
635 return (error);
639 SaAisErrorT
640 saHandleInstanceGet (
641 struct saHandleDatabase *handleDatabase,
642 SaUint64T inHandle,
643 void **instance)
645 uint32_t check = inHandle >> 32;
646 uint32_t handle = inHandle & 0xffffffff;
648 SaAisErrorT error = SA_AIS_OK;
649 pthread_mutex_lock (&handleDatabase->mutex);
651 if (handle >= (SaUint64T)handleDatabase->handleCount) {
652 error = SA_AIS_ERR_BAD_HANDLE;
653 goto error_exit;
655 if (handleDatabase->handles[handle].state != SA_HANDLE_STATE_ACTIVE) {
656 error = SA_AIS_ERR_BAD_HANDLE;
657 goto error_exit;
659 if (check != handleDatabase->handles[handle].check) {
660 error = SA_AIS_ERR_BAD_HANDLE;
661 goto error_exit;
665 *instance = handleDatabase->handles[handle].instance;
667 handleDatabase->handles[handle].refCount += 1;
669 error_exit:
670 pthread_mutex_unlock (&handleDatabase->mutex);
672 return (error);
676 SaAisErrorT
677 saHandleInstancePut (
678 struct saHandleDatabase *handleDatabase,
679 SaUint64T inHandle)
681 void *instance;
682 SaAisErrorT error = SA_AIS_OK;
683 uint32_t check = inHandle >> 32;
684 uint32_t handle = inHandle & 0xffffffff;
686 pthread_mutex_lock (&handleDatabase->mutex);
688 if (check != handleDatabase->handles[handle].check) {
689 error = SA_AIS_ERR_BAD_HANDLE;
690 goto error_exit;
693 handleDatabase->handles[handle].refCount -= 1;
694 assert (handleDatabase->handles[handle].refCount >= 0);
696 if (handleDatabase->handles[handle].refCount == 0) {
697 instance = (handleDatabase->handles[handle].instance);
698 handleDatabase->handleInstanceDestructor (instance);
699 free (instance);
700 memset (&handleDatabase->handles[handle], 0, sizeof (struct saHandle));
703 error_exit:
704 pthread_mutex_unlock (&handleDatabase->mutex);
706 return (error);
710 SaAisErrorT
711 saVersionVerify (
712 struct saVersionDatabase *versionDatabase,
713 SaVersionT *version)
715 int i;
716 SaAisErrorT error = SA_AIS_ERR_VERSION;
718 if (version == 0) {
719 return (SA_AIS_ERR_INVALID_PARAM);
723 * Look for a release code that we support. If we find it then
724 * make sure that the supported major version is >= to the required one.
725 * In any case we return what we support in the version structure.
727 for (i = 0; i < versionDatabase->versionCount; i++) {
730 * Check if the caller requires and old release code that we don't support.
732 if (version->releaseCode < versionDatabase->versionsSupported[i].releaseCode) {
733 break;
737 * Check if we can support this release code.
739 if (version->releaseCode == versionDatabase->versionsSupported[i].releaseCode) {
742 * Check if we can support the major version requested.
744 if (versionDatabase->versionsSupported[i].majorVersion >= version->majorVersion) {
745 error = SA_AIS_OK;
746 break;
750 * We support the release code, but not the major version.
752 break;
757 * If we fall out of the if loop, the caller requires a release code
758 * beyond what we support.
760 if (i == versionDatabase->versionCount) {
761 i = versionDatabase->versionCount - 1;
765 * Tell the caller what we support
767 memcpy(version, &versionDatabase->versionsSupported[i], sizeof(*version));
768 return (error);
772 * Get the time of day and convert to nanoseconds
774 SaTimeT clustTimeNow(void)
776 struct timeval tv;
777 SaTimeT time_now;
779 if (gettimeofday(&tv, 0)) {
780 return 0ULL;
783 time_now = (SaTimeT)(tv.tv_sec) * 1000000000ULL;
784 time_now += (SaTimeT)(tv.tv_usec) * 1000ULL;
786 return time_now;