]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/utils.c
pppd.8: Document netmask option
[ppp.git] / pppd / utils.c
index eb771a540c118cad770548a64b9cadfa61f85211..bf9923ce362224d8c2095648b37202587f51f777 100644 (file)
@@ -17,7 +17,7 @@
  * 3. Redistributions of any form whatsoever must retain the following
  *    acknowledgment:
  *    "This product includes software developed by Paul Mackerras
- *     <paulus@samba.org>".
+ *     <paulus@ozlabs.org>".
  *
  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: utils.c,v 1.25 2008/06/03 12:06:37 paulus Exp $"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <sys/mkdev.h>
 #endif
 
-#include "pppd.h"
+#include "pppd-private.h"
 #include "fsm.h"
 #include "lcp.h"
+#include "pathnames.h"
 
-static const char rcsid[] = RCSID;
 
 #if defined(SUNOS4)
 extern char *strerror();
 #endif
 
-static void logit __P((int, char *, va_list));
-static void log_write __P((int, char *));
-static void vslp_printer __P((void *, char *, ...));
-static void format_packet __P((u_char *, int, printer_func, void *));
+static void logit(int, const char *, va_list);
+static void log_write(int, char *);
+static void vslp_printer(void *, char *, ...);
+static void format_packet(u_char *, int, printer_func, void *);
 
 struct buffer_info {
     char *ptr;
@@ -80,10 +83,7 @@ struct buffer_info {
  * always leaves destination null-terminated (for len > 0).
  */
 size_t
-strlcpy(dest, src, len)
-    char *dest;
-    const char *src;
-    size_t len;
+strlcpy(char *dest, const char *src, size_t len)
 {
     size_t ret = strlen(src);
 
@@ -103,10 +103,7 @@ strlcpy(dest, src, len)
  * always leaves destination null-terminated (for len > 0).
  */
 size_t
-strlcat(dest, src, len)
-    char *dest;
-    const char *src;
-    size_t len;
+strlcat(char *dest, const char *src, size_t len)
 {
     size_t dlen = strlen(dest);
 
@@ -123,22 +120,12 @@ strlcat(dest, src, len)
  * Returns the number of chars put into buf.
  */
 int
-slprintf __V((char *buf, int buflen, char *fmt, ...))
+slprintf(char *buf, int buflen, const char *fmt, ...)
 {
     va_list args;
     int n;
 
-#if defined(__STDC__)
     va_start(args, fmt);
-#else
-    char *buf;
-    int buflen;
-    char *fmt;
-    va_start(args);
-    buf = va_arg(args, char *);
-    buflen = va_arg(args, int);
-    fmt = va_arg(args, char *);
-#endif
     n = vslprintf(buf, buflen, fmt, args);
     va_end(args);
     return n;
@@ -150,23 +137,22 @@ slprintf __V((char *buf, int buflen, char *fmt, ...))
 #define OUTCHAR(c)     (buflen > 0? (--buflen, *buf++ = (c)): 0)
 
 int
-vslprintf(buf, buflen, fmt, args)
-    char *buf;
-    int buflen;
-    char *fmt;
-    va_list args;
+vslprintf(char *buf, int buflen, const char *fmt, va_list args)
 {
     int c, i, n;
     int width, prec, fillch;
     int base, len, neg, quoted;
+    long lval = 0;
     unsigned long val = 0;
-    char *str, *f, *buf0;
+    char *str, *buf0;
+    const char *f;
     unsigned char *p;
     char num[32];
     time_t t;
     u_int32_t ip;
     static char hexchars[] = "0123456789abcdef";
     struct buffer_info bufinfo;
+    int termch;
 
     buf0 = buf;
     --buflen;
@@ -223,11 +209,12 @@ vslprintf(buf, buflen, fmt, args)
            c = *fmt++;
            switch (c) {
            case 'd':
-               val = va_arg(args, long);
-               if (val < 0) {
+               lval = va_arg(args, long);
+               if (lval < 0) {
                    neg = 1;
-                   val = -val;
-               }
+                   val = -lval;
+               } else
+                   val = lval;
                base = 10;
                break;
            case 'u':
@@ -286,19 +273,6 @@ vslprintf(buf, buflen, fmt, args)
                     (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
            str = num;
            break;
-#if 0  /* not used, and breaks on S/390, apparently */
-       case 'r':
-           f = va_arg(args, char *);
-#ifndef __powerpc__
-           n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
-#else
-           /* On the powerpc, a va_list is an array of 1 structure */
-           n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
-#endif
-           buf += n;
-           buflen -= n;
-           continue;
-#endif
        case 't':
            time(&t);
            str = ctime(&t);
@@ -309,15 +283,21 @@ vslprintf(buf, buflen, fmt, args)
        case 'q':               /* quoted string */
            quoted = c == 'q';
            p = va_arg(args, unsigned char *);
+           if (p == NULL)
+                   p = (unsigned char *)"<NULL>";
            if (fillch == '0' && prec >= 0) {
                n = prec;
+               termch = -1;    /* matches no unsigned char value */
            } else {
-               n = strlen((char *)p);
-               if (prec >= 0 && n > prec)
+               n = buflen;
+               if (prec != -1 && n > prec)
                    n = prec;
+               termch = 0;     /* stop on null byte */
            }
            while (n > 0 && buflen > 0) {
                c = *p++;
+               if (c == termch)
+                   break;
                --n;
                if (!quoted && c >= 0x80) {
                    OUTCHAR('M');
@@ -351,6 +331,7 @@ vslprintf(buf, buflen, fmt, args)
                    OUTCHAR(c);
            }
            continue;
+#ifndef UNIT_TEST
        case 'P':               /* print PPP packet */
            bufinfo.ptr = buf;
            bufinfo.len = buflen + 1;
@@ -360,6 +341,7 @@ vslprintf(buf, buflen, fmt, args)
            buf = bufinfo.ptr;
            buflen = bufinfo.len - 1;
            continue;
+#endif
        case 'B':
            p = va_arg(args, unsigned char *);
            for (n = prec; n > 0; --n) {
@@ -397,9 +379,9 @@ vslprintf(buf, buflen, fmt, args)
            }
            len = num + sizeof(num) - 1 - str;
        } else {
-           len = strlen(str);
-           if (prec >= 0 && len > prec)
-               len = prec;
+           for (len = 0; len < buflen && (prec == -1 || len < prec); ++len)
+               if (str[len] == 0)
+                   break;
        }
        if (width > 0) {
            if (width > buflen)
@@ -424,21 +406,13 @@ vslprintf(buf, buflen, fmt, args)
  * vslp_printer - used in processing a %P format
  */
 static void
-vslp_printer __V((void *arg, char *fmt, ...))
+vslp_printer(void *arg, char *fmt, ...)
 {
     int n;
     va_list pvar;
     struct buffer_info *bi;
 
-#if defined(__STDC__)
     va_start(pvar, fmt);
-#else
-    void *arg;
-    char *fmt;
-    va_start(pvar);
-    arg = va_arg(pvar, void *);
-    fmt = va_arg(pvar, char *);
-#endif
 
     bi = (struct buffer_info *) arg;
     n = vslprintf(bi->ptr, bi->len, fmt, pvar);
@@ -454,11 +428,7 @@ vslp_printer __V((void *arg, char *fmt, ...))
  */
 
 void
-log_packet(p, len, prefix, level)
-    u_char *p;
-    int len;
-    char *prefix;
-    int level;
+log_packet(u_char *p, int len, char *prefix, int level)
 {
        init_pr_log(prefix, level);
        format_packet(p, len, pr_log, &level);
@@ -466,16 +436,13 @@ log_packet(p, len, prefix, level)
 }
 #endif /* unused */
 
+#ifndef UNIT_TEST
 /*
  * format_packet - make a readable representation of a packet,
  * calling `printer(arg, format, ...)' to output it.
  */
 static void
-format_packet(p, len, printer, arg)
-    u_char *p;
-    int len;
-    printer_func printer;
-    void *arg;
+format_packet(u_char *p, int len, printer_func printer, void *arg)
 {
     int i, n;
     u_short proto;
@@ -515,6 +482,7 @@ format_packet(p, len, printer, arg)
     else
        printer(arg, "%.*B", len, p);
 }
+#endif  /* UNIT_TEST */
 
 /*
  * init_pr_log, end_pr_log - initialize and finish use of pr_log.
@@ -525,9 +493,7 @@ static char *linep;         /* current pointer within line */
 static int llevel;             /* level for logging */
 
 void
-init_pr_log(prefix, level)
-     const char *prefix;
-     int level;
+init_pr_log(const char *prefix, int level)
 {
        linep = line;
        if (prefix != NULL) {
@@ -538,7 +504,7 @@ init_pr_log(prefix, level)
 }
 
 void
-end_pr_log()
+end_pr_log(void)
 {
        if (linep != line) {
                *linep = 0;
@@ -550,22 +516,14 @@ end_pr_log()
  * pr_log - printer routine for outputting to syslog
  */
 void
-pr_log __V((void *arg, char *fmt, ...))
+pr_log(void *arg, char *fmt, ...)
 {
        int l, n;
        va_list pvar;
        char *p, *eol;
        char buf[256];
 
-#if defined(__STDC__)
        va_start(pvar, fmt);
-#else
-       void *arg;
-       char *fmt;
-       va_start(pvar);
-       arg = va_arg(pvar, void *);
-       fmt = va_arg(pvar, char *);
-#endif
 
        n = vslprintf(buf, sizeof(buf), fmt, pvar);
        va_end(pvar);
@@ -609,11 +567,7 @@ pr_log __V((void *arg, char *fmt, ...))
  * printer.
  */
 void
-print_string(p, len, printer, arg)
-    char *p;
-    int len;
-    printer_func printer;
-    void *arg;
+print_string(char *p, int len, printer_func printer, void *arg)
 {
     int c;
 
@@ -636,7 +590,7 @@ print_string(p, len, printer, arg)
                printer(arg, "\\t");
                break;
            default:
-               printer(arg, "\\%.3o", c);
+               printer(arg, "\\%.3o", (unsigned char) c);
            }
        }
     }
@@ -647,10 +601,7 @@ print_string(p, len, printer, arg)
  * logit - does the hard work for fatal et al.
  */
 static void
-logit(level, fmt, args)
-    int level;
-    char *fmt;
-    va_list args;
+logit(int level, const char *fmt, va_list args)
 {
     char buf[1024];
 
@@ -658,10 +609,9 @@ logit(level, fmt, args)
     log_write(level, buf);
 }
 
+#ifndef UNIT_TEST
 static void
-log_write(level, buf)
-    int level;
-    char *buf;
+log_write(int level, char *buf)
 {
     syslog(level, "%s", buf);
     if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
@@ -674,44 +624,43 @@ log_write(level, buf)
            log_to_fd = -1;
     }
 }
+#else
+static void
+log_write(int level, char *buf)
+{
+    printf("<%d>: %s\n", level, buf);
+}
+#endif
 
 /*
  * fatal - log an error message and die horribly.
  */
 void
-fatal __V((char *fmt, ...))
+fatal(const char *fmt, ...)
 {
     va_list pvar;
 
-#if defined(__STDC__)
     va_start(pvar, fmt);
-#else
-    char *fmt;
-    va_start(pvar);
-    fmt = va_arg(pvar, char *);
-#endif
 
     logit(LOG_ERR, fmt, pvar);
     va_end(pvar);
 
+#ifndef UNIT_TEST
     die(1);                    /* as promised */
+#else
+    exit(-1);
+#endif
 }
 
 /*
  * error - log an error message.
  */
 void
-error __V((char *fmt, ...))
+error(const char *fmt, ...)
 {
     va_list pvar;
 
-#if defined(__STDC__)
     va_start(pvar, fmt);
-#else
-    char *fmt;
-    va_start(pvar);
-    fmt = va_arg(pvar, char *);
-#endif
 
     logit(LOG_ERR, fmt, pvar);
     va_end(pvar);
@@ -722,17 +671,11 @@ error __V((char *fmt, ...))
  * warn - log a warning message.
  */
 void
-warn __V((char *fmt, ...))
+warn(const char *fmt, ...)
 {
     va_list pvar;
 
-#if defined(__STDC__)
     va_start(pvar, fmt);
-#else
-    char *fmt;
-    va_start(pvar);
-    fmt = va_arg(pvar, char *);
-#endif
 
     logit(LOG_WARNING, fmt, pvar);
     va_end(pvar);
@@ -742,17 +685,11 @@ warn __V((char *fmt, ...))
  * notice - log a notice-level message.
  */
 void
-notice __V((char *fmt, ...))
+notice(const char *fmt, ...)
 {
     va_list pvar;
 
-#if defined(__STDC__)
     va_start(pvar, fmt);
-#else
-    char *fmt;
-    va_start(pvar);
-    fmt = va_arg(pvar, char *);
-#endif
 
     logit(LOG_NOTICE, fmt, pvar);
     va_end(pvar);
@@ -762,17 +699,11 @@ notice __V((char *fmt, ...))
  * info - log an informational message.
  */
 void
-info __V((char *fmt, ...))
+info(const char *fmt, ...)
 {
     va_list pvar;
 
-#if defined(__STDC__)
     va_start(pvar, fmt);
-#else
-    char *fmt;
-    va_start(pvar);
-    fmt = va_arg(pvar, char *);
-#endif
 
     logit(LOG_INFO, fmt, pvar);
     va_end(pvar);
@@ -782,17 +713,11 @@ info __V((char *fmt, ...))
  * dbglog - log a debug message.
  */
 void
-dbglog __V((char *fmt, ...))
+dbglog(const char *fmt, ...)
 {
     va_list pvar;
 
-#if defined(__STDC__)
     va_start(pvar, fmt);
-#else
-    char *fmt;
-    va_start(pvar);
-    fmt = va_arg(pvar, char *);
-#endif
 
     logit(LOG_DEBUG, fmt, pvar);
     va_end(pvar);
@@ -828,6 +753,8 @@ dump_packet(const char *tag, unsigned char *p, int len)
     dbglog("%s %P", tag, p, len);
 }
 
+
+#ifndef UNIT_TEST
 /*
  * complete_read - read a full `count' bytes from fd,
  * unless end-of-file or an error other than EINTR is encountered.
@@ -842,7 +769,7 @@ complete_read(int fd, void *buf, size_t count)
        for (done = 0; done < count; ) {
                nb = read(fd, ptr, count - done);
                if (nb < 0) {
-                       if (errno == EINTR)
+                       if (errno == EINTR && !ppp_signaled(SIGTERM))
                                continue;
                        return -1;
                }
@@ -853,28 +780,98 @@ complete_read(int fd, void *buf, size_t count)
        }
        return done;
 }
-
-/* Procedures for locking the serial device using a lock file. */
-#ifndef LOCK_DIR
-#ifdef __linux__
-#define LOCK_DIR       "/var/lock"
-#else
-#ifdef SVR4
-#define LOCK_DIR       "/var/spool/locks"
-#else
-#define LOCK_DIR       "/var/spool/lock"
-#endif
 #endif
-#endif /* LOCK_DIR */
 
+/*
+ * mkdir_check - helper for mkdir_recursive, creates a directory
+ * but do not error on EEXIST if and only if entry is a directory
+ * The caller must check for errno == ENOENT if appropriate.
+ */
+static int
+mkdir_check(const char *path)
+{
+    struct stat statbuf;
+
+    if (mkdir(path, 0755) >= 0)
+       return 0;
+
+    if (errno == EEXIST) {
+       if (stat(path, &statbuf) < 0)
+           /* got raced? */
+           return -1;
+
+       if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+           return 0;
+
+       /* already exists but not a dir, treat as failure */
+       errno = EEXIST;
+       return -1;
+    }
+
+    return -1;
+}
+
+/*
+ * mkdir_parent - helper for mkdir_recursive, modifies the string in place
+ * Assumes mkdir(path) already failed, so it first creates the parent then
+ * full path again.
+ */
+static int
+mkdir_parent(char *path)
+{
+    char *slash;
+    int rc;
+
+    slash = strrchr(path, '/');
+    if (!slash)
+       return -1;
+
+    *slash = 0;
+    if (mkdir_check(path) < 0) {
+       if (errno != ENOENT) {
+           *slash = '/';
+           return -1;
+       }
+       if (mkdir_parent(path) < 0) {
+           *slash = '/';
+           return -1;
+       }
+    }
+    *slash = '/';
+
+    return mkdir_check(path);
+}
+
+/*
+ * mkdir_recursive - recursively create directory if it didn't exist
+ */
+int
+mkdir_recursive(const char *path)
+{
+    char *copy;
+    int rc;
+
+    // optimistically try on full path first to avoid allocation
+    if (mkdir_check(path) == 0)
+       return 0;
+
+    copy = strdup(path);
+    if (!copy)
+       return -1;
+
+    rc = mkdir_parent(copy);
+    free(copy);
+    return rc;
+}
+
+/* Procedures for locking the serial device using a lock file. */
 static char lock_file[MAXPATHLEN];
 
 /*
  * lock - create a lock file for the named device
  */
 int
-lock(dev)
-    char *dev;
+lock(char *dev)
 {
 #ifdef LOCKLIB
     int result;
@@ -894,7 +891,7 @@ lock(dev)
 #else /* LOCKLIB */
 
     char lock_buffer[12];
-    int fd, pid, n;
+    int fd, pid, n, siz;
 
 #ifdef SVR4
     struct stat sbuf;
@@ -908,7 +905,7 @@ lock(dev)
        return -1;
     }
     slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
-            LOCK_DIR, major(sbuf.st_dev),
+            PPP_PATH_LOCKDIR, major(sbuf.st_dev),
             major(sbuf.st_rdev), minor(sbuf.st_rdev));
 #else
     char *p;
@@ -926,7 +923,7 @@ lock(dev)
        if ((p = strrchr(dev, '/')) != NULL)
            dev = p + 1;
 
-    slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
+    slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", PPP_PATH_LOCKDIR, dev);
 #endif
 
     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
@@ -981,11 +978,16 @@ lock(dev)
 
     pid = getpid();
 #ifndef LOCK_BINARY
+    siz = 11;
     slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
-    write (fd, lock_buffer, 11);
+    n = write (fd, lock_buffer, siz);
 #else
-    write(fd, &pid, sizeof (pid));
+    siz = sizeof (pid);
+    n = write(fd, &pid, siz);
 #endif
+    if (n != siz) {
+       error("Could not write pid to lock file when locking");
+    }
     close(fd);
     return 0;
 
@@ -1002,15 +1004,14 @@ lock(dev)
  * between when the parent died and the child rewrote the lockfile).
  */
 int
-relock(pid)
-    int pid;
+relock(int pid)
 {
 #ifdef LOCKLIB
     /* XXX is there a way to do this? */
     return -1;
 #else /* LOCKLIB */
 
-    int fd;
+    int fd, n, siz;
     char lock_buffer[12];
 
     if (lock_file[0] == 0)
@@ -1023,11 +1024,16 @@ relock(pid)
     }
 
 #ifndef LOCK_BINARY
+    siz = 11;
     slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
-    write (fd, lock_buffer, 11);
+    n = write (fd, lock_buffer, siz);
 #else
-    write(fd, &pid, sizeof(pid));
+    siz = sizeof(pid);
+    n = write(fd, &pid, siz);
 #endif /* LOCK_BINARY */
+    if (n != siz) {
+       error("Could not write pid to lock file when locking");
+    }
     close(fd);
     return 0;
 
@@ -1038,7 +1044,7 @@ relock(pid)
  * unlock - remove our lockfile
  */
 void
-unlock()
+unlock(void)
 {
     if (lock_file[0]) {
 #ifdef LOCKLIB