]>
Commit | Line | Data |
---|---|---|
ed34e3c3 A |
1 | /* |
2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_APACHE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | * you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, software | |
13 | * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | * See the License for the specific language governing permissions and | |
16 | * limitations under the License. | |
17 | * | |
18 | * @APPLE_APACHE_LICENSE_HEADER_END@ | |
19 | */ | |
20 | ||
ddbbfbc1 | 21 | static const char *const __rcs_file_version__ = "$Revision: 23921 $"; |
5b0a4722 A |
22 | |
23 | #include "config.h" | |
24 | #include "launchd_unix_ipc.h" | |
ed34e3c3 | 25 | |
ddbbfbc1 | 26 | #include <sys/socket.h> |
ed34e3c3 A |
27 | #include <sys/types.h> |
28 | #include <sys/queue.h> | |
29 | #include <sys/event.h> | |
30 | #include <sys/stat.h> | |
31 | #include <sys/ucred.h> | |
32 | #include <sys/fcntl.h> | |
33 | #include <sys/un.h> | |
34 | #include <sys/wait.h> | |
35 | #include <sys/sysctl.h> | |
36 | #include <sys/sockio.h> | |
37 | #include <sys/time.h> | |
38 | #include <sys/resource.h> | |
39 | #include <sys/ioctl.h> | |
40 | #include <unistd.h> | |
41 | #include <signal.h> | |
42 | #include <errno.h> | |
ed34e3c3 A |
43 | #include <libgen.h> |
44 | #include <stdio.h> | |
45 | #include <stdlib.h> | |
46 | #include <stdarg.h> | |
47 | #include <stdbool.h> | |
48 | #include <paths.h> | |
49 | #include <string.h> | |
50 | ||
ef398931 A |
51 | #include "launch.h" |
52 | #include "launch_priv.h" | |
ed34e3c3 | 53 | #include "launchd.h" |
5b0a4722 | 54 | #include "launchd_runtime.h" |
ed34e3c3 | 55 | #include "launchd_core_logic.h" |
ed34e3c3 A |
56 | |
57 | extern char **environ; | |
58 | ||
5b0a4722 | 59 | static LIST_HEAD(, conncb) connections; |
ed34e3c3 A |
60 | |
61 | static launch_data_t adjust_rlimits(launch_data_t in); | |
62 | ||
63 | static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context); | |
ddbbfbc1 | 64 | static void ipc_readmsg(launch_data_t msg, void *context); |
ed34e3c3 A |
65 | |
66 | static void ipc_listen_callback(void *obj __attribute__((unused)), struct kevent *kev); | |
67 | ||
68 | static kq_callback kqipc_listen_callback = ipc_listen_callback; | |
69 | ||
70 | static pid_t ipc_self = 0; | |
71 | ||
72 | char *sockpath = NULL; | |
73 | static char *sockdir = NULL; | |
74 | ||
75 | static bool ipc_inited = false; | |
76 | ||
ddbbfbc1 | 77 | static void |
ed34e3c3 A |
78 | ipc_clean_up(void) |
79 | { | |
5b0a4722 | 80 | if (ipc_self != getpid()) { |
ed34e3c3 | 81 | return; |
5b0a4722 | 82 | } |
ed34e3c3 | 83 | |
5b0a4722 | 84 | if (-1 == unlink(sockpath)) { |
ddbbfbc1 | 85 | runtime_syslog(LOG_WARNING, "unlink(\"%s\"): %s", sockpath, strerror(errno)); |
5b0a4722 | 86 | } else if (-1 == rmdir(sockdir)) { |
ddbbfbc1 | 87 | runtime_syslog(LOG_WARNING, "rmdir(\"%s\"): %s", sockdir, strerror(errno)); |
5b0a4722 | 88 | } |
ed34e3c3 A |
89 | } |
90 | ||
91 | void | |
5b0a4722 | 92 | ipc_server_init(void) |
ed34e3c3 A |
93 | { |
94 | struct sockaddr_un sun; | |
95 | mode_t oldmask; | |
96 | int r, fd = -1; | |
97 | char ourdir[1024]; | |
ed34e3c3 | 98 | |
5b0a4722 | 99 | if (ipc_inited) { |
ed34e3c3 | 100 | return; |
5b0a4722 | 101 | } |
ed34e3c3 A |
102 | |
103 | memset(&sun, 0, sizeof(sun)); | |
104 | sun.sun_family = AF_UNIX; | |
105 | ||
ddbbfbc1 | 106 | if (pid1_magic) { |
ed34e3c3 A |
107 | strcpy(ourdir, LAUNCHD_SOCK_PREFIX); |
108 | strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path)); | |
109 | ||
110 | unlink(ourdir); | |
111 | if (mkdir(ourdir, S_IRWXU) == -1) { | |
112 | if (errno == EROFS) { | |
113 | goto out_bad; | |
114 | } else if (errno == EEXIST) { | |
115 | struct stat sb; | |
116 | stat(ourdir, &sb); | |
117 | if (!S_ISDIR(sb.st_mode)) { | |
118 | errno = EEXIST; | |
ddbbfbc1 | 119 | runtime_syslog(LOG_ERR, "mkdir(\"%s\"): %s", LAUNCHD_SOCK_PREFIX, strerror(errno)); |
ed34e3c3 A |
120 | goto out_bad; |
121 | } | |
122 | } else { | |
ddbbfbc1 | 123 | runtime_syslog(LOG_ERR, "mkdir(\"%s\"): %s", ourdir, strerror(errno)); |
ed34e3c3 A |
124 | goto out_bad; |
125 | } | |
126 | } | |
127 | } else { | |
ddbbfbc1 A |
128 | snprintf(ourdir, sizeof(ourdir), _PATH_TMP "launchd-%u.XXXXXX", getpid()); |
129 | if (mkdtemp(ourdir) == NULL) { | |
130 | runtime_syslog(LOG_ERR, "Could not create critical directory \"%s\": %s", ourdir, strerror(errno)); | |
ed34e3c3 | 131 | goto out_bad; |
5b0a4722 | 132 | } |
ed34e3c3 | 133 | snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/sock", ourdir); |
ed34e3c3 A |
134 | } |
135 | ||
136 | if (unlink(sun.sun_path) == -1 && errno != ENOENT) { | |
5b0a4722 | 137 | if (errno != EROFS) { |
ddbbfbc1 | 138 | runtime_syslog(LOG_ERR, "unlink(\"thesocket\"): %s", strerror(errno)); |
5b0a4722 | 139 | } |
ed34e3c3 A |
140 | goto out_bad; |
141 | } | |
142 | ||
5b0a4722 | 143 | if (!launchd_assumes((fd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) != -1)) { |
ed34e3c3 | 144 | goto out_bad; |
5b0a4722 | 145 | } |
ed34e3c3 A |
146 | |
147 | oldmask = umask(S_IRWXG|S_IRWXO); | |
148 | r = bind(fd, (struct sockaddr *)&sun, sizeof(sun)); | |
149 | umask(oldmask); | |
150 | ||
151 | if (r == -1) { | |
5b0a4722 | 152 | if (errno != EROFS) { |
ddbbfbc1 | 153 | runtime_syslog(LOG_ERR, "bind(\"thesocket\"): %s", strerror(errno)); |
5b0a4722 | 154 | } |
ed34e3c3 A |
155 | goto out_bad; |
156 | } | |
157 | ||
158 | if (listen(fd, SOMAXCONN) == -1) { | |
ddbbfbc1 | 159 | runtime_syslog(LOG_ERR, "listen(\"thesocket\"): %s", strerror(errno)); |
ed34e3c3 A |
160 | goto out_bad; |
161 | } | |
162 | ||
5b0a4722 | 163 | if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqipc_listen_callback) == -1) { |
ddbbfbc1 | 164 | runtime_syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %s", strerror(errno)); |
ed34e3c3 A |
165 | goto out_bad; |
166 | } | |
167 | ||
168 | ipc_inited = true; | |
169 | ||
5b0a4722 A |
170 | sockdir = strdup(ourdir); |
171 | sockpath = strdup(sun.sun_path); | |
172 | ipc_self = getpid(); | |
173 | atexit(ipc_clean_up); | |
ed34e3c3 A |
174 | |
175 | out_bad: | |
5b0a4722 A |
176 | if (!ipc_inited && fd != -1) { |
177 | launchd_assumes(runtime_close(fd) == 0); | |
178 | } | |
ed34e3c3 A |
179 | } |
180 | ||
181 | void | |
5b0a4722 | 182 | ipc_open(int fd, job_t j) |
ed34e3c3 A |
183 | { |
184 | struct conncb *c = calloc(1, sizeof(struct conncb)); | |
185 | ||
186 | fcntl(fd, F_SETFL, O_NONBLOCK); | |
187 | ||
188 | c->kqconn_callback = ipc_callback; | |
ddbbfbc1 A |
189 | if( j ) { |
190 | c->conn = launchd_fdopen(-1, fd); | |
191 | } else { | |
192 | c->conn = launchd_fdopen(fd, -1); | |
193 | } | |
194 | ||
ed34e3c3 | 195 | c->j = j; |
5b0a4722 | 196 | LIST_INSERT_HEAD(&connections, c, sle); |
ed34e3c3 A |
197 | kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &c->kqconn_callback); |
198 | } | |
199 | ||
200 | void | |
201 | ipc_listen_callback(void *obj __attribute__((unused)), struct kevent *kev) | |
202 | { | |
203 | struct sockaddr_un sun; | |
204 | socklen_t sl = sizeof(sun); | |
205 | int cfd; | |
206 | ||
207 | if ((cfd = _fd(accept(kev->ident, (struct sockaddr *)&sun, &sl))) == -1) { | |
208 | return; | |
209 | } | |
210 | ||
211 | ipc_open(cfd, NULL); | |
212 | } | |
213 | ||
214 | void | |
215 | ipc_callback(void *obj, struct kevent *kev) | |
216 | { | |
217 | struct conncb *c = obj; | |
218 | int r; | |
219 | ||
220 | if (kev->filter == EVFILT_READ) { | |
221 | if (launchd_msg_recv(c->conn, ipc_readmsg, c) == -1 && errno != EAGAIN) { | |
5b0a4722 | 222 | if (errno != ECONNRESET) { |
ddbbfbc1 | 223 | runtime_syslog(LOG_DEBUG, "%s(): recv: %s", __func__, strerror(errno)); |
5b0a4722 | 224 | } |
ed34e3c3 A |
225 | ipc_close(c); |
226 | } | |
227 | } else if (kev->filter == EVFILT_WRITE) { | |
228 | r = launchd_msg_send(c->conn, NULL); | |
229 | if (r == -1) { | |
230 | if (errno != EAGAIN) { | |
ddbbfbc1 | 231 | runtime_syslog(LOG_DEBUG, "%s(): send: %s", __func__, strerror(errno)); |
ed34e3c3 A |
232 | ipc_close(c); |
233 | } | |
234 | } else if (r == 0) { | |
235 | kevent_mod(launchd_getfd(c->conn), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); | |
236 | } | |
237 | } else { | |
5b0a4722 | 238 | runtime_syslog(LOG_DEBUG, "%s(): unknown filter type!", __func__); |
ed34e3c3 A |
239 | ipc_close(c); |
240 | } | |
241 | } | |
242 | ||
ddbbfbc1 A |
243 | static void |
244 | set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) | |
ed34e3c3 | 245 | { |
ddbbfbc1 A |
246 | const char *v = launch_data_get_string(obj); |
247 | if( v ) { | |
248 | setenv(key, v, 1); | |
249 | } else { | |
250 | runtime_syslog(LOG_WARNING, "Attempt to set NULL environment variable: %s (type = %d)", key, launch_data_get_type(obj)); | |
251 | } | |
ed34e3c3 A |
252 | } |
253 | ||
5b0a4722 A |
254 | void |
255 | ipc_close_all_with_job(job_t j) | |
256 | { | |
257 | struct conncb *ci, *cin; | |
258 | ||
259 | LIST_FOREACH_SAFE(ci, &connections, sle, cin) { | |
260 | if (ci->j == j) { | |
261 | ipc_close(ci); | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
ed34e3c3 A |
266 | void |
267 | ipc_close_fds(launch_data_t o) | |
268 | { | |
269 | size_t i; | |
270 | ||
271 | switch (launch_data_get_type(o)) { | |
272 | case LAUNCH_DATA_DICTIONARY: | |
273 | launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))ipc_close_fds, NULL); | |
274 | break; | |
275 | case LAUNCH_DATA_ARRAY: | |
276 | for (i = 0; i < launch_data_array_get_count(o); i++) | |
277 | ipc_close_fds(launch_data_array_get_index(o, i)); | |
278 | break; | |
279 | case LAUNCH_DATA_FD: | |
5b0a4722 A |
280 | if (launch_data_get_fd(o) != -1) { |
281 | launchd_assumes(runtime_close(launch_data_get_fd(o)) == 0); | |
282 | } | |
ed34e3c3 A |
283 | break; |
284 | default: | |
285 | break; | |
286 | } | |
287 | } | |
288 | ||
289 | void | |
290 | ipc_revoke_fds(launch_data_t o) | |
291 | { | |
292 | size_t i; | |
293 | ||
294 | switch (launch_data_get_type(o)) { | |
295 | case LAUNCH_DATA_DICTIONARY: | |
296 | launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))ipc_revoke_fds, NULL); | |
297 | break; | |
298 | case LAUNCH_DATA_ARRAY: | |
299 | for (i = 0; i < launch_data_array_get_count(o); i++) | |
300 | ipc_revoke_fds(launch_data_array_get_index(o, i)); | |
301 | break; | |
302 | case LAUNCH_DATA_FD: | |
303 | launch_data_set_fd(o, -1); | |
304 | break; | |
305 | default: | |
306 | break; | |
307 | } | |
308 | } | |
309 | ||
310 | struct readmsg_context { | |
311 | struct conncb *c; | |
312 | launch_data_t resp; | |
313 | }; | |
314 | ||
315 | void | |
316 | ipc_readmsg(launch_data_t msg, void *context) | |
317 | { | |
318 | struct readmsg_context rmc = { context, NULL }; | |
319 | ||
320 | if (LAUNCH_DATA_DICTIONARY == launch_data_get_type(msg)) { | |
321 | launch_data_dict_iterate(msg, ipc_readmsg2, &rmc); | |
322 | } else if (LAUNCH_DATA_STRING == launch_data_get_type(msg)) { | |
323 | ipc_readmsg2(NULL, launch_data_get_string(msg), &rmc); | |
324 | } else { | |
325 | rmc.resp = launch_data_new_errno(EINVAL); | |
326 | } | |
327 | ||
5b0a4722 | 328 | if (NULL == rmc.resp) { |
ed34e3c3 | 329 | rmc.resp = launch_data_new_errno(ENOSYS); |
5b0a4722 | 330 | } |
ed34e3c3 A |
331 | |
332 | ipc_close_fds(msg); | |
333 | ||
334 | if (launchd_msg_send(rmc.c->conn, rmc.resp) == -1) { | |
335 | if (errno == EAGAIN) { | |
336 | kevent_mod(launchd_getfd(rmc.c->conn), EVFILT_WRITE, EV_ADD, 0, 0, &rmc.c->kqconn_callback); | |
337 | } else { | |
ddbbfbc1 | 338 | runtime_syslog(LOG_DEBUG, "launchd_msg_send() == -1: %s", strerror(errno)); |
ed34e3c3 A |
339 | ipc_close(rmc.c); |
340 | } | |
341 | } | |
342 | launch_data_free(rmc.resp); | |
343 | } | |
344 | ||
ed34e3c3 A |
345 | void |
346 | ipc_readmsg2(launch_data_t data, const char *cmd, void *context) | |
347 | { | |
348 | struct readmsg_context *rmc = context; | |
349 | launch_data_t resp = NULL; | |
5b0a4722 | 350 | job_t j; |
ed34e3c3 | 351 | |
5b0a4722 | 352 | if (rmc->resp) { |
ed34e3c3 | 353 | return; |
5b0a4722 A |
354 | } |
355 | ||
ddbbfbc1 A |
356 | // job_log(rmc->c->j, LOG_NOTICE, "Socket IPC request: %s.", cmd); |
357 | ||
358 | /* Do not allow commands other than check-in to come over the trusted socket | |
359 | * on the Desktop. On Embedded, allow all commands over the trusted socket if | |
360 | * the job has the God Mode key set. | |
361 | */ | |
362 | #if TARGET_OS_EMBEDDED | |
363 | bool allow_privileged_ops = ( !rmc->c->j || job_is_god(rmc->c->j) ); | |
364 | #else | |
365 | bool allow_privileged_ops = !rmc->c->j; | |
366 | #endif | |
367 | ||
368 | if( rmc->c->j && strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0 ) { | |
369 | resp = job_export(rmc->c->j); | |
370 | job_checkin(rmc->c->j); | |
371 | } else if( allow_privileged_ops ) { | |
372 | #if TARGET_OS_EMBEDDED | |
373 | g_embedded_privileged_action = rmc->c->j && job_is_god(rmc->c->j); | |
374 | #endif | |
375 | if( data == NULL ) { | |
376 | if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) { | |
377 | launchd_shutdown(); | |
378 | resp = launch_data_new_errno(0); | |
379 | } else if (!strcmp(cmd, LAUNCH_KEY_SINGLEUSER)) { | |
380 | launchd_single_user(); | |
381 | resp = launch_data_new_errno(0); | |
382 | } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) { | |
383 | resp = job_export_all(); | |
384 | ipc_revoke_fds(resp); | |
385 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) { | |
386 | resp = adjust_rlimits(NULL); | |
387 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) { | |
388 | struct rusage rusage; | |
389 | getrusage(RUSAGE_SELF, &rusage); | |
390 | resp = launch_data_new_opaque(&rusage, sizeof(rusage)); | |
391 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) { | |
392 | struct rusage rusage; | |
393 | getrusage(RUSAGE_CHILDREN, &rusage); | |
394 | resp = launch_data_new_opaque(&rusage, sizeof(rusage)); | |
ed34e3c3 | 395 | } |
ed34e3c3 | 396 | } else { |
ddbbfbc1 A |
397 | if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) { |
398 | if ((j = job_find(launch_data_get_string(data))) != NULL) { | |
399 | errno = job_dispatch(j, true) ? 0 : errno; | |
400 | } | |
401 | resp = launch_data_new_errno(errno); | |
402 | } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) { | |
403 | if ((j = job_find(launch_data_get_string(data))) != NULL) { | |
404 | errno = 0; | |
405 | job_stop(j); | |
406 | } | |
407 | resp = launch_data_new_errno(errno); | |
408 | } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) { | |
409 | if ((j = job_find(launch_data_get_string(data))) != NULL) { | |
410 | errno = 0; | |
411 | job_remove(j); | |
412 | } | |
413 | resp = launch_data_new_errno(errno); | |
414 | } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) { | |
415 | if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) { | |
416 | resp = job_import_bulk(data); | |
417 | } else { | |
418 | if (job_import(data)) { | |
419 | errno = 0; | |
420 | } | |
421 | resp = launch_data_new_errno(errno); | |
422 | } | |
423 | } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) { | |
424 | unsetenv(launch_data_get_string(data)); | |
425 | resp = launch_data_new_errno(0); | |
426 | } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) { | |
427 | launch_data_dict_iterate(data, set_user_env, NULL); | |
428 | resp = launch_data_new_errno(0); | |
429 | } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) { | |
430 | resp = adjust_rlimits(data); | |
431 | } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) { | |
432 | if ((j = job_find(launch_data_get_string(data))) == NULL) { | |
433 | resp = launch_data_new_errno(errno); | |
434 | } else { | |
435 | resp = job_export(j); | |
436 | ipc_revoke_fds(resp); | |
437 | } | |
438 | } else if( !strcmp(cmd, LAUNCH_KEY_SETPRIORITYLIST) ) { | |
439 | resp = launch_data_new_errno(launchd_set_jetsam_priorities(data)); | |
5b0a4722 | 440 | } |
ed34e3c3 | 441 | } |
ddbbfbc1 A |
442 | #if TARGET_OS_EMBEDDED |
443 | g_embedded_privileged_action = false; | |
444 | #endif | |
445 | } else { | |
446 | resp = launch_data_new_errno(EACCES); | |
ed34e3c3 A |
447 | } |
448 | ||
449 | rmc->resp = resp; | |
450 | } | |
451 | ||
ddbbfbc1 A |
452 | static int |
453 | close_abi_fixup(int fd) | |
454 | { | |
455 | return runtime_close(fd); | |
456 | } | |
457 | ||
ed34e3c3 A |
458 | void |
459 | ipc_close(struct conncb *c) | |
460 | { | |
5b0a4722 | 461 | LIST_REMOVE(c, sle); |
ddbbfbc1 | 462 | launchd_close(c->conn, close_abi_fixup); |
ed34e3c3 A |
463 | free(c); |
464 | } | |
465 | ||
466 | launch_data_t | |
467 | adjust_rlimits(launch_data_t in) | |
468 | { | |
469 | struct rlimit l[RLIM_NLIMITS]; | |
470 | struct rlimit *ltmp; | |
471 | size_t i,ltmpsz; | |
472 | ||
473 | for (i = 0; i < RLIM_NLIMITS; i++) { | |
474 | launchd_assumes(getrlimit(i, l + i) != -1); | |
475 | } | |
476 | ||
477 | if (in) { | |
478 | ltmp = launch_data_get_opaque(in); | |
479 | ltmpsz = launch_data_get_opaque_size(in); | |
480 | ||
481 | if (ltmpsz > sizeof(l)) { | |
5b0a4722 | 482 | runtime_syslog(LOG_WARNING, "Too much rlimit data sent!"); |
ed34e3c3 A |
483 | ltmpsz = sizeof(l); |
484 | } | |
485 | ||
486 | for (i = 0; i < (ltmpsz / sizeof(struct rlimit)); i++) { | |
5b0a4722 | 487 | if (ltmp[i].rlim_cur == l[i].rlim_cur && ltmp[i].rlim_max == l[i].rlim_max) { |
ed34e3c3 | 488 | continue; |
5b0a4722 | 489 | } |
ed34e3c3 | 490 | |
ddbbfbc1 | 491 | if (/* XXX readcfg_pid && */ pid1_magic && (i == RLIMIT_NOFILE || i == RLIMIT_NPROC)) { |
ed34e3c3 A |
492 | int gmib[] = { CTL_KERN, KERN_MAXPROC }; |
493 | int pmib[] = { CTL_KERN, KERN_MAXPROCPERUID }; | |
494 | const char *gstr = "kern.maxproc"; | |
495 | const char *pstr = "kern.maxprocperuid"; | |
496 | int gval = ltmp[i].rlim_max; | |
497 | int pval = ltmp[i].rlim_cur; | |
498 | switch (i) { | |
499 | case RLIMIT_NOFILE: | |
500 | gmib[1] = KERN_MAXFILES; | |
501 | pmib[1] = KERN_MAXFILESPERPROC; | |
502 | gstr = "kern.maxfiles"; | |
503 | pstr = "kern.maxfilesperproc"; | |
504 | break; | |
ed34e3c3 A |
505 | default: |
506 | break; | |
507 | } | |
508 | ||
509 | if (gval > 0) { | |
510 | launchd_assumes(sysctl(gmib, 2, NULL, NULL, &gval, sizeof(gval)) != -1); | |
511 | } else { | |
5b0a4722 | 512 | runtime_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", gstr); |
ed34e3c3 A |
513 | } |
514 | if (pval > 0) { | |
515 | launchd_assumes(sysctl(pmib, 2, NULL, NULL, &pval, sizeof(pval)) != -1); | |
516 | } else { | |
5b0a4722 | 517 | runtime_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", pstr); |
ed34e3c3 A |
518 | } |
519 | } | |
520 | launchd_assumes(setrlimit(i, ltmp + i) != -1); | |
521 | /* the kernel may have clamped the values we gave it */ | |
522 | launchd_assumes(getrlimit(i, l + i) != -1); | |
523 | } | |
524 | } | |
525 | ||
526 | return launch_data_new_opaque(l, sizeof(struct rlimit) * RLIM_NLIMITS); | |
527 | } |