ustfork: Fix warning about volatile qualifier
[lttng-ust.git] / liblttng-ust-fork / ustfork.c
1 /*
2 * Copyright (C) 2009 Pierre-Marc Fournier
3 * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; version 2.1 of
8 * the License.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #define _GNU_SOURCE
21 #include <lttng/ust-dlfcn.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <signal.h>
25 #include <sched.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <errno.h>
29
30 #include <lttng/ust.h>
31
32 #include <urcu/uatomic.h>
33
34 pid_t fork(void)
35 {
36 static pid_t (*plibc_func)(void) = NULL;
37 pid_t (*func)(void);
38 sigset_t sigset;
39 pid_t retval;
40 int saved_errno;
41
42 func = uatomic_read(&plibc_func);
43 if (func == NULL) {
44 func = dlsym(RTLD_NEXT, "fork");
45 if (func == NULL) {
46 fprintf(stderr, "libustfork: unable to find \"fork\" symbol\n");
47 errno = ENOSYS;
48 return -1;
49 }
50 uatomic_set(&plibc_func, func);
51 }
52
53 ust_before_fork(&sigset);
54 /* Do the real fork */
55 retval = func();
56 saved_errno = errno;
57 if (retval == 0) {
58 /* child */
59 ust_after_fork_child(&sigset);
60 } else {
61 ust_after_fork_parent(&sigset);
62 }
63 errno = saved_errno;
64 return retval;
65 }
66
67 int daemon(int nochdir, int noclose)
68 {
69 static int (*plibc_func)(int nochdir, int noclose) = NULL;
70 int (*func)(int nochdir, int noclose);
71 sigset_t sigset;
72 int retval;
73 int saved_errno;
74
75 func = uatomic_read(&plibc_func);
76 if (func == NULL) {
77 func = dlsym(RTLD_NEXT, "daemon");
78 if (func == NULL) {
79 fprintf(stderr, "libustfork: unable to find \"daemon\" symbol\n");
80 errno = ENOSYS;
81 return -1;
82 }
83 uatomic_set(&plibc_func, func);
84 }
85
86 ust_before_fork(&sigset);
87 /* Do the real daemon call */
88 retval = func(nochdir, noclose);
89 saved_errno = errno;
90 if (retval == 0) {
91 /* child, parent called _exit() directly */
92 ust_after_fork_child(&sigset);
93 } else {
94 /* on error in the parent */
95 ust_after_fork_parent(&sigset);
96 }
97 errno = saved_errno;
98 return retval;
99 }
100
101 int setuid(uid_t uid)
102 {
103 static int (*plibc_func)(uid_t uid) = NULL;
104 int (*func)(uid_t uid);
105 int retval;
106 int saved_errno;
107
108 func = uatomic_read(&plibc_func);
109 if (func == NULL) {
110 func = dlsym(RTLD_NEXT, "setuid");
111 if (func == NULL) {
112 fprintf(stderr, "libustfork: unable to find \"setuid\" symbol\n");
113 errno = ENOSYS;
114 return -1;
115 }
116 uatomic_set(&plibc_func, func);
117 }
118
119 /* Do the real setuid */
120 retval = func(uid);
121 saved_errno = errno;
122
123 ust_after_setuid();
124
125 errno = saved_errno;
126 return retval;
127 }
128
129 int setgid(gid_t gid)
130 {
131 static int (*plibc_func)(gid_t gid) = NULL;
132 int (*func)(gid_t gid);
133 int retval;
134 int saved_errno;
135
136 func = uatomic_read(&plibc_func);
137 if (func == NULL) {
138 func = dlsym(RTLD_NEXT, "setgid");
139 if (func == NULL) {
140 fprintf(stderr, "libustfork: unable to find \"setgid\" symbol\n");
141 errno = ENOSYS;
142 return -1;
143 }
144 uatomic_set(&plibc_func, func);
145 }
146
147 /* Do the real setgid */
148 retval = func(gid);
149 saved_errno = errno;
150
151 ust_after_setgid();
152
153 errno = saved_errno;
154 return retval;
155 }
156
157 int seteuid(uid_t euid)
158 {
159 static int (*plibc_func)(uid_t euid) = NULL;
160 int (*func)(uid_t euid);
161 int retval;
162 int saved_errno;
163
164 func = uatomic_read(&plibc_func);
165 if (func == NULL) {
166 func = dlsym(RTLD_NEXT, "seteuid");
167 if (func == NULL) {
168 fprintf(stderr, "libustfork: unable to find \"seteuid\" symbol\n");
169 errno = ENOSYS;
170 return -1;
171 }
172 uatomic_set(&plibc_func, func);
173 }
174
175 /* Do the real seteuid */
176 retval = func(euid);
177 saved_errno = errno;
178
179 ust_after_seteuid();
180
181 errno = saved_errno;
182 return retval;
183 }
184
185 int setegid(gid_t egid)
186 {
187 static int (*plibc_func)(gid_t egid) = NULL;
188 int (*func)(gid_t egid);
189 int retval;
190 int saved_errno;
191
192 func = uatomic_read(&plibc_func);
193 if (func == NULL) {
194 func = dlsym(RTLD_NEXT, "setegid");
195 if (func == NULL) {
196 fprintf(stderr, "libustfork: unable to find \"setegid\" symbol\n");
197 errno = ENOSYS;
198 return -1;
199 }
200 uatomic_set(&plibc_func, func);
201 }
202
203 /* Do the real setegid */
204 retval = func(egid);
205 saved_errno = errno;
206
207 ust_after_setegid();
208
209 errno = saved_errno;
210 return retval;
211 }
212
213 int setreuid(uid_t ruid, uid_t euid)
214 {
215 static int (*plibc_func)(uid_t ruid, uid_t euid) = NULL;
216 int (*func)(uid_t ruid, uid_t euid);
217 int retval;
218 int saved_errno;
219
220 func = uatomic_read(&plibc_func);
221 if (func == NULL) {
222 func = dlsym(RTLD_NEXT, "setreuid");
223 if (func == NULL) {
224 fprintf(stderr, "libustfork: unable to find \"setreuid\" symbol\n");
225 errno = ENOSYS;
226 return -1;
227 }
228 uatomic_set(&plibc_func, func);
229 }
230
231 /* Do the real setreuid */
232 retval = func(ruid, euid);
233 saved_errno = errno;
234
235 ust_after_setreuid();
236
237 errno = saved_errno;
238 return retval;
239 }
240
241 int setregid(gid_t rgid, gid_t egid)
242 {
243 static int (*plibc_func)(gid_t rgid, gid_t egid) = NULL;
244 int (*func)(gid_t rgid, gid_t egid);
245 int retval;
246 int saved_errno;
247
248 func = uatomic_read(&plibc_func);
249 if (func == NULL) {
250 func = dlsym(RTLD_NEXT, "setregid");
251 if (func == NULL) {
252 fprintf(stderr, "libustfork: unable to find \"setregid\" symbol\n");
253 errno = ENOSYS;
254 return -1;
255 }
256 uatomic_set(&plibc_func, func);
257 }
258
259 /* Do the real setregid */
260 retval = func(rgid, egid);
261 saved_errno = errno;
262
263 ust_after_setregid();
264
265 errno = saved_errno;
266 return retval;
267 }
268
269 #ifdef __linux__
270
271 struct user_desc;
272
273 struct ustfork_clone_info {
274 int (*fn)(void *);
275 void *arg;
276 sigset_t sigset;
277 };
278
279 static int clone_fn(void *arg)
280 {
281 struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg;
282
283 /* clone is now done and we are in child */
284 ust_after_fork_child(&info->sigset);
285 return info->fn(info->arg);
286 }
287
288 int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
289 {
290 static int (*plibc_func)(int (*fn)(void *), void *child_stack,
291 int flags, void *arg, pid_t *ptid,
292 struct user_desc *tls, pid_t *ctid) = NULL;
293 int (*func)(int (*fn)(void *), void *child_stack,
294 int flags, void *arg, pid_t *ptid,
295 struct user_desc *tls, pid_t *ctid);
296 /* var args */
297 pid_t *ptid;
298 struct user_desc *tls;
299 pid_t *ctid;
300 /* end of var args */
301 va_list ap;
302 int retval;
303 int saved_errno;
304
305 va_start(ap, arg);
306 ptid = va_arg(ap, pid_t *);
307 tls = va_arg(ap, struct user_desc *);
308 ctid = va_arg(ap, pid_t *);
309 va_end(ap);
310
311 func = uatomic_read(&plibc_func);
312 if (func == NULL) {
313 func = dlsym(RTLD_NEXT, "clone");
314 if (func == NULL) {
315 fprintf(stderr, "libustfork: unable to find \"clone\" symbol.\n");
316 errno = ENOSYS;
317 return -1;
318 }
319 uatomic_set(&plibc_func, func);
320 }
321
322 if (flags & CLONE_VM) {
323 /*
324 * Creating a thread, no need to intervene, just pass on
325 * the arguments.
326 */
327 retval = func(fn, child_stack, flags, arg, ptid,
328 tls, ctid);
329 saved_errno = errno;
330 } else {
331 /* Creating a real process, we need to intervene. */
332 struct ustfork_clone_info info = { .fn = fn, .arg = arg };
333
334 ust_before_fork(&info.sigset);
335 retval = func(clone_fn, child_stack, flags, &info,
336 ptid, tls, ctid);
337 saved_errno = errno;
338 /* The child doesn't get here. */
339 ust_after_fork_parent(&info.sigset);
340 }
341 errno = saved_errno;
342 return retval;
343 }
344
345 int setns(int fd, int nstype)
346 {
347 static int (*plibc_func)(int fd, int nstype) = NULL;
348 int (*func)(int fd, int nstype);
349 int retval;
350 int saved_errno;
351
352 func = uatomic_read(&plibc_func);
353 if (func == NULL) {
354 func = dlsym(RTLD_NEXT, "setns");
355 if (func == NULL) {
356 fprintf(stderr, "libustfork: unable to find \"setns\" symbol\n");
357 errno = ENOSYS;
358 return -1;
359 }
360 uatomic_set(&plibc_func, func);
361 }
362
363 /* Do the real setns */
364 retval = func(fd, nstype);
365 saved_errno = errno;
366
367 ust_after_setns();
368
369 errno = saved_errno;
370 return retval;
371 }
372
373 int unshare(int flags)
374 {
375 static int (*plibc_func)(int flags) = NULL;
376 int (*func)(int flags);
377 int retval;
378 int saved_errno;
379
380 func = uatomic_read(&plibc_func);
381 if (func == NULL) {
382 func = dlsym(RTLD_NEXT, "unshare");
383 if (func == NULL) {
384 fprintf(stderr, "libustfork: unable to find \"unshare\" symbol\n");
385 errno = ENOSYS;
386 return -1;
387 }
388 uatomic_set(&plibc_func, func);
389 }
390
391 /* Do the real setns */
392 retval = func(flags);
393 saved_errno = errno;
394
395 ust_after_unshare();
396
397 errno = saved_errno;
398 return retval;
399 }
400
401 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
402 {
403 static int (*plibc_func)(uid_t ruid, uid_t euid, uid_t suid) = NULL;
404 int (*func)(uid_t ruid, uid_t euid, uid_t suid);
405 int retval;
406 int saved_errno;
407
408 func = uatomic_read(&plibc_func);
409 if (func == NULL) {
410 func = dlsym(RTLD_NEXT, "setresuid");
411 if (func == NULL) {
412 fprintf(stderr, "libustfork: unable to find \"setresuid\" symbol\n");
413 errno = ENOSYS;
414 return -1;
415 }
416 uatomic_set(&plibc_func, func);
417 }
418
419 /* Do the real setresuid */
420 retval = func(ruid, euid, suid);
421 saved_errno = errno;
422
423 ust_after_setresuid();
424
425 errno = saved_errno;
426 return retval;
427 }
428
429 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
430 {
431 static int (*plibc_func)(gid_t rgid, gid_t egid, gid_t sgid) = NULL;
432 int (*func)(gid_t rgid, gid_t egid, gid_t sgid);
433 int retval;
434 int saved_errno;
435
436 func = uatomic_read(&plibc_func);
437 if (func == NULL) {
438 func = dlsym(RTLD_NEXT, "setresgid");
439 if (func == NULL) {
440 fprintf(stderr, "libustfork: unable to find \"setresgid\" symbol\n");
441 errno = ENOSYS;
442 return -1;
443 }
444 uatomic_set(&plibc_func, func);
445 }
446
447 /* Do the real setresgid */
448 retval = func(rgid, egid, sgid);
449 saved_errno = errno;
450
451 ust_after_setresgid();
452
453 errno = saved_errno;
454 return retval;
455 }
456
457 #elif defined (__FreeBSD__)
458
459 pid_t rfork(int flags)
460 {
461 static pid_t (*plibc_func)(int flags) = NULL;
462 pid_t (*func)(int flags);
463 sigset_t sigset;
464 pid_t retval;
465 int saved_errno;
466
467 func = uatomic_read(&plibc_func);
468 if (func == NULL) {
469 func = dlsym(RTLD_NEXT, "rfork");
470 if (func == NULL) {
471 fprintf(stderr, "libustfork: unable to find \"rfork\" symbol\n");
472 errno = ENOSYS;
473 return -1;
474 }
475 uatomic_set(&plibc_func, func);
476 }
477
478 ust_before_fork(&sigset);
479 /* Do the real rfork */
480 retval = func(flags);
481 saved_errno = errno;
482 if (retval == 0) {
483 /* child */
484 ust_after_fork_child(&sigset);
485 } else {
486 ust_after_fork_parent(&sigset);
487 }
488 errno = saved_errno;
489 return retval;
490 }
491
492 /*
493 * On BSD, no need to override vfork, because it runs in the context of
494 * the parent, with parent waiting until execve or exit is executed in
495 * the child.
496 */
497
498 #else
499 #warning "Unknown OS. You might want to ensure that fork/clone/vfork/fork handling is complete."
500 #endif
This page took 0.038911 seconds and 4 git commands to generate.