master xplshn/aruu / cmd / pseudo / killall5.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <dirent.h>
  4#include <limits.h>
  5#include <signal.h>
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9#include <unistd.h>
 10
 11#include "proc.h"
 12#include "queue.h"
 13#include "util.h"
 14
 15struct {
 16  const char *name;
 17  int         sig;
 18} sigs[] = {
 19#define SIG(n) {#n, SIG##n}
 20    SIG(ABRT), SIG(ALRM), SIG(BUS),  SIG(CHLD), SIG(CONT), SIG(FPE),  SIG(HUP),
 21    SIG(ILL),  SIG(INT),  SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
 22    SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG),
 23#undef SIG
 24};
 25
 26struct pidentry {
 27  pid_t pid;
 28  SLIST_ENTRY(pidentry) entry;
 29};
 30
 31static SLIST_HEAD(, pidentry) omitpid_head;
 32
 33static void
 34usage(void)
 35{
 36  eprintf("usage: %s [-o pid1,pid2,..,pidN] [-s signal]\n", argv0);
 37}
 38
 39// ?man killall5: send signal to all processes
 40// ?man arguments: -o pid1
 41// ?man send a signal to all processes except kernel threads
 42int
 43main(int argc, char *argv[])
 44{
 45  struct pidentry *pe;
 46  struct dirent   *entry;
 47  DIR             *dp;
 48  char            *p, *arg = NULL;
 49  char            *end, *v;
 50  int              oflag = 0;
 51  int              sig   = SIGTERM;
 52  pid_t            pid;
 53  size_t           i;
 54
 55  ARGBEGIN
 56  {
 57    // ?man -s:str: silent mode or print summary
 58    case 's':
 59      v   = EARGF(usage());
 60      sig = strtol(v, &end, 0);
 61      if (*end == '\0')
 62        break;
 63      for (i = 0; i < LEN(sigs); i++) {
 64        if (strcasecmp(v, sigs[i].name) == 0) {
 65          sig = sigs[i].sig;
 66          break;
 67        }
 68      }
 69      if (i == LEN(sigs))
 70        eprintf("%s: unknown signal\n", v);
 71      break;
 72    // ?man -o:str: specify output file
 73    case 'o':
 74      oflag = 1;
 75      arg   = EARGF(usage());
 76      break;
 77    default:
 78      usage();
 79  }
 80  ARGEND;
 81
 82  SLIST_INIT(&omitpid_head);
 83
 84  if (oflag) {
 85    for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
 86      pe      = emalloc(sizeof(*pe));
 87      pe->pid = estrtol(p, 10);
 88      SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
 89    }
 90  }
 91
 92  if (sig != SIGSTOP && sig != SIGCONT)
 93    kill(-1, SIGSTOP);
 94
 95  if (!(dp = opendir("/proc")))
 96    eprintf("opendir /proc:");
 97  while ((entry = readdir(dp))) {
 98    if (pidfile(entry->d_name) == 0)
 99      continue;
100    pid = estrtol(entry->d_name, 10);
101    if (pid == 1 || pid == getpid() || getsid(pid) == getsid(0) || getsid(pid) == 0)
102      continue;
103    if (oflag == 1) {
104      SLIST_FOREACH(pe, &omitpid_head, entry)
105      if (pe->pid == pid)
106        break;
107      if (pe)
108        continue;
109    }
110    kill(pid, sig);
111  }
112  closedir(dp);
113
114  if (sig != SIGSTOP && sig != SIGCONT)
115    kill(-1, SIGCONT);
116
117  return 0;
118}