Commit | Line | Data |
---|---|---|
60b6c79c MD |
1 | /* |
2 | * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca> | |
3 | * Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
4 | * | |
d14d33bf AM |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License, version 2 only, | |
7 | * as published by the Free Software Foundation. | |
60b6c79c MD |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
d14d33bf | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
60b6c79c MD |
12 | * more details. |
13 | * | |
d14d33bf AM |
14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
60b6c79c MD |
17 | */ |
18 | ||
19 | #define _GNU_SOURCE | |
6c1c0768 | 20 | #define _LGPL_SOURCE |
60b6c79c MD |
21 | #include <errno.h> |
22 | #include <limits.h> | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <sys/wait.h> | |
27 | #include <sys/types.h> | |
28 | #include <sys/stat.h> | |
29 | #include <unistd.h> | |
30 | #include <fcntl.h> | |
c2b75c49 | 31 | #include <sched.h> |
730389d9 | 32 | #include <sys/signal.h> |
60b6c79c | 33 | |
90e535ef | 34 | #include <common/common.h> |
3fd15a74 | 35 | #include <common/utils.h> |
e8fa9fb0 | 36 | #include <common/compat/getenv.h> |
7567352f | 37 | #include <common/sessiond-comm/unix.h> |
60b6c79c | 38 | |
0857097f DG |
39 | #include "runas.h" |
40 | ||
7567352f MD |
41 | struct run_as_data; |
42 | typedef int (*run_as_fct)(struct run_as_data *data); | |
c2b75c49 | 43 | |
e11d277b | 44 | struct run_as_mkdir_data { |
7567352f | 45 | char path[PATH_MAX]; |
60b6c79c MD |
46 | mode_t mode; |
47 | }; | |
48 | ||
e11d277b | 49 | struct run_as_open_data { |
7567352f | 50 | char path[PATH_MAX]; |
60b6c79c MD |
51 | int flags; |
52 | mode_t mode; | |
53 | }; | |
54 | ||
4628484a | 55 | struct run_as_unlink_data { |
7567352f | 56 | char path[PATH_MAX]; |
4628484a MD |
57 | }; |
58 | ||
7567352f MD |
59 | struct run_as_rmdir_recursive_data { |
60 | char path[PATH_MAX]; | |
61 | }; | |
62 | ||
63 | enum run_as_cmd { | |
64 | RUN_AS_MKDIR, | |
65 | RUN_AS_OPEN, | |
66 | RUN_AS_UNLINK, | |
67 | RUN_AS_RMDIR_RECURSIVE, | |
68 | RUN_AS_MKDIR_RECURSIVE, | |
69 | }; | |
70 | ||
71 | struct run_as_data { | |
72 | enum run_as_cmd cmd; | |
73 | union { | |
74 | struct run_as_mkdir_data mkdir; | |
75 | struct run_as_open_data open; | |
76 | struct run_as_unlink_data unlink; | |
77 | struct run_as_rmdir_recursive_data rmdir_recursive; | |
78 | } u; | |
79 | uid_t uid; | |
80 | gid_t gid; | |
4628484a MD |
81 | }; |
82 | ||
df5b86c8 MD |
83 | struct run_as_ret { |
84 | int ret; | |
85 | int _errno; | |
86 | }; | |
87 | ||
7567352f MD |
88 | struct run_as_worker { |
89 | pid_t pid; /* Worker PID. */ | |
90 | int sockpair[2]; | |
91 | char *procname; | |
92 | }; | |
93 | ||
94 | /* Single global worker per process (for now). */ | |
95 | static struct run_as_worker *global_worker; | |
96 | /* Lock protecting the worker. */ | |
97 | static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER; | |
98 | ||
8f0044bf MD |
99 | #ifdef VALGRIND |
100 | static | |
101 | int use_clone(void) | |
102 | { | |
103 | return 0; | |
104 | } | |
105 | #else | |
106 | static | |
107 | int use_clone(void) | |
108 | { | |
e8fa9fb0 | 109 | return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE"); |
8f0044bf MD |
110 | } |
111 | #endif | |
112 | ||
d77dded2 JG |
113 | LTTNG_HIDDEN |
114 | int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode); | |
115 | ||
60b6c79c MD |
116 | /* |
117 | * Create recursively directory using the FULL path. | |
118 | */ | |
119 | static | |
7567352f | 120 | int _mkdir_recursive(struct run_as_data *data) |
60b6c79c | 121 | { |
60b6c79c | 122 | const char *path; |
60b6c79c | 123 | mode_t mode; |
60b6c79c | 124 | |
7567352f MD |
125 | path = data->u.mkdir.path; |
126 | mode = data->u.mkdir.mode; | |
60b6c79c | 127 | |
d77dded2 JG |
128 | /* Safe to call as we have transitioned to the requested uid/gid. */ |
129 | return _utils_mkdir_recursive_unsafe(path, mode); | |
60b6c79c MD |
130 | } |
131 | ||
132 | static | |
7567352f | 133 | int _mkdir(struct run_as_data *data) |
60b6c79c | 134 | { |
7567352f MD |
135 | return mkdir(data->u.mkdir.path, data->u.mkdir.mode); |
136 | } | |
7ce36756 | 137 | |
7567352f MD |
138 | static |
139 | int _open(struct run_as_data *data) | |
140 | { | |
141 | return open(data->u.open.path, data->u.open.flags, data->u.open.mode); | |
142 | } | |
143 | ||
144 | static | |
145 | int _unlink(struct run_as_data *data) | |
146 | { | |
147 | return unlink(data->u.unlink.path); | |
60b6c79c MD |
148 | } |
149 | ||
150 | static | |
7567352f | 151 | int _rmdir_recursive(struct run_as_data *data) |
60b6c79c | 152 | { |
7567352f MD |
153 | return utils_recursive_rmdir(data->u.rmdir_recursive.path); |
154 | } | |
df5b86c8 | 155 | |
7567352f MD |
156 | static |
157 | run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd) | |
158 | { | |
159 | switch (cmd) { | |
160 | case RUN_AS_MKDIR: | |
161 | return _mkdir; | |
162 | case RUN_AS_OPEN: | |
163 | return _open; | |
164 | case RUN_AS_UNLINK: | |
165 | return _unlink; | |
166 | case RUN_AS_RMDIR_RECURSIVE: | |
167 | return _rmdir_recursive; | |
168 | case RUN_AS_MKDIR_RECURSIVE: | |
169 | return _mkdir_recursive; | |
170 | default: | |
171 | ERR("Unknown command %d", (int) cmd) | |
172 | return NULL; | |
173 | } | |
60b6c79c MD |
174 | } |
175 | ||
4628484a | 176 | static |
7567352f MD |
177 | int do_send_fd(struct run_as_worker *worker, |
178 | enum run_as_cmd cmd, int fd) | |
4628484a | 179 | { |
7567352f | 180 | ssize_t len; |
4628484a | 181 | |
7567352f MD |
182 | switch (cmd) { |
183 | case RUN_AS_OPEN: | |
184 | break; | |
185 | default: | |
186 | return 0; | |
187 | } | |
188 | if (fd < 0) { | |
189 | return 0; | |
190 | } | |
191 | len = lttcomm_send_fds_unix_sock(worker->sockpair[1], &fd, 1); | |
192 | if (len < 0) { | |
193 | PERROR("lttcomm_send_fds_unix_sock"); | |
194 | return -1; | |
195 | } | |
196 | if (close(fd) < 0) { | |
197 | PERROR("close"); | |
198 | return -1; | |
199 | } | |
200 | return 0; | |
4628484a MD |
201 | } |
202 | ||
203 | static | |
7567352f MD |
204 | int do_recv_fd(struct run_as_worker *worker, |
205 | enum run_as_cmd cmd, int *fd) | |
4628484a | 206 | { |
7567352f | 207 | ssize_t len; |
4628484a | 208 | |
7567352f MD |
209 | switch (cmd) { |
210 | case RUN_AS_OPEN: | |
211 | break; | |
212 | default: | |
213 | return 0; | |
214 | } | |
215 | if (*fd < 0) { | |
216 | return 0; | |
217 | } | |
218 | len = lttcomm_recv_fds_unix_sock(worker->sockpair[0], fd, 1); | |
219 | if (len < 0) { | |
220 | PERROR("lttcomm_recv_fds_unix_sock"); | |
221 | return -1; | |
222 | } | |
223 | return 0; | |
4628484a MD |
224 | } |
225 | ||
7567352f MD |
226 | /* |
227 | * Return < 0 on error, 0 if OK, 1 on hangup. | |
228 | */ | |
c2b75c49 | 229 | static |
7567352f | 230 | int handle_one_cmd(struct run_as_worker *worker) |
c2b75c49 | 231 | { |
7567352f MD |
232 | int ret = 0; |
233 | struct run_as_data data; | |
234 | ssize_t readlen, writelen; | |
df5b86c8 | 235 | struct run_as_ret sendret; |
7567352f MD |
236 | run_as_fct cmd; |
237 | uid_t prev_euid; | |
238 | ||
239 | /* Read data */ | |
240 | readlen = lttcomm_recv_unix_sock(worker->sockpair[1], &data, | |
241 | sizeof(data)); | |
242 | if (readlen == 0) { | |
243 | /* hang up */ | |
244 | ret = 1; | |
245 | goto end; | |
246 | } | |
247 | if (readlen < sizeof(data)) { | |
248 | PERROR("lttcomm_recv_unix_sock error"); | |
249 | ret = -1; | |
250 | goto end; | |
251 | } | |
c2b75c49 | 252 | |
7567352f MD |
253 | cmd = run_as_enum_to_fct(data.cmd); |
254 | if (!cmd) { | |
255 | ret = -1; | |
256 | goto end; | |
257 | } | |
258 | ||
259 | prev_euid = getuid(); | |
260 | if (data.gid != getegid()) { | |
261 | ret = setegid(data.gid); | |
1576d582 | 262 | if (ret < 0) { |
4c462e79 | 263 | PERROR("setegid"); |
6d73c4ef | 264 | goto write_return; |
1576d582 | 265 | } |
c2b75c49 | 266 | } |
7567352f MD |
267 | if (data.uid != prev_euid) { |
268 | ret = seteuid(data.uid); | |
1576d582 | 269 | if (ret < 0) { |
4c462e79 | 270 | PERROR("seteuid"); |
6d73c4ef | 271 | goto write_return; |
1576d582 | 272 | } |
c2b75c49 MD |
273 | } |
274 | /* | |
275 | * Also set umask to 0 for mkdir executable bit. | |
276 | */ | |
277 | umask(0); | |
7567352f | 278 | ret = (*cmd)(&data); |
6d73c4ef MD |
279 | |
280 | write_return: | |
df5b86c8 MD |
281 | sendret.ret = ret; |
282 | sendret._errno = errno; | |
c2b75c49 | 283 | /* send back return value */ |
7567352f MD |
284 | writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret, |
285 | sizeof(sendret)); | |
6cd525e8 | 286 | if (writelen < sizeof(sendret)) { |
7567352f MD |
287 | PERROR("lttcomm_send_unix_sock error"); |
288 | ret = -1; | |
289 | goto end; | |
290 | } | |
291 | ret = do_send_fd(worker, data.cmd, ret); | |
292 | if (ret) { | |
293 | PERROR("do_send_fd error"); | |
294 | ret = -1; | |
295 | goto end; | |
296 | } | |
297 | if (seteuid(prev_euid) < 0) { | |
298 | PERROR("seteuid"); | |
299 | ret = -1; | |
300 | goto end; | |
301 | } | |
302 | ret = 0; | |
303 | end: | |
304 | return ret; | |
305 | } | |
306 | ||
307 | static | |
308 | int run_as_worker(struct run_as_worker *worker) | |
309 | { | |
310 | int ret; | |
311 | ssize_t writelen; | |
312 | struct run_as_ret sendret; | |
313 | size_t proc_orig_len; | |
314 | ||
315 | /* | |
316 | * Initialize worker. Set a different process cmdline. | |
317 | */ | |
318 | proc_orig_len = strlen(worker->procname); | |
319 | memset(worker->procname, 0, proc_orig_len); | |
320 | strncpy(worker->procname, DEFAULT_RUN_AS_WORKER_NAME, proc_orig_len); | |
321 | ||
322 | ret = pthread_setname_np(pthread_self(), DEFAULT_RUN_AS_WORKER_NAME); | |
323 | if (ret) { | |
324 | errno = ret; | |
325 | ret = -1; | |
326 | PERROR("pthread_setname_np"); | |
6cd525e8 | 327 | return EXIT_FAILURE; |
6cd525e8 | 328 | } |
7567352f MD |
329 | |
330 | sendret.ret = 0; | |
331 | sendret._errno = 0; | |
332 | writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret, | |
333 | sizeof(sendret)); | |
334 | if (writelen < sizeof(sendret)) { | |
335 | PERROR("lttcomm_send_unix_sock error"); | |
336 | ret = EXIT_FAILURE; | |
337 | goto end; | |
338 | } | |
339 | ||
340 | for (;;) { | |
341 | ret = handle_one_cmd(worker); | |
342 | if (ret < 0) { | |
343 | ret = EXIT_FAILURE; | |
344 | goto end; | |
345 | } else if (ret > 0) { | |
346 | break; | |
347 | } else { | |
348 | continue; /* Next command. */ | |
349 | } | |
350 | } | |
351 | ret = EXIT_SUCCESS; | |
352 | end: | |
353 | return ret; | |
c2b75c49 MD |
354 | } |
355 | ||
60b6c79c | 356 | static |
7567352f MD |
357 | int run_as_cmd(struct run_as_worker *worker, |
358 | enum run_as_cmd cmd, | |
359 | struct run_as_data *data, | |
360 | uid_t uid, gid_t gid) | |
60b6c79c | 361 | { |
7567352f | 362 | ssize_t readlen, writelen; |
df5b86c8 | 363 | struct run_as_ret recvret; |
60b6c79c | 364 | |
7567352f | 365 | pthread_mutex_lock(&worker_lock); |
60b6c79c MD |
366 | /* |
367 | * If we are non-root, we can only deal with our own uid. | |
368 | */ | |
369 | if (geteuid() != 0) { | |
370 | if (uid != geteuid()) { | |
df5b86c8 MD |
371 | recvret.ret = -1; |
372 | recvret._errno = EPERM; | |
60b6c79c MD |
373 | ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)", |
374 | uid, geteuid()); | |
df5b86c8 | 375 | goto end; |
60b6c79c | 376 | } |
60b6c79c MD |
377 | } |
378 | ||
7567352f MD |
379 | data->cmd = cmd; |
380 | data->uid = uid; | |
381 | data->gid = gid; | |
382 | ||
383 | writelen = lttcomm_send_unix_sock(worker->sockpair[0], data, | |
384 | sizeof(*data)); | |
385 | if (writelen < sizeof(*data)) { | |
386 | PERROR("Error writing message to run_as"); | |
df5b86c8 MD |
387 | recvret.ret = -1; |
388 | recvret._errno = errno; | |
60b6c79c | 389 | goto end; |
c2b75c49 | 390 | } |
7567352f | 391 | |
c2b75c49 | 392 | /* receive return value */ |
7567352f MD |
393 | readlen = lttcomm_recv_unix_sock(worker->sockpair[0], &recvret, |
394 | sizeof(recvret)); | |
df5b86c8 | 395 | if (readlen < sizeof(recvret)) { |
7567352f | 396 | PERROR("Error reading response from run_as"); |
df5b86c8 MD |
397 | recvret.ret = -1; |
398 | recvret._errno = errno; | |
6cd525e8 | 399 | } |
7567352f | 400 | if (do_recv_fd(worker, cmd, &recvret.ret)) { |
df5b86c8 | 401 | recvret.ret = -1; |
7567352f | 402 | recvret._errno = -EIO; |
4c462e79 | 403 | } |
7567352f | 404 | |
60b6c79c | 405 | end: |
7567352f | 406 | pthread_mutex_unlock(&worker_lock); |
df5b86c8 MD |
407 | errno = recvret._errno; |
408 | return recvret.ret; | |
60b6c79c MD |
409 | } |
410 | ||
2d85a600 | 411 | /* |
7567352f | 412 | * This is for debugging ONLY and should not be considered secure. |
2d85a600 MD |
413 | */ |
414 | static | |
7567352f MD |
415 | int run_as_noworker(enum run_as_cmd cmd, |
416 | struct run_as_data *data, uid_t uid, gid_t gid) | |
2d85a600 | 417 | { |
df5b86c8 | 418 | int ret, saved_errno; |
5b73926f | 419 | mode_t old_mask; |
7567352f | 420 | run_as_fct fct; |
5b73926f | 421 | |
7567352f MD |
422 | fct = run_as_enum_to_fct(cmd); |
423 | if (!fct) { | |
424 | errno = -ENOSYS; | |
425 | ret = -1; | |
426 | goto end; | |
427 | } | |
5b73926f | 428 | old_mask = umask(0); |
7567352f | 429 | ret = fct(data); |
df5b86c8 | 430 | saved_errno = errno; |
5b73926f | 431 | umask(old_mask); |
df5b86c8 | 432 | errno = saved_errno; |
7567352f | 433 | end: |
5b73926f | 434 | return ret; |
2d85a600 MD |
435 | } |
436 | ||
437 | static | |
7567352f MD |
438 | int run_as(struct run_as_worker *worker, |
439 | enum run_as_cmd cmd, | |
440 | struct run_as_data *data, uid_t uid, gid_t gid) | |
2d85a600 | 441 | { |
7567352f MD |
442 | int ret; |
443 | ||
444 | if (worker) { | |
445 | DBG("Using run_as worker"); | |
446 | ret = run_as_cmd(worker, cmd, data, uid, gid); | |
2d85a600 | 447 | } else { |
7567352f MD |
448 | DBG("Using run_as without worker"); |
449 | ret = run_as_noworker(cmd, data, uid, gid); | |
2d85a600 | 450 | } |
7567352f | 451 | return ret; |
2d85a600 MD |
452 | } |
453 | ||
90e535ef | 454 | LTTNG_HIDDEN |
e11d277b | 455 | int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid) |
60b6c79c | 456 | { |
7567352f MD |
457 | struct run_as_worker *worker = global_worker; |
458 | struct run_as_data data; | |
60b6c79c MD |
459 | |
460 | DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d", | |
461 | path, mode, uid, gid); | |
7567352f MD |
462 | strncpy(data.u.mkdir.path, path, PATH_MAX - 1); |
463 | data.u.mkdir.path[PATH_MAX - 1] = '\0'; | |
464 | data.u.mkdir.mode = mode; | |
465 | return run_as(worker, RUN_AS_MKDIR_RECURSIVE, &data, uid, gid); | |
60b6c79c MD |
466 | } |
467 | ||
90e535ef | 468 | LTTNG_HIDDEN |
e11d277b | 469 | int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) |
60b6c79c | 470 | { |
7567352f MD |
471 | struct run_as_worker *worker = global_worker; |
472 | struct run_as_data data; | |
60b6c79c MD |
473 | |
474 | DBG3("mkdir() %s with mode %d for uid %d and gid %d", | |
475 | path, mode, uid, gid); | |
7567352f MD |
476 | strncpy(data.u.mkdir.path, path, PATH_MAX - 1); |
477 | data.u.mkdir.path[PATH_MAX - 1] = '\0'; | |
478 | data.u.mkdir.mode = mode; | |
479 | return run_as(worker, RUN_AS_MKDIR, &data, uid, gid); | |
60b6c79c MD |
480 | } |
481 | ||
482 | /* | |
483 | * Note: open_run_as is currently not working. We'd need to pass the fd | |
484 | * opened in the child to the parent. | |
485 | */ | |
90e535ef | 486 | LTTNG_HIDDEN |
e11d277b | 487 | int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) |
60b6c79c | 488 | { |
7567352f MD |
489 | struct run_as_worker *worker = global_worker; |
490 | struct run_as_data data; | |
c2b75c49 | 491 | |
47fb7563 MD |
492 | DBG3("open() %s with flags %X mode %d for uid %d and gid %d", |
493 | path, flags, mode, uid, gid); | |
7567352f MD |
494 | strncpy(data.u.open.path, path, PATH_MAX - 1); |
495 | data.u.open.path[PATH_MAX - 1] = '\0'; | |
496 | data.u.open.flags = flags; | |
497 | data.u.open.mode = mode; | |
498 | return run_as(worker, RUN_AS_OPEN, &data, uid, gid); | |
60b6c79c | 499 | } |
4628484a MD |
500 | |
501 | LTTNG_HIDDEN | |
502 | int run_as_unlink(const char *path, uid_t uid, gid_t gid) | |
503 | { | |
7567352f MD |
504 | struct run_as_worker *worker = global_worker; |
505 | struct run_as_data data; | |
4628484a MD |
506 | |
507 | DBG3("unlink() %s with for uid %d and gid %d", | |
508 | path, uid, gid); | |
7567352f MD |
509 | strncpy(data.u.unlink.path, path, PATH_MAX - 1); |
510 | data.u.unlink.path[PATH_MAX - 1] = '\0'; | |
511 | return run_as(worker, RUN_AS_UNLINK, &data, uid, gid); | |
4628484a MD |
512 | } |
513 | ||
514 | LTTNG_HIDDEN | |
7567352f | 515 | int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid) |
4628484a | 516 | { |
7567352f MD |
517 | struct run_as_worker *worker = global_worker; |
518 | struct run_as_data data; | |
4628484a | 519 | |
7567352f | 520 | DBG3("rmdir_recursive() %s with for uid %d and gid %d", |
4628484a | 521 | path, uid, gid); |
7567352f MD |
522 | strncpy(data.u.rmdir_recursive.path, path, PATH_MAX - 1); |
523 | data.u.rmdir_recursive.path[PATH_MAX - 1] = '\0'; | |
524 | return run_as(worker, RUN_AS_RMDIR_RECURSIVE, &data, uid, gid); | |
525 | } | |
526 | ||
527 | LTTNG_HIDDEN | |
528 | int run_as_create_worker(char *procname) | |
529 | { | |
530 | pid_t pid; | |
531 | int i, ret = 0; | |
532 | ssize_t readlen; | |
533 | struct run_as_ret recvret; | |
534 | struct run_as_worker *worker; | |
535 | ||
536 | if (!use_clone()) { | |
537 | ret = 0; | |
538 | goto end; | |
539 | } | |
540 | worker = zmalloc(sizeof(*worker)); | |
541 | if (!worker) { | |
542 | ret = -ENOMEM; | |
543 | goto end; | |
544 | } | |
545 | worker->procname = procname; | |
546 | /* Create unix socket. */ | |
547 | if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) { | |
548 | ret = -1; | |
549 | goto error_sock; | |
550 | } | |
551 | /* Fork worker. */ | |
552 | pid = fork(); | |
553 | if (pid < 0) { | |
554 | PERROR("fork"); | |
555 | ret = -1; | |
556 | goto error_fork; | |
557 | } else if (pid == 0) { | |
558 | /* Child */ | |
559 | ||
560 | /* Just close, no shutdown. */ | |
561 | if (close(worker->sockpair[0])) { | |
562 | PERROR("close"); | |
563 | exit(EXIT_FAILURE); | |
564 | } | |
565 | worker->sockpair[0] = -1; | |
566 | ret = run_as_worker(worker); | |
567 | if (lttcomm_close_unix_sock(worker->sockpair[1])) { | |
568 | PERROR("close"); | |
569 | ret = -1; | |
570 | } | |
571 | worker->sockpair[1] = -1; | |
572 | exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); | |
573 | } else { | |
574 | /* Parent */ | |
575 | ||
576 | /* Just close, no shutdown. */ | |
577 | if (close(worker->sockpair[1])) { | |
578 | PERROR("close"); | |
579 | ret = -1; | |
580 | goto error_fork; | |
581 | } | |
582 | worker->sockpair[1] = -1; | |
583 | worker->pid = pid; | |
584 | /* Wait for worker to become ready. */ | |
585 | readlen = lttcomm_recv_unix_sock(worker->sockpair[0], | |
586 | &recvret, sizeof(recvret)); | |
587 | if (readlen < sizeof(recvret)) { | |
588 | ERR("readlen: %zd", readlen); | |
589 | PERROR("Error reading response from run_as at creation"); | |
590 | ret = -1; | |
591 | goto error_fork; | |
592 | } | |
593 | global_worker = worker; | |
594 | } | |
595 | end: | |
596 | return ret; | |
597 | ||
598 | /* Error handling. */ | |
599 | error_fork: | |
600 | for (i = 0; i < 2; i++) { | |
601 | if (worker->sockpair[i] < 0) { | |
602 | continue; | |
603 | } | |
604 | if (lttcomm_close_unix_sock(worker->sockpair[i])) { | |
605 | PERROR("close"); | |
606 | } | |
607 | worker->sockpair[i] = -1; | |
608 | } | |
609 | error_sock: | |
610 | free(worker); | |
611 | return ret; | |
612 | } | |
613 | ||
614 | LTTNG_HIDDEN | |
615 | void run_as_destroy_worker(void) | |
616 | { | |
617 | struct run_as_worker *worker = global_worker; | |
618 | int status; | |
619 | pid_t pid; | |
620 | ||
621 | if (!worker) { | |
622 | return; | |
623 | } | |
624 | /* Close unix socket */ | |
625 | if (lttcomm_close_unix_sock(worker->sockpair[0])) { | |
626 | PERROR("close"); | |
627 | } | |
628 | worker->sockpair[0] = -1; | |
629 | /* Wait for worker. */ | |
630 | pid = waitpid(worker->pid, &status, 0); | |
631 | if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { | |
632 | PERROR("wait"); | |
633 | } | |
634 | free(worker); | |
635 | global_worker = NULL; | |
4628484a | 636 | } |