static inline void xmemalign(void **memptr, size_t alignment, size_t size) { if ((posix_memalign(memptr, alignment, size)) < 0) { if (sent_sigstop) kill(-1, SIGCONT); nsyslog(LOG_ERR, "out of memory"); exit(1); } }
/* * See if the proc filesystem is there. Mount if needed. */ int mount_proc(void) { struct stat st; char *args[] = { "mount", "-t", "proc", "proc", "/proc", 0 }; pid_t pid, rc; int wst; int did_mount = 0; /* Stat /proc/version to see if /proc is mounted. */ if (stat("/proc/version", &st) < 0 && errno == ENOENT) { /* It's not there, so mount it. */ if ((pid = fork()) < 0) { nsyslog(LOG_ERR, "cannot fork"); exit(1); } if (pid == 0) { /* Try a few mount binaries. */ execv("/sbin/mount", args); execv("/bin/mount", args); /* Okay, I give up. */ nsyslog(LOG_ERR, "cannot execute mount"); exit(1); } /* Wait for child. */ while ((rc = wait(&wst)) != pid) if (rc < 0 && errno == ECHILD) break; if (rc != pid || WEXITSTATUS(wst) != 0) nsyslog(LOG_ERR, "mount returned non-zero exit status"); did_mount = 1; } /* See if mount succeeded. */ if (stat("/proc/version", &st) < 0) { if (errno == ENOENT) nsyslog(LOG_ERR, "/proc not mounted, failed to mount."); else nsyslog(LOG_ERR, "/proc unavailable."); exit(1); } return did_mount; }
static void *xmalloc(size_t bytes) { void *p; if ((p = malloc(bytes)) == NULL) { if (sent_sigstop) kill(-1, SIGCONT); nsyslog(LOG_ERR, "out of memory"); exit(1); } return p; }
/* Main for either killall or pidof. */ int main(int argc, char **argv) { PROC *p; int pid, sid = -1; pid_t opid[KILLALL_OMITSZ]; int i, oind, omit = 0; int sig = SIGKILL; /* return non-zero if no process was killed */ int retval = 2; /* Get program name. */ if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; /* Now connect to syslog. */ openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON); /* Were we called as 'pidof' ? */ if (strcmp(progname, "pidof") == 0) return main_pidof(argc, argv); /* Right, so we are "killall". */ for (oind = KILLALL_OMITSZ-1; oind > 0; oind--) opid[oind] = 0; if (argc > 1) { for (i = 1; i < argc; i++) { if (argv[i][0] == '-') (argv[i])++; if (argv[i][0] == 'o') { if (++i >= argc) usage(); if (oind >= KILLALL_OMITSZ -1) { nsyslog(LOG_ERR,"omit pid buffer size " "%d exceeded!\n", KILLALL_OMITSZ); closelog(); exit(1); } if ((opid[oind] = atoi(argv[i])) < 1) { nsyslog(LOG_ERR, "illegal omit pid value " "(%s)!\n", argv[i]); closelog(); exit(1); } oind++; omit = 1; } else if ((sig = atoi(argv[1])) <= 0 || sig > 31) usage(); } } /* First get the /proc filesystem online. */ mount_proc(); /* * Ignoring SIGKILL and SIGSTOP do not make sense, but * someday kill(-1, sig) might kill ourself if we don't * do this. This certainly is a valid concern for SIGTERM- * Linux 2.1 might send the calling process the signal too. */ signal(SIGTERM, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGKILL, SIG_IGN); /* lock us into memory */ mlockall(MCL_CURRENT | MCL_FUTURE); /* Now stop all processes. */ kill(-1, SIGSTOP); sent_sigstop = 1; /* Read /proc filesystem */ if (readproc(NO_STAT) < 0) { kill(-1, SIGCONT); return(1); } /* Now kill all processes except init (pid 1) and our session. */ sid = (int)getsid(0); pid = (int)getpid(); for (p = plist; p; p = p->next) { if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel) continue; if (omit) { for (i = 0; i < oind; i++) if (opid[i] == p->pid) break; /* On a match, continue with the for loop above. */ if (i < oind) continue; } kill(p->pid, sig); retval = 0; } /* And let them continue. */ kill(-1, SIGCONT); /* Done. */ closelog(); /* Force the kernel to run the scheduler */ usleep(1); return retval; }
/* * Pidof functionality. */ int main_pidof(int argc, char **argv) { PIDQ_HEAD *q; PROC *p; pid_t opid[PIDOF_OMITSZ], spid; int f; int first = 1; int i, oind, opt, flags = 0; int chroot_check = 0; struct stat st; char tmp[512]; for (oind = PIDOF_OMITSZ-1; oind > 0; oind--) opid[oind] = 0; opterr = 0; while ((opt = getopt(argc,argv,"hco:sx")) != EOF) switch (opt) { case '?': nsyslog(LOG_ERR,"invalid options on command line!\n"); closelog(); exit(1); case 'c': if (geteuid() == 0) chroot_check = 1; break; case 'o': if (oind >= PIDOF_OMITSZ -1) { nsyslog(LOG_ERR,"omit pid buffer size %d " "exceeded!\n", PIDOF_OMITSZ); closelog(); exit(1); } if (strcmp("%PPID",optarg) == 0) opid[oind] = getppid(); else if ((opid[oind] = atoi(optarg)) < 1) { nsyslog(LOG_ERR, "illegal omit pid value (%s)!\n", optarg); closelog(); exit(1); } oind++; flags |= PIDOF_OMIT; break; case 's': flags |= PIDOF_SINGLE; break; case 'x': scripts_too++; break; default: /* Nothing */ break; } argc -= optind; argv += optind; /* Check if we are in a chroot */ if (chroot_check) { snprintf(tmp, 512, "/proc/%d/root", getpid()); if (stat(tmp, &st) < 0) { nsyslog(LOG_ERR, "stat failed for %s!\n", tmp); closelog(); exit(1); } } /* Print out process-ID's one by one. */ readproc(DO_STAT); for(f = 0; f < argc; f++) { if ((q = pidof(argv[f])) != NULL) { spid = 0; while ((p = get_next_from_pid_q(q))) { if (flags & PIDOF_OMIT) { for (i = 0; i < oind; i++) if (opid[i] == p->pid) break; /* * On a match, continue with * the for loop above. */ if (i < oind) continue; } if (flags & PIDOF_SINGLE) { if (spid) continue; else spid = 1; } if (chroot_check) { struct stat st2; snprintf(tmp, 512, "/proc/%d/root", p->pid); if (stat(tmp, &st2) < 0 || st.st_dev != st2.st_dev || st.st_ino != st2.st_ino) { continue; } } if (!first) printf(" "); printf("%d", p->pid); first = 0; } } } if (!first) printf("\n"); closelog(); return(first ? 1 : 0); }
/* Give usage message and exit. */ void usage(void) { nsyslog(LOG_ERR, "only one argument, a signal number, allowed"); closelog(); exit(1); }
/* * Read the proc filesystem. * CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse). */ int readproc(int do_stat) { DIR *dir; FILE *fp; PROC *p, *n; struct dirent *d; struct stat st; char path[256]; char buf[256]; char *s, *q; unsigned long startcode, endcode; int pid, f; /* Open the /proc directory. */ if (chdir("/proc") == -1) { nsyslog(LOG_ERR, "chdir /proc failed"); return -1; } if ((dir = opendir(".")) == NULL) { nsyslog(LOG_ERR, "cannot opendir(/proc)"); return -1; } /* Free the already existing process list. */ n = plist; for (p = plist; n; p = n) { n = p->next; if (p->argv0) free(p->argv0); if (p->argv1) free(p->argv1); free(p); } plist = NULL; /* Walk through the directory. */ while ((d = readdir(dir)) != NULL) { /* See if this is a process */ if ((pid = atoi(d->d_name)) == 0) continue; /* Get a PROC struct . */ p = (PROC *)xmalloc(sizeof(PROC)); memset(p, 0, sizeof(PROC)); /* Open the status file. */ snprintf(path, sizeof(path), "%s/stat", d->d_name); /* Read SID & statname from it. */ if ((fp = fopen(path, "r")) != NULL) { buf[0] = 0; fgets(buf, sizeof(buf), fp); /* See if name starts with '(' */ s = buf; while (*s != ' ') s++; s++; if (*s == '(') { /* Read program name. */ q = strrchr(buf, ')'); if (q == NULL) { p->sid = 0; nsyslog(LOG_ERR, "can't get program name from /proc/%s\n", path); free(p); continue; } s++; } else { q = s; while (*q != ' ') q++; } *q++ = 0; while (*q == ' ') q++; p->statname = (char *)xmalloc(strlen(s)+1); strcpy(p->statname, s); /* Get session, startcode, endcode. */ startcode = endcode = 0; if (sscanf(q, "%*c %*d %*d %d %*d %*d %*u %*u " "%*u %*u %*u %*u %*u %*d %*d " "%*d %*d %*d %*d %*u %*u %*d " "%*u %lu %lu", &p->sid, &startcode, &endcode) != 3) { p->sid = 0; nsyslog(LOG_ERR, "can't read sid from %s\n", path); free(p); continue; } if (startcode == 0 && endcode == 0) p->kernel = 1; fclose(fp); } else { /* Process disappeared.. */ free(p); continue; } snprintf(path, sizeof(path), "%s/cmdline", d->d_name); if ((fp = fopen(path, "r")) != NULL) { /* Now read argv[0] */ f = readarg(fp, buf, sizeof(buf)); if (buf[0]) { /* Store the name into malloced memory. */ p->argv0 = (char *)xmalloc(f + 1); strcpy(p->argv0, buf); /* Get a pointer to the basename. */ p->argv0base = strrchr(p->argv0, '/'); if (p->argv0base != NULL) p->argv0base++; else p->argv0base = p->argv0; } /* And read argv[1] */ while ((f = readarg(fp, buf, sizeof(buf))) != EOF) if (buf[0] != '-') break; if (buf[0]) { /* Store the name into malloced memory. */ p->argv1 = (char *)xmalloc(f + 1); strcpy(p->argv1, buf); /* Get a pointer to the basename. */ p->argv1base = strrchr(p->argv1, '/'); if (p->argv1base != NULL) p->argv1base++; else p->argv1base = p->argv1; } fclose(fp); } else { /* Process disappeared.. */ free(p); continue; } /* Try to stat the executable. */ snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name); if (do_stat && stat(path, &st) == 0) { p->dev = st.st_dev; p->ino = st.st_ino; } /* Link it into the list. */ p->next = plist; plist = p; p->pid = pid; } closedir(dir); /* Done. */ return 0; }