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

  1. /* Copyright 1996 Free Software Foundation, Inc.
  2.    Contributed by Marcin Dalecki <dalecki@sub994.sub.uni-goettingen.de>
  3.  
  4.    This file is part of the Linux modutils.
  5.  
  6.    This program is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by the
  8.    Free Software Foundation; either version 2 of the License, or (at your
  9.    option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.    General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software Foundation,
  18.    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  19.  
  20. #ident "$Id: misc.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $"
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <stdarg.h>
  25. #include <string.h>
  26. #include <syslog.h>
  27. #include <ctype.h>
  28. #include <errno.h>
  29. #include <sys/stat.h>
  30. #include <sys/utsname.h>
  31.  
  32. #include "util.h"
  33. #include "misc.h"
  34.  
  35. /*=================================================================*/
  36.  
  37. int flag_debug = 0;
  38.  
  39. /*=================================================================*/
  40.  
  41. /*
  42.  * Strip the directory and .o or .mod extension of a file name
  43.  * Return a pointer to a malloc()ed buffer
  44.  */
  45. char *
  46. strip_o (char *fname)
  47. {
  48.   char *pt = fname;
  49.  
  50.   while ((pt = strchr (fname, '/')))
  51.     fname = pt + 1;
  52.   if ((pt = strrchr (fname, '.'))
  53.       && ((strcmp (pt, ".o") == 0) || (strcmp (pt, ".mod") == 0)))
  54.     {
  55.       char *leak = (char *) xmalloc (pt - fname + 1);
  56.       strncpy (leak, fname, pt - fname);
  57.       leak[pt - fname] = '\0';
  58.       
  59.       return leak;
  60.     }
  61.   return xstrdup (fname);
  62. }
  63.  
  64. /*=================================================================*/
  65.  
  66. /*
  67.  * Read and preprocess the contents of a configuration file.
  68.  * Return the preprocessed contents on success and NULL otherwise.
  69.  *
  70.  * This function implements efficient in place reading of files,
  71.  * the usual semantics of '#' comments and the arbitrary multiplicity of
  72.  * white spaces as delimiters.
  73.  */
  74. char *
  75. read_and_preprocess_file (const char *file)
  76. {
  77.   char *buf;
  78.  
  79.   char *tmp;
  80.   char *pmt;
  81.   char *cp;
  82.   
  83.   FILE *fp;
  84.   struct stat statb;
  85.  
  86.   if (stat (file, &statb) == -1
  87.       || (statb.st_mode & S_IFMT) != S_IFREG
  88.       || !(fp = fopen (file, "r")))
  89.     {
  90.       return NULL;
  91.     }
  92.  
  93.   /*
  94.    * OK: Now first read all of the file into a dynamically allocated buffer.
  95.    */
  96.   buf = (char *) xmalloc ((unsigned) (statb.st_size + 2));
  97.   if (!fread (buf, sizeof (char), statb.st_size + 1, fp));
  98.     /* lprintf ("warning: file %s is empty!\n", file); */
  99.   buf[statb.st_size] = '\0';    /* be sure to NULL-terminate */
  100.   fclose (fp);
  101.  
  102.   if (!strlen(buf))
  103.       return buf;
  104.   /* 
  105.    * Go through the whole buffer and remove comments by blanking them out.
  106.    */
  107.   for (cp = buf; (cp = strchr (cp, '#')); cp = tmp)
  108.     {
  109.       tmp = strchr (cp, '\n');
  110.       if (!tmp)
  111.     tmp = cp + strlen (cp);
  112.       memset (cp, ' ', tmp - cp);
  113.     }
  114.  
  115.   /*
  116.    * Replace whitespaces other then '\n' by ' '
  117.    */
  118.   cp = buf;
  119.   do
  120.     {
  121.       cp += strcspn (cp, "\t\f\v\r");
  122.       if (*cp)
  123.     *cp = ' ';
  124.     }
  125.   while (*cp);
  126.  
  127.   /*
  128.    * Collapse all multiple white spaces into one
  129.    */
  130.   tmp = pmt = buf;
  131.   do
  132.     {
  133.       tmp += strspn (tmp, " ");
  134.       cp = strchr (tmp, ' ');
  135.       if (!cp)
  136.     cp = tmp + strlen (tmp);
  137.       memmove (pmt, tmp, cp - tmp + 1);
  138.       pmt += cp - tmp + 1;
  139.  
  140.       tmp = cp + 1;
  141.     }
  142.   while (*cp);
  143.   
  144.   /*
  145.    * Remove any white space at line ends.
  146.    */
  147.   tmp = pmt = buf;  
  148.   do
  149.     {
  150.        cp = strstr(tmp, " \n");
  151.        if (!cp)
  152.          cp = tmp + strlen (tmp);
  153.        else
  154.          *cp = '\n';
  155.        memmove (pmt, tmp, cp - tmp + 1);
  156.        pmt += cp - tmp + 1;
  157.        
  158.        tmp = cp + 2;
  159.     }
  160.   while (*cp);
  161.  
  162.   tmp = pmt = buf;  
  163.   do
  164.     {
  165.       cp = strstr(tmp, "\n ");
  166.       if (!cp)
  167.         cp = tmp + strlen (tmp);
  168.       memmove (pmt, tmp, cp - tmp + 1);
  169.       pmt += cp - tmp + 1;
  170.       
  171.       tmp = cp + 2;
  172.     }
  173.   while(*cp);
  174.   
  175.   /*
  176.    * Make sure that the last line is terminated by newline.
  177.    */
  178.   if ((cp > buf) && (*(cp - 1) != '\n'))
  179.     {
  180.       cp[0] = '\n';
  181.       cp[1] = '\0';        /* no problem, we allocated this bit */
  182.     }
  183.  
  184.   return buf;
  185. }
  186.  
  187. #define RELEASE        0
  188. #define UNKNOWN        -1
  189.  
  190. /* We check what kind command or pattern it tries to run. */
  191. static int
  192. what_command (const char *cmd)
  193. {
  194.   /* We first build the canonical form. */
  195.   cmd = basename (cmd);
  196.   if (strncmp (cmd, "uname", 5) == 0)
  197.   {
  198.     char *p;
  199.  
  200.     /* We check the argument. */
  201.     p = strstr (cmd, "-r");
  202.     if (p == NULL) return UNKNOWN;
  203.     for (cmd += 5; cmd < p; cmd++)
  204.     {
  205.       if (!isspace (*cmd)) return UNKNOWN;
  206.     }
  207.     for (cmd += 2; *cmd; cmd++)
  208.     {
  209.       if (!isspace (*cmd)) return UNKNOWN;
  210.     }
  211.  
  212.     return RELEASE;
  213.   }
  214.   return UNKNOWN;
  215. }
  216.  
  217. /* We expand the command or pattern. */
  218. static char *
  219. expand_command (const char *prefix, const char *command)
  220. {
  221.   static struct utsname utsbuf; 
  222.   char *tmp;
  223.  
  224.   switch (what_command (command))
  225.   {
  226.   case RELEASE:
  227.     /* We need the kernel release number. */
  228.     if (uname (&utsbuf) && errno != 0)
  229.     {
  230.       /* Bad release number. */
  231.       tmp = "uname return error";
  232.     }
  233.     else
  234.     {
  235.       tmp = utsbuf.release;
  236.     }
  237.     break;
  238.  
  239.   default:
  240.     /* We can add more later. For now, we just ignore it. */
  241.     tmp = NULL;
  242.     break;
  243.   }
  244.  
  245.   return tmp;
  246. }
  247.  
  248. /* We resolve the string for patterns and commands. */
  249. char *
  250. resolve_string (const char *str, char *buf, int size)
  251. {
  252.   const char *next, *left, *right;
  253.   char *command, *tmp, *cp;
  254.   int len;
  255.  
  256.   /* We parse the string for `foo`. */
  257.   cp = buf;
  258.   right = str;
  259.   for (next = str; (left = strchr (next, '`')) != NULL; next = right + 1)
  260.   {
  261.     /* We found the first `. Copy the plain part. */
  262.     len = left - next;
  263.     size -= len;
  264.     if (size <= 0)
  265.     {
  266.       goto error;
  267.     }
  268.     strncpy (cp, next, len);
  269.     cp += len;
  270.  
  271.     right = strchr (left + 1, '`');
  272.     if (right == NULL)
  273.     {
  274.       /* No second `. */
  275.       break;
  276.     }
  277.  
  278.     /* Now we get the second `. */
  279.     len = right - left;
  280.     command = alloca (len);
  281.     strncpy (command, left + 1, len - 1);
  282.     command [len - 1] = '\0';
  283.     *cp = '\0';
  284.  
  285.     tmp = expand_command (buf, command);
  286.     if (tmp)
  287.     {
  288.       len = strlen (tmp);
  289.       size -= len;
  290.       if (size <= 0)
  291.       {
  292.     goto error;
  293.       }
  294.       strncpy (cp, tmp, len);
  295.       cp += len;
  296.     }
  297.     else
  298.     {
  299.       /* We don't know how to deal with it. Just copy it for now. */
  300.       size -= len + 1;
  301.       if (size <= 0)
  302.       {
  303.     goto error;
  304.       }
  305.       strncpy (cp, left, len + 1);
  306.       cp += len + 1;
  307.     }
  308.   }
  309.  
  310.   if (right)
  311.   {
  312.     /* We are done. Copy the rest. */
  313.    strncpy (cp, next, size - 1);
  314.   }
  315.   else
  316.   {
  317.     /* No second `. Copy the rest. */
  318.     strncpy (cp, left, size - 1);
  319.   }
  320.   buf [size - 1] = '\0';
  321.   
  322.   return buf;
  323.  
  324. error:
  325.   /* We don't do anything. */
  326.   return (char *) str;
  327. }
  328.  
  329. /*
  330.  * This function concatenates lines terminated by '\\' and increases "lines"
  331.  * accordingly. If "src" there is no source or the source is empty, we
  332.  * return NULL. Otherwise we are returning the end of parsing.
  333.  * The result is placed in "src"! lines is adjusted to the number of lines
  334.  * read.
  335.  */
  336. char *
  337. get_concat_line (char *src, int *lines)
  338. {
  339.   char *tmp;
  340.  
  341.   if (!src)            /* nothing to be processed */
  342.     return NULL;
  343.  
  344.   tmp = src;
  345.  
  346.   if (!*tmp)
  347.     return NULL;
  348.  
  349.   while (*src && (*src != '\n'))
  350.     {
  351.       if (src[0] == '\\' && src[1] == '\n')
  352.     {
  353.       ++*lines;
  354.       ++src;
  355.       *src = '*';        /* fake it for the next loop */
  356.       --tmp;
  357.     }
  358.       else
  359.     *tmp = *src;
  360.  
  361.       ++src;
  362.       ++tmp;
  363.     }
  364.   *tmp = '\0';
  365.   ++*lines;
  366.  
  367.   return src + 1;
  368. }
  369.  
  370. /*=================================================================*/
  371.  
  372. /*
  373.  * Error logging facilities.
  374.  */
  375.  
  376. int log;            /* this is passed to insmod */
  377. static int silent;
  378.  
  379. static int errors;
  380. static const char *error_file;
  381.  
  382. void
  383. error (const char *fmt,...)
  384. {
  385.   va_list args;
  386.  
  387.   if (silent)
  388.     ;
  389.   else if (log)
  390.     {
  391.       char buf[1024];
  392.       int n;
  393.  
  394.       n = snprintf (buf, sizeof (buf), "%s: ",
  395.             error_file ? error_file : "insmod");
  396.       va_start (args, fmt);
  397.       vsnprintf (buf + n, sizeof (buf) - n, fmt, args);
  398.       va_end (args);
  399.  
  400.       syslog (LOG_ERR, "%s", buf);
  401.     }
  402.   else
  403.     {
  404.       fprintf (stderr, "%s: ", error_file ? error_file : "modprobe");
  405.       va_start (args, fmt);
  406.       vfprintf (stderr, fmt, args);
  407.       va_end (args);
  408.       putc ('\n', stderr);
  409.     }
  410.  
  411.   errors++;
  412. }
  413.  
  414. void
  415. lprintf (const char *fmt,...)
  416. {
  417.   va_list args;
  418.  
  419.   if (silent)
  420.     ;
  421.   else if (log)
  422.     {
  423.       char buf[1024];
  424.       va_start (args, fmt);
  425.       vsnprintf (buf, sizeof (buf), fmt, args);
  426.       va_end (args);
  427.       syslog (LOG_INFO, "%s", buf);
  428.     }
  429.   else
  430.     {
  431.       va_start (args, fmt);
  432.       vfprintf (stdout, fmt, args);
  433.       va_end (args);
  434.       putchar ('\n');
  435.     }
  436. }
  437.  
  438. void
  439. setsyslog (const char *program)
  440. {
  441.   openlog (program, LOG_CONS, LOG_DAEMON);
  442.   log = 1;
  443. }
  444.