Mike Frysinger wrote: > On Monday 06 April 2009 06:12:06 Mike Frysinger wrote: > > On Saturday 28 February 2009 14:16:30 Jamie Lokier wrote: > > > Mike Frysinger wrote: > > > > (like daemonizing code) > > > > > > It is possible to daemonize on uClinux without exec'ing a new process, > > > using clone() instead of vfork(). I have a version of the daemon() > > > function which does that, which I posted to the Busybox bug tracker > > > years ago; I should really submit it to uClibc. > > > > so we're working on converting the old mantis db to bugzilla, but it's not > > complete (attachments are missing). i tried searching for this but wasnt > > able to find it. could you give it a spin ? > > http://bugstest.busybox.net/ > > > > otherwise i dont suppose you could dig up your old patch ? having daemon() > > support in uClibc would be pretty nice to have under no-mmu ... i read > > through the clone() man page for a while, but i couldnt seem to trick my > > head into figuring out how to emulate proper behavior where the parent and > > grand parent die but the child keeps running, and the child is able to > > return to the calling function with the stack intact. > > nm, what i was missing was that the function argument is evaluated > by userspace, not the kernel. so it's pretty easy to use clone to > (1) have the parent immediately call _exit and (2) have the child > return untouched, and (3) do it in parallel. i'll add this to > uClibc once i test with a real app other than my simple code that > just calls daemon() after checking pgrp/sid.
It's easy but you need an asm wrapper for each architecture, as the parent must not touch the stack before calling _exit. You also have to block signals in the parent otherwise the parent may clobber the stack handling a signal before _exit. My patch is attached below. -- Jamie Many uClinux systems don't have an MMU. Due to lack of MMU, they don't have fork(). Traditionally the daemon() function depends on fork(), however it's possible to implement it using clone() instead. This patch adds a daemon() function for uClinux systems. It works properly for ARM and i386, and has a half-hearted implementation using vfork() for others. Proper support for other architectures can be added by writing a little assembly code. As a bonus, this should run a little faster with MMU, too. I think this should be added to uClibc as it's a useful standard function. The fork_and_exit() function is useful by itself, for programs which need to daemonize but daemon() doesn't have quite the right behaviour. So perhaps fork_and_exit() should be made available too. The x86 and ARM versions are tested; ARM thumb is not. Signed-Off-By: Jamie Lokier <ja...@shareable.org> diff -urN busybox-1.00.orig/libbb/daemon.c busybox-1.00/libbb/daemon.c --- busybox-1.00.orig/libbb/daemon.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.00/libbb/daemon.c 2006-03-22 20:05:55.000000000 +0000 @@ -0,0 +1,161 @@ +/* + * daemon() function for uClinux systems without MMU and fork(). + * + * Copyright (C) 2005-2006 Jamie Lokier <ja...@shareable.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "busybox.h" + +#include <stdio.h> +#include <unistd.h> +#include <sys/file.h> +#include <signal.h> +#include <errno.h> + +#define _PATH_DEVNULL "/dev/null" + +static inline int fork_and_exit( void ) +{ +#if defined(__linux__) && (defined(__i386__) || defined(__arm__)) + + /* Equivalent to fork-then-exit which allows the parent process + to exit properly even when fork() isn't available. The trick + is to use clone(), and make the parent exit without + clobbering any memory. Signals must be blocked to prevent + that clobbering. Unfortunately each implementation of this + is architecture-specific. */ + +# ifndef CLONE_VM +# define CLONE_VM 0x00000100 +# define CLONE_FS 0x00000200 +# define CLONE_FILES 0x00000400 +# define CLONE_SIGHAND 0x00000800 +# endif + + int result; + sigset_t new_set, old_set; + sigfillset(&new_set); + sigprocmask(SIG_BLOCK, &new_set, &old_set); + + { + int flags = (CLONE_VM | CLONE_FS | CLONE_FILES + | CLONE_SIGHAND | SIGCHLD); + +# ifdef __i386__ + __asm__ __volatile__ ( +# ifdef __PIC__ + "pushl %%ebx\n\t" + "movl %1,%%ebx\n\t" +# endif /* __PIC__ */ + "movl $120,%0\n\t" + "int $0x80\n\t" + "testl %0,%0\n\t" + "jle 0f\n\t" + "movl $1,%0\n\t" + "xorl %%ebx,%%ebx\n\t" + "int $0x80\n" + "0:" +# ifdef __PIC__ + "\n\tpopl %%ebx" + : "=a" (result) : "ir" (flags), "c" ((int) 0) +# else /* not __PIC__ */ + : "=a" (result) : "b" (flags), "c" ((int) 0) +# endif /* not __PIC__ */ + ); +# endif /* __i386__ */ +# ifdef __arm__ + register int r0 __asm__("r0"), stack __asm__("r1") = 0; + __asm__ __volatile__ ( +# ifdef __thumb__ + /* This Thumb version hasn't been tested. + If you do test it, please delete this comment. */ + "push {r7}\n\t" + "mov r7, #120\t@ clone\n\t" + "swi 0\n\t" + "cmp r0, #0\n\t" + "ble 0f\n\t" + "mov r0, #0\n\t" + "mov r7, #1\t\t@ exit\n\t" + "swi 0\n" + "0:\t" + "pop {r7}" +# else /* Standard ARM, not Thumb. */ + "swi 0x900000+120\t@ clone\n\t" + "cmp r0, #0\n\t" + "ble 0f\n\t" + "mov r0, #0\n\t" + "swi 0x900000+1\t@ exit\n" + "0:" +# endif /* Standard ARM, not Thumb. */ + : "=r" (r0) + : "0" (flags), "r" (stack) + : "cc", "lr"); + result = r0; +# endif /* __arm__ */ + + } + sigprocmask(SIG_SETMASK, &old_set, (sigset_t *)0); + if (result == 0) + return(0); + errno = -result; + return(-1); + +#else /* Can't do the special thing. */ + + /* Half-hearted version with vfork(). The parent process won't + be able to exit until the child does, so this keeps extra + processes around, and requires the program to be started in + the background. */ + switch (vfork()) { + case -1: + return(-1); + case 0: + return(0); + default: + _exit(0); + } + +#endif /* Can't do the special thing. */ +} + +int daemon( int nochdir, int noclose ) +{ + int fd; + + if (fork_and_exit() == -1) + return(-1); + + if (setsid() == -1) + return(-1); + + /* Make certain we are not a session leader, or else we + * might reacquire a controlling terminal */ + if (fork_and_exit() == -1) + return(-1); + + if (!nochdir) + chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } + return(0); +} _______________________________________________ uClinux-dev mailing list uClinux-dev@uclinux.org http://mailman.uclinux.org/mailman/listinfo/uclinux-dev This message was resent by uclinux-dev@uclinux.org To unsubscribe see: http://mailman.uclinux.org/mailman/options/uclinux-dev