/* @(#)fuser.c 1.4 */ #include <a.out.h> #include <fcntl.h> #include <pwd.h> #include <stdio.h> #include <sys/param.h> #include <sys/types.h> #include <sys/dir.h> #include <sys/file.h> #include <sys/inode.h> #ifdef u3b #include <sys/page.h> #include <sys/istk.h> #include <sys/seg.h> #endif #include <sys/proc.h> #include <sys/signal.h> #include <sys/stat.h> #include <sys/sysmacros.h> #include <sys/user.h> #include <sys/var.h> /* definition of memory page size */ #if pdp11 || vax #define PSIZE 512 #define PSHIFT 9 #endif #ifdef u3b #define PSIZE 2048 #define PSHIFT 11 #endif /* symbol names */ #if pdp11 || vax #define V_STR "_v" #define PROC_STR "_proc" #define FILE_STR "_file" #define INODE_STR "_inode" #define SWPLO_STR "_swplo" #define SBRPTE_STR "_sbrpte" #endif #ifdef u3b #define V_STR "v" #define PROC_STR "proc" #define FILE_STR "file" #define INODE_STR "inode" #define SWPLO_STR "swaplow" #endif #ifdef vax #define memf "/dev/kmem" #else #define memf "/dev/mem" #endif #define system "/unix" #define ieq( X, Y) ((X.i_dev == Y.i_dev) && (X.i_number == Y.i_number)) || \ ( ((X.i_mode & IFMT) == IFBLK) && (X.i_rdev == Y.i_dev) ) #define min( X, Y) ( (X < Y) ? X : Y ) #define valid_file(X) (file_adr <= (unsigned) X &&\ (unsigned) X < file_adr + v.v_file * sizeof (struct file)) #define valid_inode(X) (inode_adr <= (unsigned) X &&\ (unsigned) X < inode_adr + v.v_inode * sizeof (struct inode)) void exit(), perror(); copylval( nl_file, symbol, ptr) char *nl_file, *symbol; unsigned *ptr; { /* Copies the lvalue of the UNIX symbol "symbol" into * the variable pointed to by "ptr". The lvalue of * "symbol" is read from the name list file "nl_file". */ char *strncpy(); struct nlist nl[2]; strncpy( nl[0].n_name, symbol, 8); strncpy( nl[1].n_name, "", 8); nlist( nl_file, nl); *ptr = nl[0].n_value; } copyrval( nl_file, symbol, ptr, size, memdev) char *nl_file, *symbol, *ptr; int memdev, size; { /* Copies the rvalue of the UNIX symbol "symbol" into the structure * pointed to by "ptr". The rvalue is read from memory at the location * specified by the value of "symbol" in the name list file "nl_file". */ int mem; unsigned lval; copylval( nl_file, symbol, &lval); if ( memdev >= 0 ) mem = memdev; else if ( (mem = open( memf, O_RDONLY)) == -1 ) { perror( memf); exit( 1); } #ifdef vax lval &= 0x3fffffff; #endif rread( mem, (long) lval, ptr, size); if ( memdev != mem ) close( mem); } file_to_inode( file_adr, in, memdev) int memdev; struct inode *in; struct file *file_adr; { /* Takes a pointer to one of the system's file entries * and copies the inode to which it refers into the area * pointed to by "in". "file_adr" is a system pointer, usually * from the user area. */ int mem; struct file f; union /* used to convert pointers to numbers */ { char *ptr; unsigned addr; /* must be same length as char * */ } convert; convert.ptr = (char *) file_adr; #ifdef vax convert.addr &= 0x3fffffff; #endif if ( convert.addr == 0 ) return( -1); if ( memdev >= 0 ) mem = memdev; else if( (mem = open( memf, O_RDONLY)) == -1 ) { perror( memf); return( -1); } /* read the file table entry */ rread( mem, (long) convert.addr, (char *) &f, sizeof f); if ( memdev != mem ) close( mem); if ( f.f_flag ) return( read_inode( f.f_inode, in, memdev)); else return( -1); } main( argc, argv) int argc; char **argv; { int mem, file = 0, gun = 0, uname = 0; register i, j, k; struct inode ina, inb; struct proc p; struct user u; struct var v; unsigned proc_adr, file_adr, inode_adr; /* once only code */ /* open file to access memory */ if ( (mem = open( memf, O_RDONLY)) == -1) { fprintf( stderr, "%s: ", argv[0]); perror( memf); exit( 1); } /* get values of system variables and address of process table */ copyrval( system, V_STR, (char *) &v, sizeof v, mem); copylval( system, PROC_STR, &proc_adr); copylval( system, FILE_STR, &file_adr); copylval( system, INODE_STR, &inode_adr); #ifdef vax proc_adr &= 0x3fffffff; #endif if ( argc < 2 ) { fprintf( stderr, "Usage: %s [-ku] [file1 . . .]\n", argv[0]); exit( 1); } /* For each of the arguments in the command string */ for ( i = 1; i < argc; i++) { if ( argv[i][0] == '-' ) { /* options processing */ if ( file ) { gun = 0; uname = 0; } file = 0; for ( j = 1; argv[i][j] != '\0'; j++) switch ( argv[i][j]) { case 'k': ++gun; break; case 'u': ++uname; break; default: fprintf( stderr, "Illegal option %c ignored.\n", argv[i][j]); } continue; } else file = 1; /* First print its name on stderr (so the output can * be piped to kill) */ fprintf( stderr, "%s: ", argv[i]); /* then convert the path into an inode */ if ( path_to_inode( argv[i], &ina) == -1 ) continue; /* then for each process */ for ( j = 0; j < v.v_proc; j++) { /* read in the per-process info */ rread( mem, (long) (proc_adr + j * sizeof p), (char *) &p, sizeof p); if ( p.p_stat == 0 || p.p_stat == SZOMB ) continue; /* and the user area */ read_user( p, &u, mem); if ( valid_inode( u.u_cdir) && read_inode( u.u_cdir, &inb, mem) == 0 ) if ( ieq( ina, inb) ) { fprintf( stdout, " %7d", (int) p.p_pid); fflush(stdout); fprintf( stderr, "c"); if (uname) puname( (int) p.p_uid); if (gun) kill( (int) p.p_pid, 9); continue; } /* This code is only valid in transient cases and the inodes * (pointed to by u_pdir) are not cleared after their use. */ /* if ( valid_inode( u.u_pdir) && /* read_inode( u.u_pdir, &inb, mem) == 0 ) /* if ( ieq( ina, inb) ) /* { fprintf( stdout, " %7d", (int) p.p_pid); /* fflush(stdout); /* fprintf( stderr, "p"); /* if (uname) puname( (int) p.p_uid); /* if (gun) kill( (int) p.p_pid, 9); /* continue; /* } */ if ( valid_inode( u.u_rdir) && read_inode( u.u_rdir, &inb, mem) == 0 ) if ( ieq( ina, inb) ) { fprintf( stdout, " %7d", (int) p.p_pid); fflush(stdout); fprintf( stderr, "r"); if (uname) puname( (int) p.p_uid); if (gun) kill( (int) p.p_pid, 9); continue; } /* then, for each file */ for ( k = 0; k < NOFILE; k++) { /* check if it is the fs being checked */ if ( ! valid_file( u.u_ofile[k]) ) continue; if (file_to_inode( u.u_ofile[k], &inb, mem)) continue; if ( ieq( ina, inb) ) { fprintf(stdout, " %7d", (int) p.p_pid); fflush(stdout); if (uname) puname( (int) p.p_uid); if (gun) kill( (int) p.p_pid, 9); break; } } } fprintf( stderr, "\n"); } printf( "\n"); } path_to_inode( path, in) char *path; struct inode *in; { /* Converts a path to inode info by the stat system call */ struct stat s; if ( stat( path, &s) == -1 ) { perror( ""); return( -1); } in->i_mode = s.st_mode; in->i_dev = s.st_dev; in->i_number = s.st_ino; in->i_rdev = s.st_rdev; return( 0); } puname( uid) int uid; { struct passwd *getpwuid(), *p; p = getpwuid( uid); if ( p == NULL ) return; fprintf( stderr, "(%s)", p->pw_name); } read_inode( inode_adr, i, memdev) int memdev; struct inode *i, *inode_adr; { /* Takes a pointer to one of the system's inode entries * and reads the inode into the structure pointed to by "i" */ int mem; union /* used to convert pointers to numbers */ { char *ptr; unsigned addr; /* must be same length as char * */ } convert; convert.ptr = (char *) inode_adr; #ifdef vax convert.addr &= 0x3fffffff; #endif if ( convert.addr == 0 ) return( -1); if ( memdev >= 0 ) mem = memdev; else if( (mem = open( memf, O_RDONLY)) == -1 ) { perror( memf); return( -1); } /* read the inode */ rread( mem, (long) convert.addr, (char *) i, sizeof (struct inode)); if ( memdev != mem ) close( mem); #if vax || u3b i->i_dev = brdev(i->i_dev); /* removes bits to distinguish small and large FS */ i->i_rdev = brdev(i->i_rdev); /* removes bits to distinguish small and large FS */ #endif if(i->i_count == 0) return(-1); return( 0); } read_user( p, u, memdev) int memdev; struct proc p; struct user *u; { /* Copies the system's user area (in memory) pointed * to by "p" into the structure pointed to by "u" */ int i, x, spte, upte[128]; static int sdev = -1, mdev = -1, sbrpte = -1; static daddr_t swplo = (daddr_t) -1; if ( swplo == (daddr_t) -1 ) copyrval( system, SWPLO_STR, (char *) &swplo, sizeof swplo, memdev); /* Method depends on the machine */ /* VAX */ #ifdef vax if ( sbrpte == -1 ) { copyrval( system, SBRPTE_STR, (char *) &sbrpte, sizeof sbrpte, memdev); sbrpte &= 0x3fffffff; } #endif #if vax || u3b #ifdef vax if ( (p.p_flag & (SLOAD | SSPART)) == 0 /* swapped */ ) #endif #ifdef u3b if ( (p.p_flag & SLOAD) == 0 /* swapped */ ) #endif { if ( (sdev < 0) && ((sdev = open( "/dev/swap", O_RDONLY)) == -1) ) { perror( "/dev/swap"); exit( 1); } rread( sdev, (p.p_swaddr + p.p_swsize - USIZE + swplo) << PSHIFT, (char *) u, sizeof *u); } else /* in core */ { if ( (mdev < 0) && ((mdev = open( "/dev/mem", O_RDONLY)) == -1) ) { perror( "/dev/mem"); exit( 1); } #ifdef vax x = (int) (p.p_spt + (p.p_nspt - 1) * 128); x = (sbrpte + (( x & 0x3fffffff ) >> PSHIFT ) * 4) & 0x3fffffff; rread( mdev, (long) x, (char *) &spte, sizeof spte); rread( mdev, (long) (spte << PSHIFT), (char *) upte, sizeof upte); #endif for ( i = 0; i < sizeof (*u); i += PSIZE ) rread( mdev, #ifdef vax (long) ( upte[128-USIZE+i/PSIZE] << PSHIFT), #endif #ifdef u3b (long) ( p.p_uptbl[i/PSIZE] & PT_ADDR), #endif ((char *) u) + i, min( PSIZE, sizeof(*u) - i)); } #endif /* PDP-11 */ #ifdef pdp11 if ( p.p_flag & SLOAD /* in core */) { if ( (mdev < 0) && ((mdev = open( "/dev/mem", O_RDONLY)) == -1) ) { perror( "/dev/mem"); exit( 1); } rread( mdev, ctob((long) p.p_addr), (char *) u, sizeof *u); } else /* swapped */ { if ( (sdev < 0) && ((sdev = open( "/dev/swap", O_RDONLY)) == -1) ) { perror( "/dev/swap"); exit( 1); } rread( sdev, (p.p_addr + swplo) << 9, (char *) u, sizeof *u); } #endif } rread( device, position, buffer, count) char *buffer; int count, device; long position; { /* Seeks to "position" on device "device" and reads "count" * bytes into "buffer". Zeroes out the buffer on errors. */ int i; long lseek(); if ( lseek( device, position, 0) == (long) -1 ) { fprintf( stderr, "Seek error for file number %d: ", device); perror( ""); for ( i = 0; i < count; buffer++, i++) *buffer = '\0'; return; } if ( read( device, buffer, (unsigned) count) == -1 ) { fprintf( stderr, "Read error for file number %d: ", device); perror( ""); for ( i = 0; i < count; buffer++, i++) *buffer = '\0'; } }