X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Futils.c;h=e75bb9c8eecd21279a999c18f8c0bc4f132ef1e3;hp=eb771a540c118cad770548a64b9cadfa61f85211;hb=HEAD;hpb=c44ae5e6a7338c96eb463881fe709b2dfaffe568 diff --git a/pppd/utils.c b/pppd/utils.c index eb771a5..bf9923c 100644 --- a/pppd/utils.c +++ b/pppd/utils.c @@ -17,7 +17,7 @@ * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras - * ". + * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY @@ -28,8 +28,11 @@ * 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 #include #include #include @@ -55,20 +58,20 @@ #include #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 *)""; 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