home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / A / PS / PROCPS-0.000 / PROCPS-0 / procps-0.97 / fuser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-16  |  8.3 KB  |  335 lines

  1. /* fuser.c  -  identify processes using files. Written by Werner Almesberger */
  2.  
  3.  
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <ctype.h>
  8. #include <unistd.h>
  9. #include <dirent.h>
  10. #include <pwd.h>
  11. #include <signal.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <linux/sched.h>
  15. #include "signals.h"
  16.  
  17.  
  18. #define PROC_BASE  "/proc"
  19. #define UID_UNKNOWN -1
  20. #define NAME_FIELD 20 /* space reserved for file name */
  21.  
  22. #define REF_FILE   1    /* an open file */
  23. #define REF_ROOT   2    /* current root */
  24. #define REF_CWD    4    /* current directory */
  25. #define REF_EXE    8    /* executable */
  26. #define REF_MMAP  16    /* mmap'ed file or library */
  27.  
  28. #define FLAG_KILL  1    /* kill process */
  29. #define FLAG_UID   2    /* show uid */
  30. #define FLAG_VERB  4    /* show verbose output */
  31. #define FLAG_DEV   8    /* show all processes using this device */
  32.  
  33. #define COMM_LEN sizeof(dummy.comm)
  34.  
  35.  
  36. typedef struct proc_dsc {
  37.     pid_t pid;
  38.     int ref_set;
  39.     int uid; /* must also accept UID_UNKNOWN */
  40.     struct proc_dsc *next;
  41. } PROC_DSC;
  42.  
  43. typedef struct file_dsc {
  44.     char *name;
  45.     dev_t dev;
  46.     ino_t ino;
  47.     int flags,sig_num;
  48.     PROC_DSC *procs;
  49.     struct file_dsc *next;
  50. } FILE_DSC;
  51.  
  52.  
  53. static FILE_DSC *files = NULL;
  54. static struct task_struct dummy;
  55. static int all = 0,found_proc = 0;
  56.  
  57.  
  58. static void check_file(char *path,pid_t pid,int type)
  59. {
  60.     struct stat st1,st2;
  61.     FILE_DSC *file;
  62.     PROC_DSC **proc,*this;
  63.  
  64.     if (stat(path,&st1) < 0) return;
  65.     for (file = files; file; file = file->next)
  66.     if ((st1.st_ino == file->ino || (file->flags & FLAG_DEV)) &&
  67.       st1.st_dev == file->dev) {
  68.         for (proc = &file->procs; *proc; proc = &(*proc)->next)
  69.         if ((*proc)->pid >= pid) break;
  70.         if ((*proc)->pid == pid) this = *proc;
  71.         else {
  72.         if (!(this = malloc(sizeof(PROC_DSC)))) {
  73.             perror("malloc");
  74.             exit(1);
  75.         }
  76.         this->pid = pid;
  77.         this->ref_set = 0;
  78.         this->uid = UID_UNKNOWN;
  79.         this->next = *proc;
  80.         *proc = this;
  81.         found_proc = 1;
  82.         }
  83.         this->ref_set |= type;
  84.         if ((file->flags & (FLAG_UID | FLAG_VERB)) && this->uid ==
  85.           UID_UNKNOWN && lstat(path,&st2) >= 0) this->uid = st2.st_uid;
  86.     }
  87. }
  88.  
  89.  
  90. static void check_dir(char *rel,pid_t pid,int type)
  91. {
  92.     DIR *dir;
  93.     struct dirent *de;
  94.     char path[PATH_MAX+1];
  95.  
  96.     if (!(dir = opendir(rel))) return;
  97.     while (de = readdir(dir))
  98.     if (strcmp(de->d_name,".") && strcmp(de->d_name,"..")) {
  99.         sprintf(path,"%s/%s",rel,de->d_name);
  100.         check_file(path,pid,type);
  101.     }
  102.     (void) closedir(dir);
  103. }
  104.  
  105.  
  106. static void scan_proc(void)
  107. {
  108.     DIR *dir;
  109.     struct dirent *de;
  110.     char path[PATH_MAX+1];
  111.     pid_t pid;
  112.     int empty;
  113.  
  114.     if (!(dir = opendir(PROC_BASE))) {
  115.     perror(PROC_BASE);
  116.     exit(1);
  117.     }
  118.     empty = 1;
  119.     while (de = readdir(dir))
  120.     if (pid = atoi(de->d_name)) {
  121.         empty = 0;
  122.         sprintf(path,"%s/%d",PROC_BASE,pid);
  123.         if (chdir(path) >= 0) {
  124.         check_file("root",pid,REF_ROOT);
  125.         check_file("cwd",pid,REF_CWD);
  126.         check_file("exe",pid,REF_EXE);
  127.         check_dir("lib",pid,REF_MMAP);
  128.         check_dir("mmap",pid,REF_MMAP);
  129.         check_dir("fd",pid,REF_FILE);
  130.         }
  131.     }
  132.     (void) closedir(dir);
  133.     if (empty) {
  134.     fprintf(stderr,PROC_BASE " is empty (not mounted ?)\n");
  135.     exit(1);
  136.     }
  137. }
  138.  
  139.  
  140. static void show_files(void)
  141. {
  142.     FILE_DSC *file;
  143.     PROC_DSC *proc;
  144.     FILE *f;
  145.     struct passwd *pw;
  146.     char *name,*scan;
  147.     char tmp[10],path[PATH_MAX+1],comm[COMM_LEN+1];
  148.     int length,header,first,dummy;
  149.     pid_t self;
  150.  
  151.     self = getpid();
  152.     header = 1;
  153.     for (file = files; file; file = file->next)
  154.     if (file->procs || all) {
  155.         length = 0;
  156.         for (scan = file->name; *scan; scan++)
  157.         if (*scan == '\\') {
  158.             printf("\\\\");
  159.             length += 2;
  160.         }
  161.         else if (*scan > ' ' && *scan <= '~') {
  162.             putchar(*scan);
  163.             length++;
  164.             }
  165.             else {
  166.             printf("\\%03o",*scan);
  167.             length += 4;
  168.             }
  169.         putchar(':');
  170.         while (length < NAME_FIELD) {
  171.         putchar(' ');
  172.         length++;
  173.         }
  174.         first = 1;
  175.         for (proc = file->procs; proc; proc = proc->next)
  176.         if (!(file->flags & FLAG_VERB)) {
  177.             if (proc->ref_set & REF_FILE) printf("%6d",proc->pid);
  178.             if (proc->ref_set & REF_ROOT) printf("%6dr",proc->pid);
  179.             if (proc->ref_set & REF_CWD) printf("%6dc",proc->pid);
  180.             if (proc->ref_set & REF_EXE) printf("%6de",proc->pid);
  181.             else if (proc->ref_set & REF_MMAP) printf("%6dm",proc->pid);
  182.             if (file->flags & FLAG_UID && proc->uid != UID_UNKNOWN)
  183.             if (pw = getpwuid(proc->uid))
  184.                 printf("(%s)",pw->pw_name);
  185.             else printf("(%d)",proc->uid);
  186.         }
  187.         else {
  188.             if (header) {
  189.             if (length > NAME_FIELD)
  190.                 printf("\n%*s",NAME_FIELD+1,"");
  191.             printf(" USER       PID ACCESS COMMAND\n");
  192.             header = first = 0;
  193.             }
  194.             sprintf(path,PROC_BASE "/%d/stat",proc->pid);
  195.             strcpy(comm,"???");
  196.             if (f = fopen(path,"r")) {
  197.             (void) fscanf(f,"%d (%[^)]",&dummy,comm);
  198.             (void) fclose(f);
  199.             }
  200.             if (proc->uid == UID_UNKNOWN) name = "???";
  201.             else if (pw = getpwuid(proc->uid)) name = pw->pw_name;
  202.             else sprintf(name = tmp,"%d",proc->uid);
  203.             if (!first) printf("%*s",NAME_FIELD+1,"");
  204.             else if (length > NAME_FIELD)
  205.                 printf("\n%*s",NAME_FIELD+1,"");
  206.             first = 0;
  207.             printf(" %-8s %5d %c%c%c%c%c  ",name,proc->pid,
  208.               proc->ref_set & REF_FILE ? 'f' : '.',proc->ref_set &
  209.               REF_ROOT ? 'r' : '.',proc->ref_set & REF_CWD ? 'c' : '.',
  210.               proc->ref_set & REF_EXE ? 'e' : '.',(proc->ref_set &
  211.               REF_MMAP) && !(proc->ref_set & REF_EXE) ? 'm' : '.');
  212.             for (scan = comm; *scan; scan++)
  213.             if (*scan == '\\') printf("\\\\");
  214.             else if (*scan > ' ' && *scan <= '~') putchar(*scan);
  215.                 else printf("\\%03o",(unsigned char) *scan);
  216.             putchar('\n');
  217.         }
  218.         if (!(file->flags & FLAG_VERB) || first) putchar('\n');
  219.         if (file->flags & FLAG_KILL)
  220.         for (proc = file->procs; proc; proc = proc->next)
  221.             if (proc->pid != self)
  222.             if (kill(proc->pid,file->sig_num) < 0) {
  223.                 sprintf(tmp,"kill %d",proc->pid);
  224.                 perror(tmp);
  225.             }
  226.     }
  227. }
  228.  
  229.  
  230. static void usage(void)
  231. {
  232.     fprintf(stderr,"usage: fuser [ -a | -q ] [ -signal ] [ -kmuv ] filename "
  233.       "... [ - ] [ -signal ]\n%13s[ -kmuv ] filename ...\n","");
  234.     fprintf(stderr,"       fuser -l\n\n");
  235.     fprintf(stderr,"    -a      display unused files too\n");
  236.     fprintf(stderr,"    -k      kill processes accessing that file\n");
  237.     fprintf(stderr,"    -l      list signal names\n");
  238.     fprintf(stderr,"    -m      mounted FS\n");
  239.     fprintf(stderr,"    -s      silent operation\n");
  240.     fprintf(stderr,"    -signal send signal instead of SIGKILL\n");
  241.     fprintf(stderr,"    -u      display user ids\n");
  242.     fprintf(stderr,"    -v      verbose output\n");
  243.     fprintf(stderr,"    -       reset options\n\n");
  244.     exit(1);
  245. }
  246.  
  247.  
  248. int main(int argc,char **argv)
  249. {
  250.     struct stat st;
  251.     FILE_DSC *new,*last;
  252.     char path[PATH_MAX+1];
  253.     int flags,silent,sig_number,no_files;
  254.  
  255.     flags = silent = 0;
  256.     sig_number = SIGKILL;
  257.     no_files = 1;
  258.     last = NULL;
  259.     if (argc < 2) usage();
  260.     if (argc == 2 && !strcmp(argv[1],"-l")) {
  261.     list_signals();
  262.     return 0;
  263.     }
  264.     while (--argc) {
  265.     argv++;
  266.     if (**argv == '-')
  267.         if (!argv[0][1]) {
  268.         flags = 0;
  269.         sig_number = SIGKILL;
  270.         }
  271.         else while (*++*argv)
  272.             switch (**argv) {
  273.             case 'a':
  274.                 all = 1;
  275.                 break;
  276.             case 'k':
  277.                 flags |= FLAG_KILL;
  278.                 break;
  279.             case 'm':
  280.                 flags |= FLAG_DEV;
  281.                 break;
  282.             case 's':
  283.                 silent = 1;
  284.                 break;
  285.             case 'u':
  286.                 flags |= FLAG_UID;
  287.                 break;
  288.             case 'v':
  289.                 flags |= FLAG_VERB;
  290.                 break;
  291.             default:
  292.                 if (isupper(**argv) || isdigit(**argv)) {
  293.                 sig_number = get_signal(*argv,"fuser");
  294.                 argv[0][1] = 0;
  295.                 break;
  296.                 }
  297.                 usage();
  298.             }
  299.     else {
  300.         no_files = 0;
  301.         if (stat(*argv,&st) < 0) {
  302.         perror(*argv);
  303.         continue;
  304.         }
  305.         if (!(new = malloc(sizeof(FILE_DSC)))) {
  306.         perror("malloc");
  307.         exit(1);
  308.         }
  309.         if (!(new->name = strdup(*argv))) {
  310.         perror("strdup");
  311.         exit(1);
  312.         }
  313.         new->flags = flags;
  314.         new->sig_num = sig_number;
  315.         new->procs = NULL;
  316.         new->next = NULL;
  317.         new->dev = st.st_dev;
  318.         new->ino = st.st_ino;
  319.         if (flags & FLAG_DEV)
  320.         if (S_ISBLK(st.st_mode)) new->dev = st.st_rdev;
  321.         else if (S_ISDIR(st.st_mode)) {
  322.             sprintf(path,"%s/.",*argv);
  323.             if (stat(*argv,&st) >= 0) new->dev = st.st_dev;
  324.             }
  325.         if (last) last->next = new;
  326.         else files = new;
  327.         last = new;
  328.     }
  329.     }
  330.     if (no_files || (all && silent)) usage();
  331.     scan_proc();
  332.     if (!silent) show_files();
  333.     return found_proc ? 0 : 1;
  334. }
  335.