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