home *** CD-ROM | disk | FTP | other *** search
- /* fuser.c - identify processes using files. Written by Werner Almesberger */
-
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <dirent.h>
- #include <pwd.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <linux/sched.h>
- #include "signals.h"
-
-
- #define PROC_BASE "/proc"
- #define UID_UNKNOWN -1
- #define NAME_FIELD 20 /* space reserved for file name */
-
- #define REF_FILE 1 /* an open file */
- #define REF_ROOT 2 /* current root */
- #define REF_CWD 4 /* current directory */
- #define REF_EXE 8 /* executable */
- #define REF_MMAP 16 /* mmap'ed file or library */
-
- #define FLAG_KILL 1 /* kill process */
- #define FLAG_UID 2 /* show uid */
- #define FLAG_VERB 4 /* show verbose output */
- #define FLAG_DEV 8 /* show all processes using this device */
-
- #define COMM_LEN sizeof(dummy.comm)
-
-
- typedef struct proc_dsc {
- pid_t pid;
- int ref_set;
- int uid; /* must also accept UID_UNKNOWN */
- struct proc_dsc *next;
- } PROC_DSC;
-
- typedef struct file_dsc {
- char *name;
- dev_t dev;
- ino_t ino;
- int flags,sig_num;
- PROC_DSC *procs;
- struct file_dsc *next;
- } FILE_DSC;
-
-
- static FILE_DSC *files = NULL;
- static struct task_struct dummy;
- static int all = 0,found_proc = 0;
-
-
- static void check_file(char *path,pid_t pid,int type)
- {
- struct stat st1,st2;
- FILE_DSC *file;
- PROC_DSC **proc,*this;
-
- if (stat(path,&st1) < 0) return;
- for (file = files; file; file = file->next)
- if ((st1.st_ino == file->ino || (file->flags & FLAG_DEV)) &&
- st1.st_dev == file->dev) {
- for (proc = &file->procs; *proc; proc = &(*proc)->next)
- if ((*proc)->pid >= pid) break;
- if ((*proc)->pid == pid) this = *proc;
- else {
- if (!(this = malloc(sizeof(PROC_DSC)))) {
- perror("malloc");
- exit(1);
- }
- this->pid = pid;
- this->ref_set = 0;
- this->uid = UID_UNKNOWN;
- this->next = *proc;
- *proc = this;
- found_proc = 1;
- }
- this->ref_set |= type;
- if ((file->flags & (FLAG_UID | FLAG_VERB)) && this->uid ==
- UID_UNKNOWN && lstat(path,&st2) >= 0) this->uid = st2.st_uid;
- }
- }
-
-
- static void check_dir(char *rel,pid_t pid,int type)
- {
- DIR *dir;
- struct dirent *de;
- char path[PATH_MAX+1];
-
- if (!(dir = opendir(rel))) return;
- while (de = readdir(dir))
- if (strcmp(de->d_name,".") && strcmp(de->d_name,"..")) {
- sprintf(path,"%s/%s",rel,de->d_name);
- check_file(path,pid,type);
- }
- (void) closedir(dir);
- }
-
-
- static void scan_proc(void)
- {
- DIR *dir;
- struct dirent *de;
- char path[PATH_MAX+1];
- pid_t pid;
- int empty;
-
- if (!(dir = opendir(PROC_BASE))) {
- perror(PROC_BASE);
- exit(1);
- }
- empty = 1;
- while (de = readdir(dir))
- if (pid = atoi(de->d_name)) {
- empty = 0;
- sprintf(path,"%s/%d",PROC_BASE,pid);
- if (chdir(path) >= 0) {
- check_file("root",pid,REF_ROOT);
- check_file("cwd",pid,REF_CWD);
- check_file("exe",pid,REF_EXE);
- check_dir("lib",pid,REF_MMAP);
- check_dir("mmap",pid,REF_MMAP);
- check_dir("fd",pid,REF_FILE);
- }
- }
- (void) closedir(dir);
- if (empty) {
- fprintf(stderr,PROC_BASE " is empty (not mounted ?)\n");
- exit(1);
- }
- }
-
-
- static void show_files(void)
- {
- FILE_DSC *file;
- PROC_DSC *proc;
- FILE *f;
- struct passwd *pw;
- char *name,*scan;
- char tmp[10],path[PATH_MAX+1],comm[COMM_LEN+1];
- int length,header,first,dummy;
- pid_t self;
-
- self = getpid();
- header = 1;
- for (file = files; file; file = file->next)
- if (file->procs || all) {
- length = 0;
- for (scan = file->name; *scan; scan++)
- if (*scan == '\\') {
- printf("\\\\");
- length += 2;
- }
- else if (*scan > ' ' && *scan <= '~') {
- putchar(*scan);
- length++;
- }
- else {
- printf("\\%03o",*scan);
- length += 4;
- }
- putchar(':');
- while (length < NAME_FIELD) {
- putchar(' ');
- length++;
- }
- first = 1;
- for (proc = file->procs; proc; proc = proc->next)
- if (!(file->flags & FLAG_VERB)) {
- if (proc->ref_set & REF_FILE) printf("%6d",proc->pid);
- if (proc->ref_set & REF_ROOT) printf("%6dr",proc->pid);
- if (proc->ref_set & REF_CWD) printf("%6dc",proc->pid);
- if (proc->ref_set & REF_EXE) printf("%6de",proc->pid);
- else if (proc->ref_set & REF_MMAP) printf("%6dm",proc->pid);
- if (file->flags & FLAG_UID && proc->uid != UID_UNKNOWN)
- if (pw = getpwuid(proc->uid))
- printf("(%s)",pw->pw_name);
- else printf("(%d)",proc->uid);
- }
- else {
- if (header) {
- if (length > NAME_FIELD)
- printf("\n%*s",NAME_FIELD+1,"");
- printf(" USER PID ACCESS COMMAND\n");
- header = first = 0;
- }
- sprintf(path,PROC_BASE "/%d/stat",proc->pid);
- strcpy(comm,"???");
- if (f = fopen(path,"r")) {
- (void) fscanf(f,"%d (%[^)]",&dummy,comm);
- (void) fclose(f);
- }
- if (proc->uid == UID_UNKNOWN) name = "???";
- else if (pw = getpwuid(proc->uid)) name = pw->pw_name;
- else sprintf(name = tmp,"%d",proc->uid);
- if (!first) printf("%*s",NAME_FIELD+1,"");
- else if (length > NAME_FIELD)
- printf("\n%*s",NAME_FIELD+1,"");
- first = 0;
- printf(" %-8s %5d %c%c%c%c%c ",name,proc->pid,
- proc->ref_set & REF_FILE ? 'f' : '.',proc->ref_set &
- REF_ROOT ? 'r' : '.',proc->ref_set & REF_CWD ? 'c' : '.',
- proc->ref_set & REF_EXE ? 'e' : '.',(proc->ref_set &
- REF_MMAP) && !(proc->ref_set & REF_EXE) ? 'm' : '.');
- for (scan = comm; *scan; scan++)
- if (*scan == '\\') printf("\\\\");
- else if (*scan > ' ' && *scan <= '~') putchar(*scan);
- else printf("\\%03o",(unsigned char) *scan);
- putchar('\n');
- }
- if (!(file->flags & FLAG_VERB) || first) putchar('\n');
- if (file->flags & FLAG_KILL)
- for (proc = file->procs; proc; proc = proc->next)
- if (proc->pid != self)
- if (kill(proc->pid,file->sig_num) < 0) {
- sprintf(tmp,"kill %d",proc->pid);
- perror(tmp);
- }
- }
- }
-
-
- static void usage(void)
- {
- fprintf(stderr,"usage: fuser [ -a | -q ] [ -signal ] [ -kmuv ] filename "
- "... [ - ] [ -signal ]\n%13s[ -kmuv ] filename ...\n","");
- fprintf(stderr," fuser -l\n\n");
- fprintf(stderr," -a display unused files too\n");
- fprintf(stderr," -k kill processes accessing that file\n");
- fprintf(stderr," -l list signal names\n");
- fprintf(stderr," -m mounted FS\n");
- fprintf(stderr," -s silent operation\n");
- fprintf(stderr," -signal send signal instead of SIGKILL\n");
- fprintf(stderr," -u display user ids\n");
- fprintf(stderr," -v verbose output\n");
- fprintf(stderr," - reset options\n\n");
- exit(1);
- }
-
-
- int main(int argc,char **argv)
- {
- struct stat st;
- FILE_DSC *new,*last;
- char path[PATH_MAX+1];
- int flags,silent,sig_number,no_files;
-
- flags = silent = 0;
- sig_number = SIGKILL;
- no_files = 1;
- last = NULL;
- if (argc < 2) usage();
- if (argc == 2 && !strcmp(argv[1],"-l")) {
- list_signals();
- return 0;
- }
- while (--argc) {
- argv++;
- if (**argv == '-')
- if (!argv[0][1]) {
- flags = 0;
- sig_number = SIGKILL;
- }
- else while (*++*argv)
- switch (**argv) {
- case 'a':
- all = 1;
- break;
- case 'k':
- flags |= FLAG_KILL;
- break;
- case 'm':
- flags |= FLAG_DEV;
- break;
- case 's':
- silent = 1;
- break;
- case 'u':
- flags |= FLAG_UID;
- break;
- case 'v':
- flags |= FLAG_VERB;
- break;
- default:
- if (isupper(**argv) || isdigit(**argv)) {
- sig_number = get_signal(*argv,"fuser");
- argv[0][1] = 0;
- break;
- }
- usage();
- }
- else {
- no_files = 0;
- if (stat(*argv,&st) < 0) {
- perror(*argv);
- continue;
- }
- if (!(new = malloc(sizeof(FILE_DSC)))) {
- perror("malloc");
- exit(1);
- }
- if (!(new->name = strdup(*argv))) {
- perror("strdup");
- exit(1);
- }
- new->flags = flags;
- new->sig_num = sig_number;
- new->procs = NULL;
- new->next = NULL;
- new->dev = st.st_dev;
- new->ino = st.st_ino;
- if (flags & FLAG_DEV)
- if (S_ISBLK(st.st_mode)) new->dev = st.st_rdev;
- else if (S_ISDIR(st.st_mode)) {
- sprintf(path,"%s/.",*argv);
- if (stat(*argv,&st) >= 0) new->dev = st.st_dev;
- }
- if (last) last->next = new;
- else files = new;
- last = new;
- }
- }
- if (no_files || (all && silent)) usage();
- scan_proc();
- if (!silent) show_files();
- return found_proc ? 0 : 1;
- }
-