home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / modutils / insmod / rmmod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-06  |  6.8 KB  |  342 lines

  1. /* Remove a module from a running kernel.
  2.    Copyright 1996, 1997 Linux International.
  3.  
  4.    New implementation contributed by Richard Henderson <rth@tamu.edu>
  5.    Based on original work by Bjorn Eckwall <bj0rn@blox.se>
  6.  
  7.    This file is part of the Linux modutils.
  8.  
  9.    This program is free software; you can redistribute it and/or modify it
  10.    under the terms of the GNU General Public License as published by the
  11.    Free Software Foundation; either version 2 of the License, or (at your
  12.    option) any later version.
  13.  
  14.    This program is distributed in the hope that it will be useful, but
  15.    WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.    General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software Foundation,
  21.    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  22.  
  23. #ident "$Id: rmmod.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $"
  24.  
  25. #include <sys/types.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <string.h>
  31. #include <errno.h>
  32.  
  33. #include "module.h"
  34. #include "util.h"
  35. #include "version.h"
  36.  
  37. #include "logger.h"
  38.  
  39. /*======================================================================*/
  40.  
  41. #define WANT_TO_REMOVE 1
  42. #define CAN_REMOVE 2
  43.  
  44. struct extmodule
  45. {
  46.   char *name;
  47.   struct extmodule **refs;
  48.   int nrefs;
  49.   int status;            /* WANT_TO_REMOVE | CAN_REMOVE */
  50. };
  51.  
  52.  
  53. static struct extmodule *modules;
  54. static size_t nmodules;
  55.  
  56.  
  57. /* If we don't have query_module ... */
  58.  
  59. static int
  60. old_get_modules(void)
  61. {
  62.   int fd, nmod, len, bufsize;
  63.   char *buffer, *p;
  64.   struct extmodule *mod;
  65.  
  66.   /* Read the module information from /proc in one go.  */
  67.  
  68.   if ((fd = open("/proc/modules", O_RDONLY)) < 0)
  69.     {
  70.       error("/proc/modules: %m");
  71.       return 0;
  72.     }
  73.  
  74.   buffer = xmalloc(bufsize = 8*1024);
  75. retry_read:
  76.   len = read(fd, buffer, bufsize);
  77.   if (len < 0)
  78.     {
  79.       error("/proc/modules: %m");
  80.       return 0;
  81.     }
  82.   else if (len == sizeof(buffer))
  83.     {
  84.       lseek(fd, 0, SEEK_SET);
  85.       buffer = xrealloc(buffer, bufsize *= 2);
  86.       goto retry_read;
  87.     }
  88.  
  89.   close(fd);
  90.  
  91.   /* Break the buffer into lines and deal with them individually.  */
  92.  
  93.   mod = NULL;
  94.   nmod = 0;
  95.  
  96.   buffer[len+1] = '\0';
  97.   p = buffer;
  98.   while (p < buffer+len)
  99.     {
  100.       char *e;
  101.       struct extmodule *m;
  102.  
  103.       mod = xrealloc(mod, ++nmod * sizeof(struct extmodule));
  104.       m = &mod[nmod-1];
  105.  
  106.       m->refs = NULL;
  107.       m->nrefs = 0;
  108.       m->status = 0;
  109.  
  110.       /* Save the end of the line.  */
  111.       e = strchr(p, '\n');
  112.       *e = '\0';
  113.  
  114.       /* Save the module name.  */
  115.       m->name = p;
  116.  
  117.       p = strchr(p, ' ');
  118.       *p = '\0';
  119.  
  120.       if ((p = strchr(p+1, '[')) != NULL)
  121.     {
  122.       *strrchr(++p, ']') = '\0';
  123.  
  124.       for (p = strtok(p, " "); p ; p = strtok(NULL, " "))
  125.         {
  126.           struct extmodule *rm;
  127.           int i;
  128.  
  129.           for (i = 0, rm = mod; i < nmod; ++i, ++rm)
  130.         if (strcmp(rm->name, p) == 0)
  131.           goto found_ref;
  132.  
  133.           error("strange module reference: %s used by %s?\n", m->name, p);
  134.           return 0;
  135.  
  136.         found_ref:
  137.           m->refs = xrealloc(m->refs,
  138.                  ++m->nrefs * sizeof(struct extmodule *));
  139.           m->refs[m->nrefs-1] = rm;
  140.         }
  141.     }
  142.  
  143.       p = e+1;
  144.     }
  145.  
  146.   modules = mod;
  147.   nmodules = nmod;
  148.  
  149.   return 1;
  150. }
  151.  
  152. /* If we do have query_module ... */
  153.  
  154. static int
  155. new_get_modules(void)
  156. {
  157.   char *module_names, *mn, *refs;
  158.   struct extmodule *mod, *m;
  159.   size_t bufsize, ret, nmod, i;
  160.  
  161.   /* Fetch the list of modules.  */
  162.  
  163.   module_names = xmalloc(bufsize = 1024);
  164. retry_mod_load:
  165.   if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret))
  166.     {
  167.       if (errno == ENOSPC)
  168.     {
  169.       module_names = xrealloc(module_names, bufsize = ret);
  170.       goto retry_mod_load;
  171.     }
  172.       error("QM_MODULES: %m");
  173.       return 0;
  174.     }
  175.   nmod = ret;
  176.  
  177.   mod = xmalloc(nmod * sizeof(struct extmodule));
  178.   memset(mod, 0, nmod * sizeof(struct extmodule));
  179.  
  180.   for (i = 0, mn = module_names, m = mod;
  181.        i < nmod;
  182.        ++i, mn += strlen(mn)+1, ++m)
  183.     m->name = mn;
  184.  
  185.   /* Fetch the module references.  */
  186.  
  187.   refs = xmalloc(bufsize = 1024);
  188.   for (i = 0, m = mod; i < nmod; ++i, ++m)
  189.     {
  190.       size_t j, nrefs;
  191.       char *r;
  192.  
  193.     retry_ref_load:
  194.       if (query_module(m->name, QM_REFS, refs, bufsize, &ret))
  195.     {
  196.       if (errno == ENOSPC)
  197.         {
  198.           refs = xrealloc(refs, bufsize = ret);
  199.           goto retry_ref_load;
  200.         }
  201.       error("QM_REFS: %m");
  202.       return 0;
  203.     }
  204.       m->nrefs = nrefs = ret;
  205.       m->refs = xmalloc(nrefs * sizeof(struct extmodule *));
  206.  
  207.       for (j = 0, r = refs; j < ret; ++j, r += strlen(r)+1)
  208.     {
  209.       struct extmodule *rm;
  210.       size_t k;
  211.  
  212.       for (k = 0, rm = mod; k < nmod; ++k, ++rm)
  213.         if (strcmp(rm->name, r) == 0)
  214.           goto found_ref;
  215.  
  216.       error("strange module reference: %s used by %s?\n", m->name, r);
  217.       return 0;
  218.  
  219.     found_ref:
  220.       m->refs[j] = rm;
  221.     }
  222.     }
  223.  
  224.   free(refs);
  225.  
  226.   modules = mod;
  227.   nmodules = nmod;
  228.  
  229.   return 1;
  230. }
  231.  
  232. int
  233. main(int argc, char **argv)
  234. {
  235.   int i, j, ret = 0;
  236.  
  237.   error_file = "rmmod";
  238.  
  239.   while ((i = getopt(argc, argv, "asV")) != EOF)
  240.     switch (i)
  241.       {
  242.       case 'a':
  243.     /* Remove all unused modules and stacks.  */
  244.     if (delete_module(NULL))
  245.       {
  246.         perror("rmmod");
  247.         return 1;
  248.       }
  249.     return 0;
  250.  
  251.       case 's':
  252.     /* Start syslogging.  */
  253.     setsyslog("rmmod");
  254.     break;
  255.  
  256.       case 'V':
  257.     fputs("rmmod version " MODUTILS_VERSION "\n", stderr);
  258.     break;
  259.  
  260.       default:
  261.       usage:
  262.     fputs("Usage: rmmod [-a] [-s] module ...\n", stderr);
  263.     return 1;
  264.       }
  265.  
  266.   if (optind >= argc)
  267.     goto usage;
  268.  
  269.   /* Fetch all of the currently loaded modules and their dependencies.  */
  270.  
  271.   if (query_module(NULL, 0, NULL, 0, NULL) == 0
  272.       ? !new_get_modules()
  273.       : !old_get_modules())
  274.     return 1;
  275.  
  276.   /* Find out which ones we want to remove.  */
  277.  
  278.   for (i = optind; i < argc; ++i)
  279.     {
  280.       for (j = 0; j < nmodules; ++j)
  281.     if (strcmp(modules[j].name, argv[i]) == 0)
  282.       goto found_module;
  283.  
  284.       error("module %s not loaded", argv[i]);
  285.       ret = 1;
  286.       continue;
  287.  
  288.     found_module:
  289.       modules[j].status |= WANT_TO_REMOVE;
  290.     }
  291.  
  292.   if (ret)
  293.     return ret;
  294.  
  295.   /* Remove them if we can.  */
  296.  
  297.   for (i = 0; i < nmodules ; ++i)
  298.     {
  299.       struct extmodule *m = &modules[i];
  300.  
  301.       if (m->nrefs == 0 && m->status == WANT_TO_REMOVE)
  302.     m->status |= CAN_REMOVE;
  303.  
  304.       for (j = 0; j < m->nrefs; ++j)
  305.     {
  306.       struct extmodule *r = m->refs[j];
  307.       switch (r->status)
  308.         {
  309.         case CAN_REMOVE:
  310.         case WANT_TO_REMOVE | CAN_REMOVE:
  311.           break;
  312.  
  313.         case WANT_TO_REMOVE:
  314.           if (r->nrefs == 0)
  315.         break;
  316.         default:
  317.           m->status &= ~CAN_REMOVE;
  318.           break;
  319.         }
  320.     }
  321.  
  322.       switch (m->status)
  323.     {
  324.     case CAN_REMOVE:
  325.     case WANT_TO_REMOVE | CAN_REMOVE:
  326.       if (delete_module(m->name) < 0)
  327.         {
  328.           error("%s: %m", m->name);
  329.           ret = 1;
  330.         }
  331.       break;
  332.  
  333.     case WANT_TO_REMOVE:
  334.       error("%s is in use", m->name);
  335.       ret = 1;
  336.       break;
  337.     }
  338.     }
  339.  
  340.   return ret;
  341. }
  342.