--- checkproc.8 +++ checkproc.8 2011-10-18 09:29:16.195166916 +0000 @@ -17,6 +17,7 @@ Pidofproc \- Checks for a process by exe .HP .B checkproc .RB [ \-vLkNz ] +.RB [ \-x ] .RB [ \-p\ \fIpid_file\fP ] .RB [ \-i\ \fIingnore_file\fP ] .RB [ \-c\ \fIroot\fP ] @@ -30,10 +31,12 @@ Pidofproc \- Checks for a process by exe .B checkproc .B \ \ .RB [ \-vk ] +.RB [ \-x ] .I basename_of_executable .HP .B pidofproc .RB [ \-LkNz ] +.RB [ \-x ] .RB [ \-p\ \fIpid_file\fP ] .RB [ \-i\ \fIingnore_file\fP ] .RB [ \-c\ \fIroot\fP ] @@ -47,6 +50,7 @@ Pidofproc \- Checks for a process by exe .B pidofproc .B \ \ .RB [ \-k ] +.RB [ \-x ] .I basename_of_executable .SH SYNOPSIS LSB 3.1 .HP @@ -250,6 +254,15 @@ are in the zombie state. Without this o handled as not existent because such a process isn't alive but listed in the process table and waits on its parent process. +.TP +.B \-x +Tells +.B checkproc +as well as +.B pidofproc +to use the upto 15 byte long filename name found in +.I /proc//stat +to be able to identify scripts overwriting their command line. .PP .\" .SH EXAMPLE --- checkproc.c +++ checkproc.c 2011-10-17 15:41:46.671646382 +0000 @@ -60,7 +60,7 @@ int main(int argc, char **argv) posixa = getenv("_POSIX_OPTION_ORDER"); unsetenv("_POSIX_OPTION_ORDER"); posixb = getenv("POSIXLY_CORRECT"); unsetenv("POSIXLY_CORRECT"); opterr = 0; - while ((c = getopt(argc, argv, "c:kp:nNhqvzLi:")) != -1) { + while ((c = getopt(argc, argv, "c:kp:nNhqvzLi:x")) != -1) { switch (c) { case 'c': if (optarg && optarg[0] != '-' && !root) { @@ -86,6 +86,9 @@ int main(int argc, char **argv) case 'N': init_nfs(); break; + case 'x': + flags |= STSCRPT; + break; case 'z': flags &= ~NZOMBIE; break; --- killproc.8 +++ killproc.8 2011-10-18 09:27:22.403146549 +0000 @@ -16,6 +16,7 @@ Killproc \- Send signals to processes by .B killproc .RB [ \-vqLN ] .RB [ \-g | -G ] +.RB [ \-x ] .RB [ \-p\ \fIpid_file\fP ] .RB [ \-i\ \fIingnore_file\fP ] .RB [ \-c\ \fIroot\fP ] @@ -269,6 +270,13 @@ Be more verbose. This option list all available signals and some of their synonyms by their number and signal names to standard out. and exits. +.TP +.B \-x +Tells +.B killproc +to use the upto 15 byte long filename name found in +.I /proc//stat +to be able to identify scripts overwriting their command line. .\" .SH EXAMPLES .TP --- killproc.c +++ killproc.c 2011-10-17 15:42:52.871147146 +0000 @@ -96,7 +96,7 @@ int main(int argc, char **argv) posixa = getenv("_POSIX_OPTION_ORDER"); unsetenv("_POSIX_OPTION_ORDER"); posixb = getenv("POSIXLY_CORRECT"); unsetenv("POSIXLY_CORRECT"); opterr = 0; - while ((c = getopt(argc, argv, "c:p:gGnNhlvqt:Li:")) != -1) { + while ((c = getopt(argc, argv, "c:p:gGnNhlvqt:Li:x")) != -1) { switch (c) { case 'c': if (optarg && optarg[0] != '-' && !root) { @@ -135,6 +135,9 @@ int main(int argc, char **argv) case 'N': init_nfs(); break; + case 'x': + flags |= STSCRPT; + break; case 'p': /* Changed from -f to -p to fit startproc and LSB */ /* Allocate here: address optarg (current *argv) isn't freeable */ if (optarg && !pid_file) { --- libinit.c +++ libinit.c 2011-10-24 10:27:48.559146999 +0000 @@ -430,7 +430,19 @@ void logprogress(int prio, const char *f va_end(args); } -/* For mounting the /proc file system */ +/* + * For mounting the /proc file system if missed + * and run umount() at exit() for this case. + */ +static void undo_proc(void) +{ +#ifdef MNT_DETACH + umount2("/proc", MNT_DETACH); +#else + umount("/proc"); +#endif +} + void getproc(void) { struct stat st; @@ -441,6 +453,8 @@ void getproc(void) errno = 0; if (stat("/proc/version", &st) < 0) error(100, "/proc not mounted, failed to mount: %s\n", strerror(errno)); + + atexit(undo_proc); } /* Open the /proc directory, if necessary mounts it */ @@ -570,13 +584,12 @@ static const char * checkscripts(char* e */ scrpt = (char *)memchr(scrpt, 0, cnt); if (!scrpt || (cnt = len - (++scrpt - ent)) <= 0) - goto out; + break; if (*scrpt == '/') { ret = scrpt; goto out; } } while (scrpt && cnt > 0); - out: if (scrpt && root) { char *ptr = strdupa(scrpt); @@ -877,8 +890,11 @@ int pidof (const char * inname, const ch continue; /* Seek for a script not for a binary */ - if (!(scrpt = checkscripts(entry, root, len, d->d_name))) + if (!(scrpt = checkscripts(entry, root, len, d->d_name))) { + if (flags & STSCRPT) + goto risky; continue; + } /* Don't blame our boot scripts having the same name */ if ( (flags & (KILL|DAEMON)) @@ -1128,7 +1144,7 @@ risky: return -1; } - if (!(flags & (KTHREAD|KSHORT))&& isscrpt && + if (!(flags & (KTHREAD|KSHORT)) && isscrpt && (fp = open(proc(buf, "cmdline"), O_PROCMODE)) != -1) { char entry[PATH_MAX+1]; @@ -1142,15 +1158,18 @@ risky: goto out; /* Seek for a script not for a binary */ - if (!(scrpt = checkscripts(entry, root, len, buf))) + if (!(scrpt = checkscripts(entry, root, len, buf))) { + if (flags & STSCRPT) + goto nameonly; goto out; /* Nothing found */ + } if (scrpt && strcmp(scrpt,fullname) == 0) { do_list(pid,getsession(pid),ignore); goto out; /* Done */ } } - +nameonly: if ((fp = open(proc(buf, "stat"), O_PROCMODE)) != -1) { char entry[PATH_MAX+1]; @@ -1313,7 +1332,7 @@ int check_pids (const char * inname, con skip = true; /* No stat entry check needed */ } -risky: + risky: if (!(flags & (KTHREAD|KSHORT)) && isscrpt && (fp = open(proc(pid, "cmdline"), O_PROCMODE)) != -1) { @@ -1332,7 +1351,8 @@ risky: if ((scrpt = checkscripts(entry, root, len, pid))) { if (strcmp(scrpt,fullname) == 0) continue; /* Found */ - skip = true; /* No stat entry check needed */ + if (!(flags & STSCRPT)) + skip = true; /* No stat entry check needed */ } } --- libinit.h +++ libinit.h 2011-10-18 09:13:36.923145552 +0000 @@ -106,6 +106,7 @@ #define FLWLINK 0x0040 #define KSTOP 0x0080 #define KBASE 0x0100 +#define STSCRPT 0x0200 #define MAXENV 20 #define CMDLLEN MAXNAMLEN /* The string length of /proc/12345/cmdline\0\0 + 1 */ @@ -116,6 +117,7 @@ #endif #define DEFPIDEXT ".pid" #define DEFPIDLEN 14 /* The string length of /var/run/.pid + 1 */ +#define COMM_LEN 15 /* The lenght of the task command name in /proc//stat */ extern char **environ; extern char * newenvp[]; @@ -216,10 +218,12 @@ static inline char * base_name ( const c static inline char * swap_name ( const char * base ) { - size_t len = strlen(base) + 2 + 1; - char *swap = (char*)xmalloc(len); - - return strcat(strcat(strcpy(swap,"("),base),")"); + size_t len = strlen(base); + char *swap; + if (len > COMM_LEN) + len = COMM_LEN; + swap = (char*)xmalloc(len + 2 + 1); + return strcat(strncat(strcpy(swap,"("),base, COMM_LEN),")"); } extern void addnewenv ( const char * name, const char * entry ); --- startproc.8 +++ startproc.8 2011-10-18 09:28:45.875646247 +0000 @@ -18,6 +18,7 @@ Start_daemon \- Start processes identifi .HP .B startproc .RB [ \-fLves ] +.RB [ \-x ] .RB [[ \-n\ ] \fI+/\-\fP ] .RB [ \- ( t | T )\ \fI\fP ] .RB [ \-u\ \fIuser\fP ] @@ -32,6 +33,7 @@ Start_daemon \- Start processes identifi .HP .B start_daemon .RB [ \-fLve ] +.RB [ \-x ] .RB [ \-n\ \fI+/\-\fP ] .RB [ \-u\ \fIuser\fP ] .RB [ \-g\ \fIgroup\fP ] @@ -249,6 +251,15 @@ Sets the user ID of the process to .TP .B \-v Verbose output. +.TP +.B \-x +Tells +.B startproc +as well as +.B start_daemon +to use the upto 15 byte long filename name found in +.I /proc//stat +to be able to identify scripts overwriting their command line. .\" .SH EXAMPLE .TP --- startproc.c +++ startproc.c 2011-10-20 12:19:33.523206609 +0000 @@ -109,7 +109,7 @@ int main(int argc, char **argv) } opterr = 0; - while ((c = getopt(argc, argv, "+c:edp:l:hqvsu:g:t:n:fLi:T:wW:")) != -1) { /* `+' is POSIX correct */ + while ((c = getopt(argc, argv, "+c:edp:l:hqvsu:g:t:n:fLi:T:wW:x")) != -1) { /* `+' is POSIX correct */ switch (c) { case 'v': quiet = 0; @@ -127,6 +127,9 @@ int main(int argc, char **argv) dialog = true; seconds = 15; break; + case 'x': + flags |= STSCRPT; + break; case 'p': /* Former option -f */ if (force) warn("option -p does not work in force mode\n"); @@ -412,6 +415,8 @@ static int do_start(const char *inname, const char * fullname; char proc_exe[6+9+4+1]; static struct stat itsme; + sigset_t newset, oldset; + int pipe[2]; if ((n = snprintf(proc_exe, sizeof(proc_exe) - 1, "/proc/%d/exe", getpid())) > 0) { proc_exe[n] = '\0'; @@ -445,11 +450,17 @@ static int do_start(const char *inname, if (sdaemon) pid = 0; else { + sigemptyset(&newset); + sigaddset(&newset, SIGQUIT); + sigaddset(&newset, SIGCHLD); + sigprocmask(SIG_UNBLOCK, &newset, &oldset); save_sigquit = signal(SIGQUIT, sig_quit); if (sigchld) (void)signal(SIGCHLD, sig_chld); else (void)signal(SIGCHLD, SIG_DFL); + if (pipe2(pipe, O_CLOEXEC) < 0) + error(100, "cannot open a pipe: %m\n"); if ((pid = fork()) == 0) { /* Update again to point to the child pid */ fwd_sd_listen_pid(); @@ -459,10 +470,15 @@ static int do_start(const char *inname, switch (pid) { case 0: if (!sdaemon) { + sigprocmask(SIG_SETMASK, &oldset, NULL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); (void)signal(SIGSEGV, SIG_DFL); (void)signal(SIGTERM, SIG_DFL); + + close(pipe[1]); + read(pipe[0], proc_exe, 1); /* Wait on parent with the pipe here */ + close(pipe[0]); } if (root) { @@ -615,8 +631,8 @@ static int do_start(const char *inname, fclose(tmp); fflush(stdout); fflush(stderr); /* flush stdout and especially stderr */ - usleep(1); /* Force the kernel to run the scheduler and update - the environment of the current processes */ + + close(pipe[0]); if ((n = snprintf(proc_exe, sizeof(proc_exe) - 1, "/proc/%d/exe", pid)) > 0) { proc_exe[n] = '\0'; @@ -628,17 +644,21 @@ static int do_start(const char *inname, * pid but before the execve() is done by the kernel, in later * case be sure not to run on our own binary. */ + n = 0; do { struct stat serv; errno = 0; if (stat(proc_exe, &serv) < 0) { if (errno == ENOENT) - break; /* Seems to be a fast system */ - + break; /* Seems to be a very fast system + * should not happen due to the pipe */ error(100, "cannot stat %s: %s\n", proc_exe, strerror(errno)); } + if (n++ == 0) + close(pipe[1]); /* Sync child over the pipe */ + if (itsme.st_dev != serv.st_dev || itsme.st_ino != serv.st_ino) break; /* Seems to be a slow system */ @@ -647,6 +667,9 @@ static int do_start(const char *inname, } while (true); } else { + + close(pipe[1]); /* Sync child over the pipe */ + warn("error in snprintf: %s\n", strerror(errno)); usleep(100*1000); } @@ -657,7 +680,7 @@ retry: case -1: /* WNOHANG and hopefully no child but daemon */ if (errno == EINTR) goto retry; - if (errno != ECHILD) /* ECHILD shouldn´t happen, should it? (it does) */ + if (errno != ECHILD) /* ECHILD should not happen, should it? (it does) */ error(LSB_PROOFE," waitpid on %s: %s\n", fullname, strerror(errno)); break; case 0: /* WNOHANG and no status available */