97480f98287f947847e0e7e4cea597aa9976a0fd
[samba.git] / source / 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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "smb_launchd.h"
23
24 /* launchd source code and documentation is available here:
25  *      http://launchd.macosforge.org/
26  */
27
28 #if defined(WITH_LAUNCHD_SUPPORT)
29
30 #include <launch.h>
31 #include <stdarg.h>
32
33 typedef void (*launchd_iterator)(launch_data_t, const char*, void*);
34
35 #define LAUNCHD_TRACE_LEVEL 10
36
37  void smb_launchd_checkout(struct smb_launch_info *linfo)
38 {
39         talloc_free(linfo->socket_list);
40 }
41
42 static void pull_launch_sockets(launch_data_t key,
43                                 const char *name,
44                                 struct smb_launch_info *linfo)
45 {
46         launch_data_type_t type;
47
48         type = launch_data_get_type(key);
49         DEBUG(LAUNCHD_TRACE_LEVEL,
50                 ("Searching item name='%s' type=%d for sockets\n",
51                  name ? name : "", (int)type));
52
53         switch (type) {
54         case LAUNCH_DATA_FD:
55                 if (!linfo->socket_list) {
56                         /* We are counting the number of sockets. */
57                         linfo->num_sockets++;
58                 } else {
59                         /* We are collecting the socket fds. */
60                         int fd = launch_data_get_fd(key);
61
62                         linfo->socket_list[linfo->num_sockets] = fd;
63                         linfo->num_sockets++;
64                         DEBUG(LAUNCHD_TRACE_LEVEL,
65                                 ("Added fd=%d to launchd set\n", fd));
66                 }
67                 return;
68         case LAUNCH_DATA_ARRAY:
69         {
70                 int i;
71                 launch_data_t item;
72
73                 for (i = 0; i < launch_data_array_get_count(key); ++i) {
74                         item = launch_data_array_get_index(key, i);
75                         pull_launch_sockets(item, name, linfo);
76                 }
77                 return;
78         }
79         case LAUNCH_DATA_DICTIONARY:
80                 launch_data_dict_iterate(key,
81                         (launchd_iterator)pull_launch_sockets, linfo);
82                 return;
83         default:
84                 return;
85         }
86 }
87
88  BOOL smb_launchd_checkin_names(struct smb_launch_info *linfo, ...)
89 {
90         launch_data_t msg;
91         launch_data_t resp;
92         launch_data_t item;
93         BOOL is_launchd = False;
94
95         ZERO_STRUCTP(linfo);
96
97         msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
98         resp = launch_msg(msg);
99         if (resp == NULL) {
100                 /* IPC to launchd failed. */
101                 launch_data_free(msg);
102                 return is_launchd;
103         }
104
105         if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
106                 errno = launch_data_get_errno(resp);
107                 goto done;
108         }
109
110         /* At this point, we know we are running under launchd. */
111         linfo->idle_timeout_secs = 600;
112         is_launchd = True;
113
114         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
115                 linfo->idle_timeout_secs = launch_data_get_integer(item);
116         }
117
118         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
119                 int count = 0;
120                 const char * sockname = NULL;
121                 launch_data_t sockdata;
122                 va_list args;
123
124                 /* Figure out the maximum number of sockets. */
125                 va_start(args, linfo);
126                 while ((sockname = va_arg(args, const char *))) {
127                     ++count;
128                 }
129                 va_end(args);
130
131                 DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
132                                         linfo->num_sockets));
133
134                 if (launch_data_dict_get_count(item) < count) {
135                         DEBUG(0, ("%d launchd sockets requested, "
136                             "but only %d are available\n",
137                             count, launch_data_dict_get_count(item)));
138                 }
139
140                 linfo->socket_list = TALLOC_ARRAY(NULL, int, count);
141                 if (linfo->socket_list == NULL) {
142                         goto done;
143                 }
144
145                 linfo->num_sockets = 0;
146                 va_start(args, linfo);
147                 while ((sockname = va_arg(args, const char *))) {
148                     sockdata = launch_data_dict_lookup(item, sockname);
149
150                     pull_launch_sockets(sockdata, sockname, linfo);
151                     DEBUG(LAUNCHD_TRACE_LEVEL,
152                             ("Added launchd socket \"%s\"\n", sockname));
153                 }
154
155                 SMB_ASSERT(count >= linfo->num_sockets);
156         }
157
158 done:
159         launch_data_free(msg);
160         launch_data_free(resp);
161         return is_launchd;
162 }
163
164  BOOL smb_launchd_checkin(struct smb_launch_info *linfo)
165 {
166         launch_data_t msg;
167         launch_data_t resp;
168         launch_data_t item;
169         BOOL is_launchd = False;
170
171         ZERO_STRUCTP(linfo);
172
173         msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
174         resp = launch_msg(msg);
175         if (resp == NULL) {
176                 /* IPC to launchd failed. */
177                 launch_data_free(msg);
178                 return is_launchd;
179         }
180
181         if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
182                 errno = launch_data_get_errno(resp);
183                 goto done;
184         }
185
186         /* At this point, we know we are running under launchd. */
187         linfo->idle_timeout_secs = 600;
188         is_launchd = True;
189
190         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
191                 linfo->idle_timeout_secs = launch_data_get_integer(item);
192         }
193
194         if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
195                 int count;
196
197                 pull_launch_sockets(item, NULL, linfo);
198                 DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
199                                         linfo->num_sockets));
200
201                 count = linfo->num_sockets;
202                 linfo->socket_list = TALLOC_ARRAY(NULL, int, count);
203                 if (linfo->socket_list == NULL) {
204                         goto done;
205                 }
206
207                 linfo->num_sockets = 0;
208                 pull_launch_sockets(item, NULL, linfo);
209
210                 DEBUG(LAUNCHD_TRACE_LEVEL, ("Added %d launchd sockets\n",
211                                         linfo->num_sockets));
212
213                 SMB_ASSERT(count == linfo->num_sockets);
214         }
215
216 done:
217         launch_data_free(msg);
218         launch_data_free(resp);
219         return is_launchd;
220 }
221
222 #else /* defined(WITH_LAUNCHD_SUPPORT) */
223
224  BOOL smb_launchd_checkin(struct smb_launch_info * UNUSED(linfo))
225 {
226         ZERO_STRUCTP(linfo);
227         return False;
228 }
229
230  BOOL smb_launchd_checkin_names(struct smb_launch_info * UNUSED(linfo), ...)
231 {
232         ZERO_STRUCTP(linfo);
233         return False;
234 }
235
236  void smb_launchd_checkout(struct smb_launch_info * UNUSED(linfo))
237 {
238 }
239
240 #endif /* defined(WITH_LAUNCHD_SUPPORT) */
241