2c3f7cac89fdeb0cd8380ca41c64575ea742d912
[jra/samba/.git] / source3 / lib / launchd.c
1 /*
2    Unix SMB/CIFS implementation.
3    Launchd integration wrapper API
4
5    Copyright (C) 2007 James Peach
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "smb_launchd.h"
24
25 /* launchd source code and documentation is available here:
26  *      http://launchd.macosforge.org/
27  */
28
29 #if defined(WITH_LAUNCHD_SUPPORT)
30
31 #include <launch.h>
32 #include <stdarg.h>
33
34 typedef void (*launchd_iterator)(launch_data_t, const char*, void*);
35
36 #define LAUNCHD_TRACE_LEVEL 10
37
38  void smb_launchd_checkout(struct smb_launch_info *linfo)
39 {
40         talloc_free(linfo->socket_list);
41 }
42
43 static void pull_launch_sockets(launch_data_t key,
44                                 const char *name,
45                                 struct smb_launch_info *linfo)
46 {
47         launch_data_type_t type;
48
49         type = launch_data_get_type(key);
50         DEBUG(LAUNCHD_TRACE_LEVEL,
51                 ("Searching item name='%s' type=%d for sockets\n",
52                  name ? name : "", (int)type));
53
54         switch (type) {
55         case LAUNCH_DATA_FD:
56                 if (!linfo->socket_list) {
57                         /* We are counting the number of sockets. */
58                         linfo->num_sockets++;
59                 } else {
60                         /* We are collecting the socket fds. */
61                         int fd = launch_data_get_fd(key);
62
63                         linfo->socket_list[linfo->num_sockets] = fd;
64                         linfo->num_sockets++;
65                         DEBUG(LAUNCHD_TRACE_LEVEL,
66                                 ("Added fd=%d to launchd set\n", fd));
67                 }
68                 return;
69         case LAUNCH_DATA_ARRAY:
70         {
71                 int i;
72                 launch_data_t item;
73
74                 for (i = 0; i < launch_data_array_get_count(key); ++i) {
75                         item = launch_data_array_get_index(key, i);
76                         pull_launch_sockets(item, name, linfo);
77                 }
78                 return;
79         }
80         case LAUNCH_DATA_DICTIONARY:
81                 launch_data_dict_iterate(key,
82                         (launchd_iterator)pull_launch_sockets, linfo);
83                 return;
84         default:
85                 return;
86         }
87 }
88
89  BOOL smb_launchd_checkin_names(struct smb_launch_info *linfo, ...)
90 {
91         launch_data_t msg;
92         launch_data_t resp;
93         launch_data_t item;
94         BOOL is_launchd = False;
95
96         ZERO_STRUCTP(linfo);
97
98         msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
99         resp = launch_msg(msg);
100         if (resp == NULL) {
101                 /* IPC to launchd failed. */
102                 launch_data_free(msg);
103                 return is_launchd;
104         }
105
106         if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
107                 errno = launch_data_get_errno(resp);
108                 goto done;
109         }
110
111         /* At this point, we know we are running under launchd. */
112         linfo->idle_timeout_secs = 600;
113         is_launchd = True;
114
115         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
116                 linfo->idle_timeout_secs = launch_data_get_integer(item);
117         }
118
119         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
120                 int count = 0;
121                 const char * sockname = NULL;
122                 launch_data_t sockdata;
123                 va_list args;
124
125                 /* Figure out the maximum number of sockets. */
126                 va_start(args, linfo);
127                 while ((sockname = va_arg(args, const char *))) {
128                     ++count;
129                 }
130                 va_end(args);
131
132                 DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
133                                         linfo->num_sockets));
134
135                 if (launch_data_dict_get_count(item) < count) {
136                         DEBUG(0, ("%d launchd sockets requested, "
137                             "but only %d are available\n",
138                             count, launch_data_dict_get_count(item)));
139                 }
140
141                 linfo->socket_list = TALLOC_ARRAY(NULL, int, count);
142                 if (linfo->socket_list == NULL) {
143                         goto done;
144                 }
145
146                 linfo->num_sockets = 0;
147                 va_start(args, linfo);
148                 while ((sockname = va_arg(args, const char *))) {
149                     sockdata = launch_data_dict_lookup(item, sockname);
150
151                     pull_launch_sockets(sockdata, sockname, linfo);
152                     DEBUG(LAUNCHD_TRACE_LEVEL,
153                             ("Added launchd socket \"%s\"\n", sockname));
154                 }
155
156                 SMB_ASSERT(count >= linfo->num_sockets);
157         }
158
159 done:
160         launch_data_free(msg);
161         launch_data_free(resp);
162         return is_launchd;
163 }
164
165  BOOL smb_launchd_checkin(struct smb_launch_info *linfo)
166 {
167         launch_data_t msg;
168         launch_data_t resp;
169         launch_data_t item;
170         BOOL is_launchd = False;
171
172         ZERO_STRUCTP(linfo);
173
174         msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
175         resp = launch_msg(msg);
176         if (resp == NULL) {
177                 /* IPC to launchd failed. */
178                 launch_data_free(msg);
179                 return is_launchd;
180         }
181
182         if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
183                 errno = launch_data_get_errno(resp);
184                 goto done;
185         }
186
187         /* At this point, we know we are running under launchd. */
188         linfo->idle_timeout_secs = 600;
189         is_launchd = True;
190
191         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
192                 linfo->idle_timeout_secs = launch_data_get_integer(item);
193         }
194
195         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
196                 int count;
197
198                 pull_launch_sockets(item, NULL, linfo);
199                 DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
200                                         linfo->num_sockets));
201
202                 count = linfo->num_sockets;
203                 linfo->socket_list = TALLOC_ARRAY(NULL, int, count);
204                 if (linfo->socket_list == NULL) {
205                         goto done;
206                 }
207
208                 linfo->num_sockets = 0;
209                 pull_launch_sockets(item, NULL, linfo);
210
211                 DEBUG(LAUNCHD_TRACE_LEVEL, ("Added %d launchd sockets\n",
212                                         linfo->num_sockets));
213
214                 SMB_ASSERT(count == linfo->num_sockets);
215         }
216
217 done:
218         launch_data_free(msg);
219         launch_data_free(resp);
220         return is_launchd;
221 }
222
223 #else /* defined(WITH_LAUNCHD_SUPPORT) */
224
225  BOOL smb_launchd_checkin(struct smb_launch_info * UNUSED(linfo))
226 {
227         ZERO_STRUCTP(linfo);
228         return False;
229 }
230
231  BOOL smb_launchd_checkin_names(struct smb_launch_info * UNUSED(linfo), ...)
232 {
233         ZERO_STRUCTP(linfo);
234         return False;
235 }
236
237  void smb_launchd_checkout(struct smb_launch_info * UNUSED(linfo))
238 {
239 }
240
241 #endif /* defined(WITH_LAUNCHD_SUPPORT) */
242