/* Unix SMB/CIFS implementation. Launchd integration wrapper API Copyright (C) 2007 James Peach This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #include "smb_launchd.h" /* launchd source code and documentation is available here: * http://launchd.macosforge.org/ */ #if defined(WITH_LAUNCHD_SUPPORT) #include <launch.h> #include <stdarg.h> typedef void (*launchd_iterator)(launch_data_t, const char*, void*); #define LAUNCHD_TRACE_LEVEL 10 void smb_launchd_checkout(struct smb_launch_info *linfo) { talloc_free(linfo->socket_list); } static void pull_launch_sockets(launch_data_t key, const char *name, struct smb_launch_info *linfo) { launch_data_type_t type; type = launch_data_get_type(key); DEBUG(LAUNCHD_TRACE_LEVEL, ("Searching item name='%s' type=%d for sockets\n", name ? name : "", (int)type)); switch (type) { case LAUNCH_DATA_FD: if (!linfo->socket_list) { /* We are counting the number of sockets. */ linfo->num_sockets++; } else { /* We are collecting the socket fds. */ int fd = launch_data_get_fd(key); linfo->socket_list[linfo->num_sockets] = fd; linfo->num_sockets++; DEBUG(LAUNCHD_TRACE_LEVEL, ("Added fd=%d to launchd set\n", fd)); } return; case LAUNCH_DATA_ARRAY: { int i; launch_data_t item; for (i = 0; i < launch_data_array_get_count(key); ++i) { item = launch_data_array_get_index(key, i); pull_launch_sockets(item, name, linfo); } return; } case LAUNCH_DATA_DICTIONARY: launch_data_dict_iterate(key, (launchd_iterator)pull_launch_sockets, linfo); return; default: return; } } BOOL smb_launchd_checkin_names(struct smb_launch_info *linfo, ...) { launch_data_t msg; launch_data_t resp; launch_data_t item; BOOL is_launchd = False; ZERO_STRUCTP(linfo); msg = launch_data_new_string(LAUNCH_KEY_CHECKIN); resp = launch_msg(msg); if (resp == NULL) { /* IPC to launchd failed. */ launch_data_free(msg); return is_launchd; } if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { errno = launch_data_get_errno(resp); goto done; } /* At this point, we know we are running under launchd. */ linfo->idle_timeout_secs = 600; is_launchd = True; if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) { linfo->idle_timeout_secs = launch_data_get_integer(item); } if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) { int count = 0; const char * sockname = NULL; launch_data_t sockdata; va_list args; /* Figure out the maximum number of sockets. */ va_start(args, linfo); while ((sockname = va_arg(args, const char *))) { ++count; } va_end(args); DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n", linfo->num_sockets)); if (launch_data_dict_get_count(item) < count) { DEBUG(0, ("%d launchd sockets requested, " "but only %d are available\n", count, launch_data_dict_get_count(item))); } linfo->socket_list = TALLOC_ARRAY(NULL, int, count); if (linfo->socket_list == NULL) { goto done; } linfo->num_sockets = 0; va_start(args, linfo); while ((sockname = va_arg(args, const char *))) { sockdata = launch_data_dict_lookup(item, sockname); pull_launch_sockets(sockdata, sockname, linfo); DEBUG(LAUNCHD_TRACE_LEVEL, ("Added launchd socket \"%s\"\n", sockname)); } SMB_ASSERT(count >= linfo->num_sockets); } done: launch_data_free(msg); launch_data_free(resp); return is_launchd; } BOOL smb_launchd_checkin(struct smb_launch_info *linfo) { launch_data_t msg; launch_data_t resp; launch_data_t item; BOOL is_launchd = False; ZERO_STRUCTP(linfo); msg = launch_data_new_string(LAUNCH_KEY_CHECKIN); resp = launch_msg(msg); if (resp == NULL) { /* IPC to launchd failed. */ launch_data_free(msg); return is_launchd; } if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { errno = launch_data_get_errno(resp); goto done; } /* At this point, we know we are running under launchd. */ linfo->idle_timeout_secs = 600; is_launchd = True; if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) { linfo->idle_timeout_secs = launch_data_get_integer(item); } if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) { int count; pull_launch_sockets(item, NULL, linfo); DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n", linfo->num_sockets)); count = linfo->num_sockets; linfo->socket_list = TALLOC_ARRAY(NULL, int, count); if (linfo->socket_list == NULL) { goto done; } linfo->num_sockets = 0; pull_launch_sockets(item, NULL, linfo); DEBUG(LAUNCHD_TRACE_LEVEL, ("Added %d launchd sockets\n", linfo->num_sockets)); SMB_ASSERT(count == linfo->num_sockets); } done: launch_data_free(msg); launch_data_free(resp); return is_launchd; } #else /* defined(WITH_LAUNCHD_SUPPORT) */ BOOL smb_launchd_checkin(struct smb_launch_info * UNUSED(linfo)) { ZERO_STRUCTP(linfo); return False; } BOOL smb_launchd_checkin_names(struct smb_launch_info * UNUSED(linfo), ...) { ZERO_STRUCTP(linfo); return False; } void smb_launchd_checkout(struct smb_launch_info * UNUSED(linfo)) { } #endif /* defined(WITH_LAUNCHD_SUPPORT) */