diff options
author | Karel Zak | 2006-12-07 00:25:46 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:46 +0100 |
commit | c07ebfa1e02d208ab12430e6791ea147bcfaf9c0 (patch) | |
tree | d44a755098286f5d553c7aea1a73d98c2995d6ec /login-utils/simpleinit.c | |
parent | Imported from util-linux-2.10s tarball. (diff) | |
download | kernel-qcow2-util-linux-c07ebfa1e02d208ab12430e6791ea147bcfaf9c0.tar.gz kernel-qcow2-util-linux-c07ebfa1e02d208ab12430e6791ea147bcfaf9c0.tar.xz kernel-qcow2-util-linux-c07ebfa1e02d208ab12430e6791ea147bcfaf9c0.zip |
Imported from util-linux-2.11b tarball.
Diffstat (limited to 'login-utils/simpleinit.c')
-rw-r--r-- | login-utils/simpleinit.c | 122 |
1 files changed, 63 insertions, 59 deletions
diff --git a/login-utils/simpleinit.c b/login-utils/simpleinit.c index 9c4b63a5f..56f10455a 100644 --- a/login-utils/simpleinit.c +++ b/login-utils/simpleinit.c @@ -1,8 +1,14 @@ /* simpleinit.c - poe@daimi.aau.dk */ -/* Version 1.21 */ +/* Version 2.0.1 */ -/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> +/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> * - added Native Language Support + * 2001-01-25 Richard Gooch <rgooch@atnf.csiro.au> + * - fixed bug with failed services so they may be later "reclaimed" + * 2001-02-02 Richard Gooch <rgooch@atnf.csiro.au> + * - fixed race when reading from pipe and reaping children + * 2001-02-18 sam@quux.dropbear.id.au + * - fixed bug in <get_path>: multiple INIT_PATH components did not work */ #include <sys/types.h> @@ -31,6 +37,7 @@ #include "my_crypt.h" #include "pathnames.h" #include "linux_reboot.h" +#include "xstrncpy.h" #include "nls.h" #include "simpleinit.h" @@ -77,7 +84,8 @@ static sigjmp_buf jmp_env; static void do_single (void); static int do_rc_tty (const char *path); -static int process_path ( const char *path, int (*func) (const char *path) ); +static int process_path (const char *path, int (*func) (const char *path), + int ignore_dangling_symlink); static int preload_file (const char *path); static int run_file (const char *path); static void spawn (int i), read_inittab (void); @@ -91,7 +99,7 @@ static void sigterm_handler (int sig); static void set_tz (void); #endif static void write_wtmp (void); -static pid_t mywaitpid (pid_t pid, int *status); +static pid_t mywait (int *status); static int run_command (const char *file, const char *name, pid_t pid); @@ -221,7 +229,7 @@ int main(int argc, char *argv[]) } for ever { - pid = mywaitpid (-1, &vec); + pid = mywait (&vec); if (pid < 1) continue; /* clear utmp entry, and append to wtmp if possible */ @@ -322,7 +330,7 @@ static int do_rc_tty (const char *path) sigset_t ss; if (caught_sigint) return 0; - process_path (path, preload_file); + process_path (path, preload_file, 0); /* Launch off a subprocess to start a new session (required for frobbing the TTY) and capture control-C */ switch ( child = fork () ) @@ -344,10 +352,10 @@ static int do_rc_tty (const char *path) break; } /* Parent */ - process_path (path, run_file); + process_path (path, run_file, 0); while (1) { - if ( ( pid = mywaitpid (-1, &status) ) == child ) + if ( ( pid = mywait (&status) ) == child ) return (WTERMSIG (status) == SIGINT) ? 0 : 1; if (pid < 0) break; } @@ -356,17 +364,27 @@ static int do_rc_tty (const char *path) return 0; } /* End Function do_rc_tty */ -static int process_path ( const char *path, int (*func) (const char *path) ) +static int process_path (const char *path, int (*func) (const char *path), + int ignore_dangling_symlink) { struct stat statbuf; DIR *dp; struct dirent *de; - if (stat (path, &statbuf) != 0) + if (lstat (path, &statbuf) != 0) { - err (_ ("stat of path failed\n") ); + err (_ ("lstat of path failed\n") ); return 1; } + if ( S_ISLNK (statbuf.st_mode) ) + { + if (stat (path, &statbuf) != 0) + { + if ( (errno == ENOENT) && ignore_dangling_symlink ) return 0; + err (_ ("stat of path failed\n") ); + return 1; + } + } if ( !( statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH) ) ) return 0; if ( !S_ISDIR (statbuf.st_mode) ) return (*func) (path); if ( ( dp = opendir (path) ) == NULL ) @@ -382,7 +400,7 @@ static int process_path ( const char *path, int (*func) (const char *path) ) if (de->d_name[0] == '.') continue; retval = sprintf (newpath, "%s/%s", path, de->d_name); if (newpath[retval - 1] == '~') continue; /* Common mistake */ - if ( ( retval = process_path (newpath, func) ) ) return retval; + if ( ( retval = process_path (newpath, func, 1) ) ) return retval; } closedir (dp); return 0; @@ -545,11 +563,8 @@ static void read_inittab (void) (void) strcpy(inittab[i].line, buf); (void) strtok(inittab[i].line, ":"); - (void) strncpy(inittab[i].tty, inittab[i].line, 10); - inittab[i].tty[9] = 0; - (void) strncpy(inittab[i].termcap, - strtok((char *)0, ":"), 30); - inittab[i].termcap[29] = 0; + xstrncpy(inittab[i].tty, inittab[i].line, 10); + xstrncpy(inittab[i].termcap, strtok((char *)0, ":"), 30); getty = strtok((char *)0, ":"); (void) strtok(getty, " \t\n"); @@ -566,10 +581,8 @@ static void read_inittab (void) err(_("no TERM or cannot stat tty\n")); } else { /* is it a console tty? */ - if(major(stb.st_rdev) == 4 && minor(stb.st_rdev) < 64) { - strncpy(inittab[i].termcap, termenv, 30); - inittab[i].termcap[29] = 0; - } + if(major(stb.st_rdev) == 4 && minor(stb.st_rdev) < 64) + xstrncpy(inittab[i].termcap, termenv, 30); } #endif @@ -752,40 +765,40 @@ static void show_scripts (FILE *fp, const struct script_struct *script, static const char *get_path (const char *file); -static pid_t mywaitpid (pid_t pid, int *status) +static pid_t mywait (int *status) /* [RETURNS] The pid for a process to be reaped, 0 if no process is to be reaped, and less than 0 if the boot scripts appear to have finished. */ { - int ival; - sigset_t ss_new, ss_old; + pid_t pid; + sigset_t ss; long buffer[COMMAND_SIZE / sizeof (long)]; struct command_struct *command = (struct command_struct *) buffer; - if (initctl_fd < 0) return waitpid (pid, status, 0); - if (status == NULL) status = &ival; - if ( ( pid = waitpid (pid, status, WNOHANG) ) > 0 ) - { - return process_pidstat (pid, *status); - } - /* Some magic to avoid races */ + if (initctl_fd < 0) return wait (status); + /* Some magic to avoid races which can result in lost signals */ command->command = -1; - sigemptyset (&ss_new); - sigaddset (&ss_new, SIGCHLD); - sigprocmask (SIG_BLOCK, &ss_new, &ss_old); - ival = sigsetjmp (jmp_env, 0); - sigprocmask (SIG_SETMASK, &ss_old, NULL); - if (ival == 0) do_longjmp = 1; - else - { + if ( sigsetjmp (jmp_env, 1) ) + { /* Jump from signal handler */ do_longjmp = 0; - if (command->command < 0) return 0; + process_command (command); + return 0; + } + sigemptyset (&ss); /* Block SIGCHLD so wait status cannot be lost */ + sigaddset (&ss, SIGCHLD); + sigprocmask (SIG_BLOCK, &ss, NULL); + if ( ( pid = waitpid (-1, status, WNOHANG) ) > 0 ) + { + sigprocmask (SIG_UNBLOCK, &ss, NULL); + return process_pidstat (pid, *status); } - if (command->command < 0) read (initctl_fd, buffer, COMMAND_SIZE); + do_longjmp = 1; /* After this, SIGCHLD will cause a jump backwards */ + sigprocmask (SIG_UNBLOCK, &ss, NULL); + read (initctl_fd, buffer, COMMAND_SIZE); do_longjmp = 0; process_command (command); return 0; -} /* End Function mywaitpid */ +} /* End Function mywait */ static pid_t process_pidstat (pid_t pid, int status) /* [RETURNS] The pid for a process to be reaped, 0 if no process is to be @@ -978,7 +991,7 @@ static int run_command (const char *file, const char *name, pid_t pid) script = find_script_byname (name, &starting_list, &service); if (script == NULL) service = find_service_in_list (name, unavailable_services); - if (script == NULL) + if (service == NULL) { int i; char txt[1024]; @@ -988,24 +1001,13 @@ static int run_command (const char *file, const char *name, pid_t pid) if (needer != NULL) free (needer); return SIG_FAILED; } + service = calloc (1, strlen (name) + sizeof *service); if (service == NULL) { - service = calloc (1, strlen (name) + sizeof *service); - if (service == NULL) - { - free (script); - return SIG_FAILED; - } - strcpy (service->name, name); - } - else /* Unhook service from unavailable list */ - { - if (service->prev == NULL) unavailable_services = service->next; - else service->prev->next = service->next; - if (service->next != NULL) service->next->prev = service->prev; - service->prev = NULL; - service->next = NULL; + free (script); + return SIG_FAILED; } + strcpy (service->name, name); switch ( script->pid = fork () ) { case 0: /* Child */ @@ -1063,6 +1065,7 @@ static struct script_struct *find_script_byname (const char *name, return (script); } } + if (service != NULL) *service = NULL; return NULL; } /* End Function find_script_byname */ @@ -1121,6 +1124,7 @@ static void handle_nonworking (struct script_struct *script) next = service->next; if (provider == NULL) { + service->prev = NULL; service->next = unavailable_services; if (unavailable_services != NULL) unavailable_services->prev = service; @@ -1180,7 +1184,7 @@ static const char *get_path (const char *file) p2 = p1 + strlen (p1); strncpy (path, p1, p2 - p1); path[p2 - p1] = '/'; - strcat (path + (p2 - p1) + 1, file); + strcpy (path + (p2 - p1) + 1, file); if (*p2 == ':') ++p2; if (access (path, X_OK) == 0) return path; } |