home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume3 / xenix-fuser / fuser.c.u-pc < prev    next >
Encoding:
Text File  |  1989-02-03  |  8.9 KB  |  392 lines

  1. /************************************************************
  2.  *
  3.  * This program was written by me, Mike "Ford" Ditto, and
  4.  * I hereby release it into the public domain in the interest
  5.  * of promoting the development of free, quality software
  6.  * for the hackers and users of the world.
  7.  *
  8.  * Feel free to use, copy, modify, improve, and redistribute
  9.  * this program, but keep in mind the spirit of this
  10.  * contribution; always provide source, and always allow
  11.  * free redistribution (shareware is fine with me).  If
  12.  * you use a significant part of this code in a program of
  13.  * yours, I would appreciate being given the appropriate
  14.  * amount of credit.
  15.  *                -=] Ford [=-
  16.  *
  17.  ************************************************************/
  18.  
  19. #include <stdio.h>
  20. #include <fcntl.h>
  21. #include <ctype.h>
  22. #include <pwd.h>
  23. #include <sys/types.h>
  24. #include <sys/param.h>
  25. #include <sys/sysmacros.h>
  26. #include <sys/stat.h>
  27. #include <sys/tune.h>
  28. #include <sys/inode.h>
  29. #include <sys/file.h>
  30. #include <sys/user.h>
  31. #include <sys/proc.h>
  32. #include <sys/signal.h>
  33. #include <a.out.h>
  34.  
  35. /* get rid of meaningless NOFILE from param.h */
  36. #ifdef NOFILE
  37. #undef NOFILE
  38. #endif
  39.  
  40. extern char *sbrk();
  41. extern long lseek();
  42. extern void perror(), exit();
  43. extern struct passwd *getpwuid();
  44.  
  45.  
  46. char *progname;
  47.  
  48. #define tuhiaddr (mysyms[0].n_value)
  49. #define inodeaddr (mysyms[1].n_value)
  50. #define fileaddr (mysyms[2].n_value)
  51. #define procaddr (mysyms[3].n_value)
  52. #define nofileaddr (mysyms[4].n_value)
  53.  
  54. struct nlist mysyms[] =
  55. {
  56.     { "tuhi", },
  57.     { "inode", },
  58.     { "file", },
  59.     { "proc", },
  60.     { "nofile", },
  61.     { (char *)0, },
  62. };
  63.  
  64. char buf[BUFSIZ];
  65.  
  66. int kmem, mem, kflag, uflag;
  67. int NINODE, NFILE, NPROC, NOFILE;
  68.  
  69. struct inode *inode;
  70. struct file *file;
  71. struct proc *proc;
  72.  
  73.  
  74. /* main program for fuser(1M), a program which lists */
  75. /* processes that are using the given file(s) */
  76. main(argc, argv)
  77. int argc;
  78. char *argv[];
  79. {
  80.     int status=0;
  81.  
  82.     progname = *argv;
  83.  
  84.     setup();
  85.  
  86.     while (++argv,--argc)
  87.     if ((*argv)[0]=='-')
  88.     {
  89.         register char c, *i;
  90.  
  91.         kflag=uflag=0;
  92.  
  93.         i = *argv+1;
  94.         while (c= *i++) switch(c)
  95.         {
  96.         case 'k':
  97.         ++kflag;
  98.         break;
  99.         case 'u':
  100.         ++uflag;
  101.         break;
  102.         default:
  103.         fprintf(stderr, "%s: bad flag `-%c'\n", progname, c);
  104.         fprintf(stderr,
  105.             "Usage: %s [-ku] files [[-] [-ku] files]\n",
  106.             progname);
  107.         return -1;
  108.         }
  109.     }
  110.     else
  111.         status += fuser(*argv);
  112.  
  113.     return status;
  114. }
  115.  
  116.  
  117. /* a fast, zeroizing, memory allocator for things */
  118. /* that will never need to be freed */
  119. char *myalloc(nbytes)
  120. long nbytes;
  121. {
  122.     register char *ptr = sbrk((int)nbytes);
  123.  
  124.     if ((long)ptr < 0L)
  125.     {
  126.     sprintf(buf, "%s: no memory!", progname);
  127.     perror(buf);
  128.     exit(1);
  129.     }
  130.  
  131.     return ptr;
  132. }
  133.  
  134.  
  135. /* one-time setup of main data structures from the kernel */
  136. setup()
  137. {
  138.     struct tunable tune;
  139.  
  140.     if ( (kmem=open("/dev/kmem", O_RDONLY)) < 0 )
  141.     {
  142.     sprintf(buf, "%s: can't open /dev/kmem", progname);
  143.     perror(buf);
  144.     exit(1);
  145.     }
  146.  
  147.     if ( (mem=open("/dev/mem", O_RDONLY)) < 0 )
  148.     {
  149.     sprintf(buf, "%s: can't open /dev/mem", progname);
  150.     perror(buf);
  151.     exit(1);
  152.     }
  153.  
  154.     if (nlist("/unix", mysyms))
  155.     {
  156.     sprintf(buf, "%s: can't nlist /unix", progname);
  157.     perror(buf);
  158.     exit(1);
  159.     }
  160.  
  161.     setuid(getuid());
  162.  
  163.     kcopy((char *)&NOFILE, nofileaddr, (long) sizeof NOFILE);
  164.  
  165. #ifdef DEBUG
  166.     fprintf(stderr, "tuhi:    0x%08lx\n", tuhiaddr);
  167. #endif DEBUG
  168.     kcopy((char *)&tune, tuhiaddr, (long) sizeof tune);
  169.  
  170.     /* do indirection on these addresses, since they */
  171.     /* are just pointers in the kernel */
  172.     kcopy((char *)&inodeaddr, inodeaddr, (long) sizeof inodeaddr);
  173.     kcopy((char *)&fileaddr, fileaddr, (long) sizeof fileaddr);
  174.     kcopy((char *)&procaddr, procaddr, (long) sizeof procaddr);
  175.  
  176. #ifdef DEBUG
  177.     fprintf(stderr, "inode:    0x%08lx\n", inodeaddr);
  178.     fprintf(stderr, "file:    0x%08lx\n", fileaddr);
  179.     fprintf(stderr, "proc:    0x%08lx\n", procaddr);
  180. #endif DEBUG
  181.  
  182.     NINODE = tune.ninode;
  183.     NFILE = tune.nfile;
  184.     NPROC = tune.nproc;
  185.  
  186. #ifdef DEBUG
  187.     fprintf(stderr, "NOFILE:    %d\n", NOFILE);
  188.     fprintf(stderr, "NINODE:    %d\n", NINODE);
  189.     fprintf(stderr, "NFILE:    %d\n", NFILE);
  190.     fprintf(stderr, "NPROC:    %d\n", NPROC);
  191. #endif DEBUG
  192.  
  193.     inode = (struct inode *)myalloc((long) sizeof (struct inode) * NINODE);
  194.     file = (struct file *)myalloc((long) sizeof (struct file) * NFILE);
  195.     proc = (struct proc *)myalloc((long) sizeof (struct proc) * NPROC);
  196.  
  197.     kcopy((char *)inode, inodeaddr, (long) sizeof (struct inode) * NINODE);
  198.     kcopy((char *)file, fileaddr, (long) sizeof (struct file) * NFILE);
  199.     kcopy((char *)proc, procaddr, (long) sizeof (struct proc) * NPROC);
  200. }
  201.  
  202.  
  203. /* copy bytes from physical address space to this process */
  204. pcopy(caddr, paddr, nbytes)
  205. char *caddr;
  206. long paddr;
  207. long nbytes;
  208. {
  209.     if ( lseek(mem, paddr, 0)<0L ||
  210.     read(mem, caddr, (unsigned)nbytes) != nbytes )
  211.     {
  212.     sprintf(buf, "%s: can't read /dev/mem", progname);
  213.     perror(buf);
  214.     exit(1);
  215.     }
  216. }
  217.  
  218.  
  219. /* copy bytes from kernel address space to this process */
  220. kcopy(caddr, kaddr, nbytes)
  221. char *caddr;
  222. long kaddr;
  223. long nbytes;
  224. {
  225.     if ( lseek(kmem, kaddr, 0)<0L ||
  226.     read(kmem, caddr, (unsigned)nbytes) != nbytes )
  227.     {
  228.     sprintf(buf, "%s: can't read /dev/kmem", progname);
  229.     perror(buf);
  230.     exit(1);
  231.     }
  232. }
  233.  
  234.  
  235. /* Return a pointer to a local copy of the user structure */
  236. /* for process number `procidx'.  Returns NULL if procidx */
  237. /* refers to an invalid (not-in-use or otherwise) slot. */
  238. struct user *getuser(procidx)
  239. int procidx;
  240. {
  241.     static struct user **users;
  242.     struct file **ofile;
  243.     long upage;
  244.  
  245.     if (!proc[procidx].p_stat ||
  246.     proc[procidx].p_stat == SIDL ||
  247.     proc[procidx].p_stat == SZOMB)
  248.     return 0;
  249.  
  250.     if (!(proc[procidx].p_flag & SLOAD))
  251.     {
  252.     /* can't handle swapped process yet */
  253.     fprintf(stderr, "%s: can't handle swapped process %d (flag=%05x)\n",
  254.         progname, proc[procidx].p_pid, proc[procidx].p_flag);
  255.     return 0;
  256.     }
  257.  
  258.     if (!users)
  259.     users = (struct user **)myalloc((long) sizeof (struct user *) * NPROC);
  260.  
  261.     if (!users[procidx])
  262.     {
  263.     upage = (long)ctob(proc[procidx].p_addr[0]);
  264.  
  265.     /* allocate and copy in the user structure */
  266.     users[procidx] = (struct user *)myalloc((long) sizeof (struct user));
  267.     pcopy((char *)(users[procidx]),
  268.           upage + U_OFFSET,
  269.           (long) sizeof (struct user));
  270.  
  271.     /* allocate and copy in the list of file pointers */
  272.     ofile = (struct file **)myalloc((long) sizeof (struct file *) * NOFILE);
  273.     pcopy((char *)ofile,
  274.           upage+(long)(users[procidx]->u_ofile)-VPG_BASE,
  275.           (long) sizeof (struct file *) * NOFILE);
  276.     users[procidx]->u_ofile = ofile;
  277.     }
  278.  
  279.     return users[procidx];
  280. }
  281.  
  282.  
  283. /* find all users of the file `name' */
  284. fuser(name)
  285. char *name;
  286. {
  287.     register i;
  288.     int filesys;
  289.     struct stat Stat;
  290.  
  291.     if (stat(name, &Stat))
  292.     {
  293.     sprintf(buf, "%s: can't stat %s", progname, name);
  294.     perror(buf);
  295.     return 1;
  296.     }
  297.  
  298.     /* see if we are looking for a whole filesystem */
  299.     filesys = ((Stat.st_mode&S_IFMT) == S_IFBLK);
  300.  
  301. #ifdef DEBUG
  302.     if (filesys)
  303.     fprintf(stderr, "looking for files on dev=%d,%d\n",
  304.         bmajor(Stat.st_rdev), minor(Stat.st_rdev));
  305.     else
  306.     fprintf(stderr, "looking for dev=%d,%d, ino=%d\n",
  307.         bmajor(Stat.st_dev), minor(Stat.st_dev), Stat.st_ino);
  308. #endif DEBUG
  309.  
  310.     for ( i=0 ; i<NINODE ; ++i )
  311.     {
  312.     if ( inode[i].i_count &&
  313.          (filesys
  314.          ? (brdev(inode[i].i_dev) == Stat.st_rdev)
  315.          : (brdev(inode[i].i_dev) == Stat.st_dev &&
  316.             inode[i].i_number == Stat.st_ino)) )
  317.     {
  318. #ifdef DEBUG
  319.         fprintf(stderr, "Found it!  inode[%d], i_size is %ld\n",
  320.            i, inode[i].i_size);
  321. #endif DEBUG
  322.  
  323.         iuser((struct inode *)inodeaddr + i);
  324.     }
  325.     }
  326.  
  327.     putchar('\n');
  328.  
  329.     return 0;
  330. }
  331.  
  332.  
  333. #define CHECK(kaddr, type) if (kaddr==kinode) { if (++flag==1) printf(" %d", proc[i].p_pid); if (type) putchar(type); }
  334.  
  335. /* find all users of the inode at kernel address `kinode' */
  336. iuser(kinode)
  337. struct inode *kinode;
  338. {
  339.     register int i, j;
  340.     int flag;
  341.     struct user *user;
  342.     struct passwd *pwd;
  343.  
  344. #ifdef DEBUG
  345.     fprintf(stderr, "Looking for users of inode at kernel address 0x%08lx\n",
  346.         kinode);
  347. #endif DEBUG
  348.  
  349.     for ( i=0 ; i<NPROC ; ++i )
  350.     if (user = getuser(i))
  351.     {
  352. #ifdef DEBUG
  353.         fprintf(stderr, "%03d: pid=%5d addr[0]=%05x addr[1]=%05x swaddr=%05x\n",
  354.             i, proc[i].p_pid, proc[i].p_addr[0], proc[i].p_addr[1],
  355.             proc[i].p_swaddr);
  356. #endif DEBUG
  357.  
  358. #ifdef DEBUG
  359.         fprintf(stderr, "    user = 0x%08lx\n", user);
  360.         fprintf(stderr, "    user->u_ofile = 0x%08lx\n", user->u_ofile);
  361. #endif DEBUG
  362.  
  363.         fflush(stderr);
  364.         flag=0;
  365.         CHECK(user->u_cdir, 'c');
  366.         CHECK(user->u_rdir, 'r');
  367.         CHECK(user->u_pdir, 'p');
  368.         for ( j=0 ; !flag && j<NOFILE ; ++j )
  369.         if (user->u_ofile[j])
  370.             CHECK(file[user->u_ofile[j]-(struct file *)fileaddr].f_inode, 0);
  371.         fflush(stdout);
  372.  
  373.         if (flag)
  374.         {
  375.         if (uflag)
  376.         {
  377.             if ( (pwd=getpwuid((int)proc[i].p_uid)) )
  378.             fprintf(stderr, "(%s)", pwd->pw_name);
  379.             else
  380.             fprintf(stderr, "(%d)", proc[i].p_uid);
  381.         }
  382.         if (kflag && proc[i].p_pid)
  383.             if (kill(proc[i].p_pid, SIGKILL))
  384.             {
  385.             sprintf(buf, "%s: can't kill process %d",
  386.                 progname, proc[i].p_pid);
  387.             perror(buf);
  388.             }
  389.         }
  390.     }
  391. }
  392.