/* Copyright 1996 Free Software Foundation, Inc. Contributed by Marcin Dalecki This file is part of the Linux modutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ident "$Id: misc.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $" #include #include #include #include #include #include #include #include #include #include "util.h" #include "misc.h" /*=================================================================*/ int flag_debug = 0; /*=================================================================*/ /* * Strip the directory and .o or .mod extension of a file name * Return a pointer to a malloc()ed buffer */ char * strip_o (char *fname) { char *pt = fname; while ((pt = strchr (fname, '/'))) fname = pt + 1; if ((pt = strrchr (fname, '.')) && ((strcmp (pt, ".o") == 0) || (strcmp (pt, ".mod") == 0))) { char *leak = (char *) xmalloc (pt - fname + 1); strncpy (leak, fname, pt - fname); leak[pt - fname] = '\0'; return leak; } return xstrdup (fname); } /*=================================================================*/ /* * Read and preprocess the contents of a configuration file. * Return the preprocessed contents on success and NULL otherwise. * * This function implements efficient in place reading of files, * the usual semantics of '#' comments and the arbitrary multiplicity of * white spaces as delimiters. */ char * read_and_preprocess_file (const char *file) { char *buf; char *tmp; char *pmt; char *cp; FILE *fp; struct stat statb; if (stat (file, &statb) == -1 || (statb.st_mode & S_IFMT) != S_IFREG || !(fp = fopen (file, "r"))) { return NULL; } /* * OK: Now first read all of the file into a dynamically allocated buffer. */ buf = (char *) xmalloc ((unsigned) (statb.st_size + 2)); if (!fread (buf, sizeof (char), statb.st_size + 1, fp)); /* lprintf ("warning: file %s is empty!\n", file); */ buf[statb.st_size] = '\0'; /* be sure to NULL-terminate */ fclose (fp); if (!strlen(buf)) return buf; /* * Go through the whole buffer and remove comments by blanking them out. */ for (cp = buf; (cp = strchr (cp, '#')); cp = tmp) { tmp = strchr (cp, '\n'); if (!tmp) tmp = cp + strlen (cp); memset (cp, ' ', tmp - cp); } /* * Replace whitespaces other then '\n' by ' ' */ cp = buf; do { cp += strcspn (cp, "\t\f\v\r"); if (*cp) *cp = ' '; } while (*cp); /* * Collapse all multiple white spaces into one */ tmp = pmt = buf; do { tmp += strspn (tmp, " "); cp = strchr (tmp, ' '); if (!cp) cp = tmp + strlen (tmp); memmove (pmt, tmp, cp - tmp + 1); pmt += cp - tmp + 1; tmp = cp + 1; } while (*cp); /* * Remove any white space at line ends. */ tmp = pmt = buf; do { cp = strstr(tmp, " \n"); if (!cp) cp = tmp + strlen (tmp); else *cp = '\n'; memmove (pmt, tmp, cp - tmp + 1); pmt += cp - tmp + 1; tmp = cp + 2; } while (*cp); tmp = pmt = buf; do { cp = strstr(tmp, "\n "); if (!cp) cp = tmp + strlen (tmp); memmove (pmt, tmp, cp - tmp + 1); pmt += cp - tmp + 1; tmp = cp + 2; } while(*cp); /* * Make sure that the last line is terminated by newline. */ if ((cp > buf) && (*(cp - 1) != '\n')) { cp[0] = '\n'; cp[1] = '\0'; /* no problem, we allocated this bit */ } return buf; } #define RELEASE 0 #define UNKNOWN -1 /* We check what kind command or pattern it tries to run. */ static int what_command (const char *cmd) { /* We first build the canonical form. */ cmd = basename (cmd); if (strncmp (cmd, "uname", 5) == 0) { char *p; /* We check the argument. */ p = strstr (cmd, "-r"); if (p == NULL) return UNKNOWN; for (cmd += 5; cmd < p; cmd++) { if (!isspace (*cmd)) return UNKNOWN; } for (cmd += 2; *cmd; cmd++) { if (!isspace (*cmd)) return UNKNOWN; } return RELEASE; } return UNKNOWN; } /* We expand the command or pattern. */ static char * expand_command (const char *prefix, const char *command) { static struct utsname utsbuf; char *tmp; switch (what_command (command)) { case RELEASE: /* We need the kernel release number. */ if (uname (&utsbuf) && errno != 0) { /* Bad release number. */ tmp = "uname return error"; } else { tmp = utsbuf.release; } break; default: /* We can add more later. For now, we just ignore it. */ tmp = NULL; break; } return tmp; } /* We resolve the string for patterns and commands. */ char * resolve_string (const char *str, char *buf, int size) { const char *next, *left, *right; char *command, *tmp, *cp; int len; /* We parse the string for `foo`. */ cp = buf; right = str; for (next = str; (left = strchr (next, '`')) != NULL; next = right + 1) { /* We found the first `. Copy the plain part. */ len = left - next; size -= len; if (size <= 0) { goto error; } strncpy (cp, next, len); cp += len; right = strchr (left + 1, '`'); if (right == NULL) { /* No second `. */ break; } /* Now we get the second `. */ len = right - left; command = alloca (len); strncpy (command, left + 1, len - 1); command [len - 1] = '\0'; *cp = '\0'; tmp = expand_command (buf, command); if (tmp) { len = strlen (tmp); size -= len; if (size <= 0) { goto error; } strncpy (cp, tmp, len); cp += len; } else { /* We don't know how to deal with it. Just copy it for now. */ size -= len + 1; if (size <= 0) { goto error; } strncpy (cp, left, len + 1); cp += len + 1; } } if (right) { /* We are done. Copy the rest. */ strncpy (cp, next, size - 1); } else { /* No second `. Copy the rest. */ strncpy (cp, left, size - 1); } buf [size - 1] = '\0'; return buf; error: /* We don't do anything. */ return (char *) str; } /* * This function concatenates lines terminated by '\\' and increases "lines" * accordingly. If "src" there is no source or the source is empty, we * return NULL. Otherwise we are returning the end of parsing. * The result is placed in "src"! lines is adjusted to the number of lines * read. */ char * get_concat_line (char *src, int *lines) { char *tmp; if (!src) /* nothing to be processed */ return NULL; tmp = src; if (!*tmp) return NULL; while (*src && (*src != '\n')) { if (src[0] == '\\' && src[1] == '\n') { ++*lines; ++src; *src = '*'; /* fake it for the next loop */ --tmp; } else *tmp = *src; ++src; ++tmp; } *tmp = '\0'; ++*lines; return src + 1; } /*=================================================================*/ /* * Error logging facilities. */ int log; /* this is passed to insmod */ static int silent; static int errors; static const char *error_file; void error (const char *fmt,...) { va_list args; if (silent) ; else if (log) { char buf[1024]; int n; n = snprintf (buf, sizeof (buf), "%s: ", error_file ? error_file : "insmod"); va_start (args, fmt); vsnprintf (buf + n, sizeof (buf) - n, fmt, args); va_end (args); syslog (LOG_ERR, "%s", buf); } else { fprintf (stderr, "%s: ", error_file ? error_file : "modprobe"); va_start (args, fmt); vfprintf (stderr, fmt, args); va_end (args); putc ('\n', stderr); } errors++; } void lprintf (const char *fmt,...) { va_list args; if (silent) ; else if (log) { char buf[1024]; va_start (args, fmt); vsnprintf (buf, sizeof (buf), fmt, args); va_end (args); syslog (LOG_INFO, "%s", buf); } else { va_start (args, fmt); vfprintf (stdout, fmt, args); va_end (args); putchar ('\n'); } } void setsyslog (const char *program) { openlog (program, LOG_CONS, LOG_DAEMON); log = 1; }