tizen beta release
[external/psmisc.git] / src / killall.c
1 /*
2  * killall.c - kill processes by name or list PIDs
3  *
4  * Copyright (C) 1993-2002 Werner Almesberger
5  * Copyright (C) 2002-2007 Craig Small
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <dirent.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <getopt.h>
42 #include <pwd.h>
43 #include <regex.h>
44
45 #ifdef WITH_SELINUX
46 #include <selinux/selinux.h>
47 #endif /*WITH_SELINUX*/
48
49 #include "i18n.h"
50 #include "comm.h"
51 #include "signals.h"
52
53
54 #define PROC_BASE "/proc"
55 #define MAX_NAMES (int)(sizeof(unsigned long)*8)
56
57
58 static int verbose = 0, exact = 0, interactive = 0, reg = 0,
59            quiet = 0, wait_until_dead = 0, process_group = 0,
60            ignore_case = 0, pidof;
61
62 static int
63 ask (char *name, pid_t pid, const int signal)
64 {
65   int res;
66   size_t len;
67   char *line;
68
69   line = NULL;
70   len = 0;
71
72   do {
73     if (signal == SIGTERM)
74         printf (_("Kill %s(%s%d) ? (y/N) "), name, process_group ? "pgid " : "",
75                 pid);
76     else
77         printf (_("Signal %s(%s%d) ? (y/N) "), name, process_group ? "pgid " : "",
78                 pid);
79
80     fflush (stdout);
81
82     if (getline (&line, &len, stdin) < 0)
83       return 0;
84     /* Check for default */
85     if (line[0] == '\n') {
86       free(line);
87       return 0;
88     }
89     res = rpmatch(line);
90     if (res >= 0) {
91       free(line);
92       return res;
93     }
94   } while(1);
95   /* Never should get here */
96 }
97
98 static int
99 match_process_uid(pid_t pid, uid_t uid)
100 {
101         char buf[128];
102         uid_t puid;
103         FILE *f;
104         int re = -1;
105         
106         snprintf (buf, sizeof buf, PROC_BASE "/%d/status", pid);
107         if (!(f = fopen (buf, "r")))
108                 return 0;
109         
110         while (fgets(buf, sizeof buf, f))
111         {
112                 if (sscanf (buf, "Uid:\t%d", &puid))
113                 {
114                         re = uid==puid;
115                         break;
116                 }
117         }
118         fclose(f);
119         if (re==-1)
120         {
121                 fprintf(stderr, _("Cannot get UID from process status\n"));
122                 exit(1);
123         }
124         return re;
125 }
126
127 static regex_t *
128 build_regexp_list(int names, char **namelist)
129 {
130         int i;
131         regex_t *reglist;
132         int flag = REG_EXTENDED|REG_NOSUB;
133         
134         if (!(reglist = malloc (sizeof (regex_t) * names)))
135         {
136                 perror ("malloc");
137                 exit (1);
138         }
139
140         if (ignore_case)
141                 flag |= REG_ICASE;
142         
143         for (i = 0; i < names; i++)
144         {
145                 if (regcomp(&reglist[i], namelist[i], flag) != 0) 
146                 {
147                         fprintf(stderr, _("Bad regular expression: %s\n"), namelist[i]);
148                         exit (1);
149                 }
150         }
151         return reglist;
152 }
153
154 #ifdef WITH_SELINUX
155 static int
156 kill_all(int signal, int names, char **namelist, struct passwd *pwent, 
157                                         regex_t *scontext )
158 #else  /*WITH_SELINUX*/
159 static int
160 kill_all (int signal, int names, char **namelist, struct passwd *pwent)
161 #endif /*WITH_SELINUX*/
162 {
163   DIR *dir;
164   struct dirent *de;
165   FILE *file;
166   struct stat st, sts[MAX_NAMES];
167   int *name_len = NULL;
168   char *path, comm[COMM_LEN];
169   char *command_buf;
170   char *command;
171   pid_t *pid_table, pid, self, *pid_killed;
172   pid_t *pgids;
173   int i, j, okay, length, got_long, error;
174   int pids, max_pids, pids_killed;
175   unsigned long found;
176   regex_t *reglist = NULL;;
177 #ifdef WITH_SELINUX
178   security_context_t lcontext=NULL;
179 #endif /*WITH_SELINUX*/
180
181   if (names && reg) 
182       reglist = build_regexp_list(names, namelist);
183   else if (names)
184    {
185       if (!(name_len = malloc (sizeof (int) * names)))
186         {
187           perror ("malloc");
188           exit (1);
189         }
190       for (i = 0; i < names; i++) 
191         {
192           if (!strchr (namelist[i], '/'))
193             {
194               sts[i].st_dev = 0;
195               name_len[i] = strlen (namelist[i]);
196             }
197           else if (stat (namelist[i], &sts[i]) < 0)
198             {
199               perror (namelist[i]);
200               exit (1);
201             }
202         }
203     } 
204   self = getpid ();
205   found = 0;
206   if (!(dir = opendir (PROC_BASE)))
207     {
208       perror (PROC_BASE);
209       exit (1);
210     }
211   max_pids = 256;
212   pid_table = malloc (max_pids * sizeof (pid_t));
213   if (!pid_table)
214     {
215       perror ("malloc");
216       exit (1);
217     }
218   pids = 0;
219   while ( (de = readdir (dir)) != NULL)
220     {
221       if (!(pid = (pid_t) atoi (de->d_name)) || pid == self)
222         continue;
223       if (pids == max_pids)
224         {
225           if (!(pid_table = realloc (pid_table, 2 * pids * sizeof (pid_t))))
226             {
227               perror ("realloc");
228               exit (1);
229             }
230           max_pids *= 2;
231         }
232       pid_table[pids++] = pid;
233     }
234   (void) closedir (dir);
235   pids_killed = 0;
236   pid_killed = malloc (max_pids * sizeof (pid_t));
237   if (!pid_killed)
238     {
239       perror ("malloc");
240       exit (1);
241     }
242   if (!process_group)
243     pgids = NULL;               /* silence gcc */
244   else
245     {
246       pgids = malloc (pids * sizeof (pid_t));
247       if (!pgids)
248         {
249           perror ("malloc");
250           exit (1);
251         }
252     }
253   for (i = 0; i < pids; i++)
254     {
255       pid_t id;
256       int found_name = -1;
257
258       /* match by UID */
259       if (pwent && match_process_uid(pid_table[i], pwent->pw_uid)==0)
260         continue;
261 #ifdef WITH_SELINUX
262       /* match by SELinux context */
263       if (scontext) 
264         {
265           if (getpidcon(pid_table[i], &lcontext) < 0)
266             continue;
267           if (regexec(scontext, lcontext, 0, NULL, 0) != 0) {
268             freecon(lcontext);
269             continue;
270           }
271           freecon(lcontext);
272         }
273 #endif /*WITH_SELINUX*/
274       /* load process name */
275       if (asprintf (&path, PROC_BASE "/%d/stat", pid_table[i]) < 0)
276         continue;
277       if (!(file = fopen (path, "r"))) 
278         {
279           free (path);
280           continue;
281         }
282       free (path);
283       okay = fscanf (file, "%*d (%15[^)]", comm) == 1;
284       (void) fclose (file);
285       if (!okay)
286         continue;
287       got_long = 0;
288       command = NULL;           /* make gcc happy */
289       length = strlen (comm);
290       if (length == COMM_LEN - 1)
291         {
292           if (asprintf (&path, PROC_BASE "/%d/cmdline", pid_table[i]) < 0)
293             continue;
294           if (!(file = fopen (path, "r"))) {
295             free (path);
296             continue;
297           }
298           free (path);
299           while (1) {
300             /* look for actual command so we skip over initial "sh" if any */
301             char *p;
302             int cmd_size = 128;
303             command_buf = (char *)malloc (cmd_size);
304             if (!command_buf)
305               exit (1);
306
307             /* 'cmdline' has arguments separated by nulls */
308             for (p=command_buf; ; p++) {
309               int c;
310               if (p == (command_buf + cmd_size)) 
311                 {
312                   int cur_size = cmd_size;
313                   cmd_size *= 2;
314                   command_buf = (char *)realloc(command_buf, cmd_size);
315                   if (!command_buf)
316                     exit (1);
317                   p = command_buf + cur_size;
318                 }
319               c = fgetc(file);
320               if (c == EOF || c == '\0') {
321                 *p = '\0';
322                 break;
323               } else {
324                 *p = c;
325               }
326             }
327             if (strlen(command_buf) == 0) {
328               okay = 0;
329               break;
330             }
331             p = strrchr(command_buf,'/');
332             p = p ? p+1 : command_buf;
333             if (strncmp(p, comm, COMM_LEN-1) == 0) {
334               okay = 1;
335               command = p;
336               break;
337             }
338           }
339           (void) fclose(file);
340           if (exact && !okay)
341             {
342               if (verbose)
343                 fprintf (stderr, _("skipping partial match %s(%d)\n"), comm,
344                          pid_table[i]);
345               continue;
346             }
347           got_long = okay;
348         }
349       /* mach by process name */
350       for (j = 0; j < names; j++)
351         {
352           if (reg)
353             {
354               if (regexec (&reglist[j], got_long ? command : comm, 0, NULL, 0) != 0)
355                       continue;
356             }
357           else /* non-regex */
358             {
359               if (!sts[j].st_dev)
360                 {
361                   if (length != COMM_LEN - 1 || name_len[j] < COMM_LEN - 1)
362                     {
363                       if (ignore_case == 1)
364                         {
365                           if (strcasecmp (namelist[j], comm))
366                              continue;
367                         }
368                       else
369                         {
370                           if (strcmp(namelist[j], comm))
371                              continue;
372                         }
373                     }
374                   else if (got_long ? strcmp (namelist[j], command) :
375                                       strncmp (namelist[j], comm, COMM_LEN - 1))
376                     continue;
377                 }
378               else
379                 {
380                   int ok = 1;
381
382                   if (asprintf (&path, PROC_BASE "/%d/exe", pid_table[i]) < 0)
383                     continue;
384
385                   if (stat (path, &st) < 0) 
386                       ok = 0;
387
388                   else if (sts[j].st_dev != st.st_dev ||
389                            sts[j].st_ino != st.st_ino)
390                     {
391                       /* maybe the binary has been modified and std[j].st_ino
392                        * is not reliable anymore. We need to compare paths.
393                        */
394                       char linkbuf[PATH_MAX];
395
396                       if (readlink(path, linkbuf, sizeof(linkbuf)) <= 0 ||
397                                           strcmp(namelist[j], linkbuf))
398                         ok = 0;
399                     }
400
401                   free(path);
402                   if (!ok)
403                     continue;
404                 }
405             } /* non-regex */
406           found_name = j;
407           break;
408         }  
409         
410         if (names && found_name==-1)
411           continue;  /* match by process name faild */
412         
413         /* check for process group */
414         if (!process_group)
415           id = pid_table[i];
416         else
417           {
418             int j;
419
420             id = getpgid (pid_table[i]);
421             pgids[i] = id;
422             if (id < 0)
423               {
424                 fprintf (stderr, "getpgid(%d): %s\n", pid_table[i],
425                    strerror (errno));
426               }
427             for (j = 0; j < i; j++)
428               if (pgids[j] == id)
429                 break;
430             if (j < i)
431               continue;
432           }     
433         if (interactive && !ask (comm, id, signal))
434           continue;
435         if (pidof)
436           {
437             if (found)
438                putchar (' ');
439             printf ("%d", id);
440             found |= 1 << (found_name >= 0 ? found_name : 0);
441           }
442         else if (kill (process_group ? -id : id, signal) >= 0)
443           {
444             if (verbose)
445               fprintf (stderr, _("Killed %s(%s%d) with signal %d\n"), got_long ? command :
446                          comm, process_group ? "pgid " : "", id, signal);
447             if (found_name >= 0)
448                     /* mark item of namelist */
449                     found |= 1 << found_name;
450             pid_killed[pids_killed++] = id;
451           }
452         else if (errno != ESRCH || interactive)
453           fprintf (stderr, "%s(%d): %s\n", got_long ? command :
454                 comm, id, strerror (errno));
455     }
456   if (!quiet && !pidof)
457     for (i = 0; i < names; i++)
458       if (!(found & (1 << i)))
459         fprintf (stderr, _("%s: no process killed\n"), namelist[i]);
460   if (pidof)
461     putchar ('\n');
462   if (names)
463     /* killall returns a zero return code if at least one process has 
464      * been killed for each listed command. */
465     error = found == ((1 << (names - 1)) | ((1 << (names - 1)) - 1)) ? 0 : 1;
466   else
467     /* in nameless mode killall returns a zero return code if at least 
468      * one process has killed */
469     error = pids_killed ? 0 : 1;
470   /*
471    * We scan all (supposedly) killed processes every second to detect dead
472    * processes as soon as possible in order to limit problems of race with
473    * PID re-use.
474    */
475   while (pids_killed && wait_until_dead)
476     {
477       for (i = 0; i < pids_killed;)
478         {
479           if (kill (process_group ? -pid_killed[i] : pid_killed[i], 0) < 0 &&
480               errno == ESRCH)
481             {
482               pid_killed[i] = pid_killed[--pids_killed];
483               continue;
484             }
485           i++;
486         }
487       sleep (1);                /* wait a bit longer */
488     }
489   return error;
490 }
491
492
493 static void
494 usage_pidof (void)
495 {
496   fprintf (stderr, _(
497     "Usage: pidof [ -eg ] NAME...\n"
498     "       pidof -V\n\n"
499     "    -e      require exact match for very long names;\n"
500     "            skip if the command line is unavailable\n"
501     "    -g      show process group ID instead of process ID\n"
502     "    -V      display version information\n\n"));
503 }
504
505
506 static void
507 usage_killall (void)
508 {
509 #ifdef WITH_SELINUX
510    fprintf(stderr, _(
511      "Usage: killall [-Z CONTEXT] [-u USER] [ -eIgiqrvw ] [ -SIGNAL ] NAME...\n"));
512 #else  /*WITH_SELINUX*/
513   fprintf(stderr, _(
514     "Usage: killall [OPTION]... [--] NAME...\n"));
515 #endif /*WITH_SELINUX*/
516   fprintf(stderr, _(
517     "       killall -l, --list\n"
518     "       killall -V, --version\n\n"
519     "  -e,--exact          require exact match for very long names\n"
520     "  -I,--ignore-case    case insensitive process name match\n"
521     "  -g,--process-group  kill process group instead of process\n"
522     "  -i,--interactive    ask for confirmation before killing\n"
523     "  -l,--list           list all known signal names\n"
524     "  -q,--quiet          don't print complaints\n"
525     "  -r,--regexp         interpret NAME as an extended regular expression\n"
526     "  -s,--signal SIGNAL  send this signal instead of SIGTERM\n"
527     "  -u,--user USER      kill only process(es) running as USER\n"
528     "  -v,--verbose        report if the signal was successfully sent\n"
529     "  -V,--version        display version information\n"
530     "  -w,--wait           wait for processes to die\n"));
531 #ifdef WITH_SELINUX
532   fprintf(stderr, _(
533     "  -Z,--context REGEXP kill only process(es) having context\n"
534     "                      (must precede other arguments)\n"));
535 #endif /*WITH_SELINUX*/
536   fputc('\n', stderr);
537 }
538
539
540 static void
541 usage (void)
542 {
543   if (pidof)
544     usage_pidof ();
545   else
546     usage_killall ();
547   exit (1);
548 }
549
550 void print_version()
551 {
552   fprintf(stderr, "%s (PSmisc) %s\n", pidof ? "pidof" : "killall", VERSION);
553   fprintf(stderr, _(
554     "Copyright (C) 1993-2005 Werner Almesberger and Craig Small\n\n"));
555   fprintf(stderr, _(
556     "PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
557     "This is free software, and you are welcome to redistribute it under\n"
558     "the terms of the GNU General Public License.\n"
559     "For more information about these matters, see the files named COPYING.\n"));
560 }
561
562 int
563 main (int argc, char **argv)
564 {
565   char *name;
566   int sig_num;
567   int optc;
568   int myoptind;
569   struct passwd *pwent = NULL;
570   struct stat isproc;
571   
572   //int optsig = 0;
573
574   struct option options[] = {
575     {"exact", 0, NULL, 'e'},
576     {"ignore-case", 0, NULL, 'I'},
577     {"process-group", 0, NULL, 'g'},
578     {"interactive", 0, NULL, 'i'},
579     {"list-signals", 0, NULL, 'l'},
580     {"quiet", 0, NULL, 'q'},
581     {"regexp", 0, NULL, 'r'},
582     {"signal", 1, NULL, 's'},
583     {"user", 1, NULL, 'u'},
584     {"verbose", 0, NULL, 'v'},
585     {"wait", 0, NULL, 'w'},
586 #ifdef WITH_SELINUX
587     {"context", 1, NULL, 'Z'},
588 #endif /*WITH_SELINUX*/
589     {"version", 0, NULL, 'V'},
590     {0,0,0,0 }};
591
592   /* Setup the i18n */
593 #ifdef ENABLE_NLS
594   setlocale(LC_ALL, "");
595   bindtextdomain(PACKAGE, LOCALEDIR);
596   textdomain(PACKAGE);
597 #endif
598 #ifdef WITH_SELINUX
599   security_context_t scontext = NULL;
600   regex_t scontext_reg;
601
602   if ( argc < 2 ) usage(); /* do the obvious thing... */
603 #endif /*WITH_SELINUX*/
604
605   name = strrchr (*argv, '/');
606   if (name)
607     name++;
608   else
609     name = *argv;
610   pidof = strcmp (name, "killall");
611   sig_num = SIGTERM;
612
613
614   opterr = 0;
615 #ifdef WITH_SELINUX
616   while ( (optc = getopt_long_only(argc,argv,"egilqrs:u:vwZ:VI",options,NULL)) != EOF) {
617 #else
618   while ( (optc = getopt_long_only(argc,argv,"egilqrs:u:vwVI",options,NULL)) != EOF) {
619 #endif
620     switch (optc) {
621       case 'e':
622         exact = 1;
623         break;
624       case 'g':
625         process_group = 1;
626         break;
627       case 'i':
628         if (pidof)
629           usage();
630         interactive = 1;
631         break;
632       case 'l':
633         if (pidof)
634           usage();
635         list_signals();
636         return 0;
637         break;
638       case 'q':
639         if (pidof)
640           usage();
641         quiet = 1;
642         break;
643       case 'r':
644         if (pidof)
645           usage();
646         reg = 1;
647         break;
648       case 's':
649         sig_num = get_signal (optarg, "killall");
650         break;
651       case 'u':
652         if (pidof)
653           usage();
654         if (!(pwent = getpwnam(optarg)))
655           {
656             fprintf (stderr, _("Cannot find user %s\n"), optarg);
657             exit (1);
658           }
659         break;
660       case 'v':
661         if (pidof)
662           usage();
663         verbose = 1;
664         break;
665       case 'w':
666         if (pidof)
667           usage();
668         wait_until_dead = 1;
669         break;
670       case 'I':
671         ignore_case = 1;
672         break;
673       case 'V':
674         print_version();
675         return 0;
676         break;
677 #ifdef WITH_SELINUX
678       case 'Z': 
679         if (is_selinux_enabled()>0) {
680           scontext=optarg;
681           if (regcomp(&scontext_reg, scontext, REG_EXTENDED|REG_NOSUB) != 0) {
682             fprintf(stderr, _("Bad regular expression: %s\n"), scontext);
683             exit (1);
684           }
685         } else 
686            fprintf(stderr, "Warning: -Z (--context) ignored. Requires an SELinux enabled kernel\n");
687         break;
688 #endif /*WITH_SELINUX*/
689       case '?':
690         /* Signal names are in uppercase, so check to see if the argv
691          * is upper case */
692         if (argv[optind-1][1] >= 'A' && argv[optind-1][1] <= 'Z') {
693               sig_num = get_signal (argv[optind-1]+1, "killall");
694         } else {
695           /* Might also be a -## signal too */
696           if (argv[optind-1][1] >= '0' && argv[optind-1][1] <= '9') {
697             sig_num = atoi(argv[optind-1]+1);
698           } else {
699             usage();
700           }
701         }
702         break;
703     }
704   }
705   myoptind = optind;
706 #ifdef WITH_SELINUX
707   if ((argc - myoptind < 1) && pwent==NULL && scontext==NULL) 
708 #else
709   if ((argc - myoptind < 1) && pwent==NULL)       
710 #endif
711     usage();
712
713   if (argc - myoptind > MAX_NAMES + 1)
714     {
715       fprintf (stderr, _("Maximum number of names is %d\n"), MAX_NAMES);
716       exit (1);
717     }
718   if (stat("/proc/self/stat", &isproc)==-1)
719     {
720       fprintf (stderr, _("%s is empty (not mounted ?)\n"), PROC_BASE);
721       exit (1);
722     }
723   argv = argv + myoptind;
724   /*printf("sending signal %d to procs\n", sig_num);*/
725 #ifdef WITH_SELINUX
726   return kill_all(sig_num,argc - myoptind, argv, pwent, 
727                                 scontext ? &scontext_reg : NULL);
728 #else  /*WITH_SELINUX*/
729   return kill_all(sig_num,argc - myoptind, argv, pwent);
730 #endif /*WITH_SELINUX*/
731 }