source: rtems-libbsd/rtemsbsd/pppd/utils.c @ f0aaa04

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f0aaa04 was 70fa95a, checked in by Sebastian Huber <sebastian.huber@…>, on 09/30/14 at 12:46:12

ppp: Import from RTEMS sources

  • Property mode set to 100644
File size: 16.3 KB
Line 
1/*
2 * utils.c - various utility functions used in pppd.
3 *
4 * Copyright (c) 1999 The Australian National University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by the Australian National University.  The name of the University
13 * may not be used to endorse or promote products derived from this
14 * software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20#define RCSID   "$Id$"
21
22#include <stdio.h>
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <signal.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <netdb.h>
31#include <syslog.h>
32#include <pwd.h>
33#include <sys/param.h>
34#include <sys/types.h>
35#include <sys/wait.h>
36#include <sys/time.h>
37#include <sys/resource.h>
38#include <sys/stat.h>
39#include <sys/socket.h>
40#include <netinet/in.h>
41#ifdef SVR4
42#include <sys/mkdev.h>
43#endif
44
45#include "pppd.h"
46
47static const char rcsid[] = RCSID;
48
49static void pr_log(void *, char *, ...);
50static void logit(int, char *, va_list);
51static void vslp_printer(void *, char *, ...);
52static void format_packet(u_char *, int, void (*) (void *, char *, ...),
53                               void *);
54
55struct buffer_info {
56    char *ptr;
57    int len;
58};
59
60/*
61 * slprintf - format a message into a buffer.  Like sprintf except we
62 * also specify the length of the output buffer, and we handle
63 * %r (recursive format), %m (error message), %v (visible string),
64 * %q (quoted string), %t (current time) and %I (IP address) formats.
65 * Doesn't do floating-point formats.
66 * Returns the number of chars put into buf.
67 */
68int
69slprintf __V((char *buf, int buflen, char *fmt, ...))
70{
71    va_list args;
72    int n;
73
74#if defined(__STDC__)
75    va_start(args, fmt);
76#else
77    char *buf;
78    int buflen;
79    char *fmt;
80    va_start(args);
81    buf = va_arg(args, char *);
82    buflen = va_arg(args, int);
83    fmt = va_arg(args, char *);
84#endif
85    n = vslprintf(buf, buflen, fmt, args);
86    va_end(args);
87    return n;
88}
89
90/*
91 * vslprintf - like slprintf, takes a va_list instead of a list of args.
92 */
93#define OUTCHAR(c)      (buflen > 0? (--buflen, *buf++ = (c)): 0)
94
95int
96vslprintf(
97    char *buf,
98    int buflen,
99    char *fmt,
100    va_list args)
101{
102    int c, i, n;
103    int width, prec, fillch;
104    int base, len, neg, quoted;
105    uintptr_t val = 0;
106    char *str, *f, *buf0;
107    unsigned char *p;
108    char num[32];
109    time_t t;
110    uint32_t ip;
111    static char hexchars[] = "0123456789abcdef";
112    struct buffer_info bufinfo;
113
114    buf0 = buf;
115    --buflen;
116    while (buflen > 0) {
117        for (f = fmt; *f != '%' && *f != 0; ++f)
118            ;
119        if (f > fmt) {
120            len = f - fmt;
121            if (len > buflen)
122                len = buflen;
123            memcpy(buf, fmt, len);
124            buf += len;
125            buflen -= len;
126            fmt = f;
127        }
128        if (*fmt == 0)
129            break;
130        c = *++fmt;
131        width = 0;
132        prec = -1;
133        fillch = ' ';
134        if (c == '0') {
135            fillch = '0';
136            c = *++fmt;
137        }
138        if (c == '*') {
139            width = va_arg(args, int);
140            c = *++fmt;
141        } else {
142            while (isdigit(c)) {
143                width = width * 10 + c - '0';
144                c = *++fmt;
145            }
146        }
147        if (c == '.') {
148            c = *++fmt;
149            if (c == '*') {
150                prec = va_arg(args, int);
151                c = *++fmt;
152            } else {
153                prec = 0;
154                while (isdigit(c)) {
155                    prec = prec * 10 + c - '0';
156                    c = *++fmt;
157                }
158            }
159        }
160        str = 0;
161        base = 0;
162        neg = 0;
163        ++fmt;
164        switch (c) {
165        case 'd':
166            i = va_arg(args, int);
167            if (i < 0) {
168                neg = 1;
169                val = -i;
170            } else
171                val = i;
172            base = 10;
173            break;
174        case 'o':
175            val = va_arg(args, unsigned int);
176            base = 8;
177            break;
178        case 'x':
179        case 'X':
180            val = va_arg(args, unsigned int);
181            base = 16;
182            break;
183        case 'p':
184            val = (uintptr_t) va_arg(args, void *);
185            base = 16;
186            neg = 2;
187            break;
188        case 's':
189            str = va_arg(args, char *);
190            break;
191        case 'c':
192            num[0] = va_arg(args, int);
193            num[1] = 0;
194            str = num;
195            break;
196        case 'm':
197            str = strerror(errno);
198            break;
199        case 'I':
200            ip = va_arg(args, uint32_t);
201            ip = ntohl(ip);
202            slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
203                     (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
204            str = num;
205            break;
206        case 'r':
207            f = va_arg(args, char *);
208#if !defined(__PPC__)
209            n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
210#else
211            /* HACK: On the powerpc, a va_list is an array of 1 structure */
212            n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
213#endif
214            buf += n;
215            buflen -= n;
216            continue;
217        case 't':
218            time(&t);
219            str = ctime(&t);
220            str += 4;           /* chop off the day name */
221            str[15] = 0;        /* chop off year and newline */
222            break;
223        case 'v':               /* "visible" string */
224        case 'q':               /* quoted string */
225            quoted = c == 'q';
226            p = va_arg(args, unsigned char *);
227            if (fillch == '0' && prec >= 0) {
228                n = prec;
229            } else {
230                n = strlen((char *)p);
231                if (prec >= 0 && n > prec)
232                    n = prec;
233            }
234            while (n > 0 && buflen > 0) {
235                c = *p++;
236                --n;
237                if (!quoted && c >= 0x80) {
238                    OUTCHAR('M');
239                    OUTCHAR('-');
240                    c -= 0x80;
241                }
242                if (quoted && (c == '"' || c == '\\'))
243                    OUTCHAR('\\');
244                if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
245                    if (quoted) {
246                        OUTCHAR('\\');
247                        switch (c) {
248                        case '\t':      OUTCHAR('t');   break;
249                        case '\n':      OUTCHAR('n');   break;
250                        case '\b':      OUTCHAR('b');   break;
251                        case '\f':      OUTCHAR('f');   break;
252                        default:
253                            OUTCHAR('x');
254                            OUTCHAR(hexchars[c >> 4]);
255                            OUTCHAR(hexchars[c & 0xf]);
256                        }
257                    } else {
258                        if (c == '\t')
259                            OUTCHAR(c);
260                        else {
261                            OUTCHAR('^');
262                            OUTCHAR(c ^ 0x40);
263                        }
264                    }
265                } else
266                    OUTCHAR(c);
267            }
268            continue;
269        case 'P':               /* print PPP packet */
270            bufinfo.ptr = buf;
271            bufinfo.len = buflen + 1;
272            p = va_arg(args, unsigned char *);
273            n = va_arg(args, int);
274            format_packet(p, n, vslp_printer, &bufinfo);
275            buf = bufinfo.ptr;
276            buflen = bufinfo.len - 1;
277            continue;
278        case 'B':
279            p = va_arg(args, unsigned char *);
280            for (n = prec; n > 0; --n) {
281                c = *p++;
282                if (fillch == ' ')
283                    OUTCHAR(' ');
284                OUTCHAR(hexchars[(c >> 4) & 0xf]);
285                OUTCHAR(hexchars[c & 0xf]);
286            }
287            continue;
288        default:
289            *buf++ = '%';
290            if (c != '%')
291                --fmt;          /* so %z outputs %z etc. */
292            --buflen;
293            continue;
294        }
295        if (base != 0) {
296            str = num + sizeof(num);
297            *--str = 0;
298            while (str > num + neg) {
299                *--str = hexchars[val % base];
300                val = val / base;
301                if (--prec <= 0 && val == 0)
302                    break;
303            }
304            switch (neg) {
305            case 1:
306                *--str = '-';
307                break;
308            case 2:
309                *--str = 'x';
310                *--str = '0';
311                break;
312            }
313            len = num + sizeof(num) - 1 - str;
314        } else {
315            len = strlen(str);
316            if (prec >= 0 && len > prec)
317                len = prec;
318        }
319        if (width > 0) {
320            if (width > buflen)
321                width = buflen;
322            if ((n = width - len) > 0) {
323                buflen -= n;
324                for (; n > 0; --n)
325                    *buf++ = fillch;
326            }
327        }
328        if (len > buflen)
329            len = buflen;
330        memcpy(buf, str, len);
331        buf += len;
332        buflen -= len;
333    }
334    *buf = 0;
335    return buf - buf0;
336}
337
338/*
339 * vslp_printer - used in processing a %P format
340 */
341static void
342vslp_printer __V((void *arg, char *fmt, ...))
343{
344    int n;
345    va_list pvar;
346    struct buffer_info *bi;
347
348#if defined(__STDC__)
349    va_start(pvar, fmt);
350#else
351    void *arg;
352    char *fmt;
353    va_start(pvar);
354    arg = va_arg(pvar, void *);
355    fmt = va_arg(pvar, char *);
356#endif
357
358    bi = (struct buffer_info *) arg;
359    n = vslprintf(bi->ptr, bi->len, fmt, pvar);
360    va_end(pvar);
361
362    bi->ptr += n;
363    bi->len -= n;
364}
365
366/*
367 * log_packet - format a packet and log it.
368 */
369
370char line[256];                 /* line to be logged accumulated here */
371char *linep;
372
373void
374log_packet(
375    u_char *p,
376    int len,
377    char *prefix,
378    int level)
379{
380    strlcpy(line, prefix, sizeof(line));
381    linep = line + strlen(line);
382    format_packet(p, len, pr_log, NULL);
383}
384
385/*
386 * format_packet - make a readable representation of a packet,
387 * calling `printer(arg, format, ...)' to output it.
388 */
389static void
390format_packet(
391    u_char *p,
392    int len,
393    void (*printer)(void *, char *, ...),
394    void *arg)
395{
396    int i, n;
397    u_short proto;
398    struct protent *protp;
399
400    if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
401        p += 2;
402        GETSHORT(proto, p);
403        len -= PPP_HDRLEN;
404        for (i = 0; (protp = protocols[i]) != NULL; ++i)
405            if (proto == protp->protocol)
406                break;
407        if (protp != NULL) {
408            printer(arg, "[%s", protp->name);
409            n = (*protp->printpkt)(p, len, printer, arg);
410            printer(arg, "]");
411            p += n;
412            len -= n;
413        } else {
414            for (i = 0; (protp = protocols[i]) != NULL; ++i)
415                if (proto == (protp->protocol & ~0x8000))
416                    break;
417            if (protp != 0 && protp->data_name != 0) {
418                printer(arg, "[%s data]", protp->data_name);
419                if (len > 8)
420                    printer(arg, "%.8B ...", p);
421                else
422                    printer(arg, "%.*B", len, p);
423                len = 0;
424            } else
425                printer(arg, "[proto=0x%x]", proto);
426        }
427    }
428
429    if (len > 32)
430        printer(arg, "%.32B ...", p);
431    else
432        printer(arg, "%.*B", len, p);
433}
434
435static void
436pr_log __V((void *arg, char *fmt, ...))
437{
438    int n;
439    va_list pvar;
440    char buf[256];
441
442#if defined(__STDC__)
443    va_start(pvar, fmt);
444#else
445    void *arg;
446    char *fmt;
447    va_start(pvar);
448    arg = va_arg(pvar, void *);
449    fmt = va_arg(pvar, char *);
450#endif
451
452    n = vslprintf(buf, sizeof(buf), fmt, pvar);
453    va_end(pvar);
454
455    if (linep + n + 1 > line + sizeof(line)) {
456        linep = line;
457    }
458    strlcpy(linep, buf, line + sizeof(line) - linep);
459    linep += n;
460}
461
462/*
463 * print_string - print a readable representation of a string using
464 * printer.
465 */
466void
467print_string(
468    void *p_arg,
469    int len,
470    void (*printer)(void *, char *, ...),
471    void *arg)
472{
473    int c;
474    unsigned char *p = (unsigned char *)p_arg;
475
476    printer(arg, "\"");
477    for (; len > 0; --len) {
478        c = *p++;
479        if (' ' <= c && c <= '~') {
480            if (c == '\\' || c == '"')
481                printer(arg, "\\");
482            printer(arg, "%c", c);
483        } else {
484            switch (c) {
485            case '\n':
486                printer(arg, "\\n");
487                break;
488            case '\r':
489                printer(arg, "\\r");
490                break;
491            case '\t':
492                printer(arg, "\\t");
493                break;
494            default:
495                printer(arg, "\\%.3o", c);
496            }
497        }
498    }
499    printer(arg, "\"");
500}
501
502/*
503 * logit - does the hard work for fatal et al.
504 */
505static void
506logit(
507    int level,
508    char *fmt,
509    va_list args)
510{
511    int n;
512    char buf[256];
513
514    n = vslprintf(buf, sizeof(buf), fmt, args);
515/*    if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { */
516    if (log_to_fd >= 0 && (debug)) {
517        if (buf[n-1] != '\n')
518            buf[n++] = '\n';
519        if (write(log_to_fd, buf, n) != n)
520            log_to_fd = -1;
521    }
522}
523
524/*
525 * fatal - log an error message and die horribly.
526 */
527void
528pppd_fatal __V((char *fmt, ...))
529{
530    va_list pvar;
531
532#if defined(__STDC__)
533    va_start(pvar, fmt);
534#else
535    char *fmt;
536    va_start(pvar);
537    fmt = va_arg(pvar, char *);
538#endif
539
540    logit(LOG_ERR, fmt, pvar);
541    va_end(pvar);
542
543    die(1);                     /* as promised */
544}
545
546/*
547 * error - log an error message.
548 */
549void
550pppd_error __V((char *fmt, ...))
551{
552    va_list pvar;
553
554#if defined(__STDC__)
555    va_start(pvar, fmt);
556#else
557    char *fmt;
558    va_start(pvar);
559    fmt = va_arg(pvar, char *);
560#endif
561
562    logit(LOG_ERR, fmt, pvar);
563    va_end(pvar);
564}
565
566/*
567 * warn - log a warning message.
568 */
569void
570pppd_warn __V((char *fmt, ...))
571{
572    va_list pvar;
573
574#if defined(__STDC__)
575    va_start(pvar, fmt);
576#else
577    char *fmt;
578    va_start(pvar);
579    fmt = va_arg(pvar, char *);
580#endif
581
582    logit(LOG_WARNING, fmt, pvar);
583    va_end(pvar);
584}
585
586/*
587 * notice - log a notice-level message.
588 */
589void
590pppd_notice __V((char *fmt, ...))
591{
592    va_list pvar;
593
594#if defined(__STDC__)
595    va_start(pvar, fmt);
596#else
597    char *fmt;
598    va_start(pvar);
599    fmt = va_arg(pvar, char *);
600#endif
601
602    logit(LOG_NOTICE, fmt, pvar);
603    va_end(pvar);
604}
605
606/*
607 * info - log an informational message.
608 */
609void
610pppd_info __V((char *fmt, ...))
611{
612    va_list pvar;
613
614#if defined(__STDC__)
615    va_start(pvar, fmt);
616#else
617    char *fmt;
618    va_start(pvar);
619    fmt = va_arg(pvar, char *);
620#endif
621
622    logit(LOG_INFO, fmt, pvar);
623    va_end(pvar);
624}
625
626/*
627 * dbglog - log a debug message.
628 */
629void
630pppd_dbglog __V((char *fmt, ...))
631{
632    va_list pvar;
633
634#if defined(__STDC__)
635    va_start(pvar, fmt);
636#else
637    char *fmt;
638    va_start(pvar);
639    fmt = va_arg(pvar, char *);
640#endif
641
642    logit(LOG_DEBUG, fmt, pvar);
643    va_end(pvar);
644}
645
646/* Procedures for locking the serial device using a lock file. */
647#ifndef LOCK_DIR
648#ifdef _linux_
649#define LOCK_DIR        "/var/lock"
650#else
651#ifdef SVR4
652#define LOCK_DIR        "/var/spool/locks"
653#else
654#define LOCK_DIR        "/var/spool/lock"
655#endif
656#endif
657#endif /* LOCK_DIR */
658
659static char lock_file[MAXPATHLEN];
660
661/*
662 * lock - create a lock file for the named device
663 */
664int
665lock(char *dev)
666{
667#ifdef LOCKLIB
668    int result;
669
670    result = mklock (dev, (void *) 0);
671    if (result == 0) {
672        strlcpy(lock_file, sizeof(lock_file), dev);
673        return 0;
674    }
675
676    if (result > 0)
677        notice("Device %s is locked by pid %d", dev, result);
678    else
679        error("Can't create lock file %s", lock_file);
680    return -1;
681
682#else /* LOCKLIB */
683
684    char lock_buffer[12];
685    int fd, pid, n;
686
687#ifdef SVR4
688    struct stat sbuf;
689
690    if (stat(dev, &sbuf) < 0) {
691        error("Can't get device number for %s: %m", dev);
692        return -1;
693    }
694    if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
695        error("Can't lock %s: not a character device", dev);
696        return -1;
697    }
698    slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
699             LOCK_DIR, major(sbuf.st_dev),
700             major(sbuf.st_rdev), minor(sbuf.st_rdev));
701#else
702    char *p;
703
704    if ((p = strrchr(dev, '/')) != NULL)
705        dev = p + 1;
706    slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
707#endif
708
709    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
710        if (errno != EEXIST) {
711            error("Can't create lock file %s: %m", lock_file);
712            break;
713        }
714
715        /* Read the lock file to find out who has the device locked. */
716        fd = open(lock_file, O_RDONLY, 0);
717        if (fd < 0) {
718            if (errno == ENOENT) /* This is just a timing problem. */
719                continue;
720            error("Can't open existing lock file %s: %m", lock_file);
721            break;
722        }
723#ifndef LOCK_BINARY
724        n = read(fd, lock_buffer, 11);
725#else
726        n = read(fd, &pid, sizeof(pid));
727#endif /* LOCK_BINARY */
728        close(fd);
729        fd = -1;
730        if (n <= 0) {
731            error("Can't read pid from lock file %s", lock_file);
732            break;
733        }
734
735        /* See if the process still exists. */
736#ifndef LOCK_BINARY
737        lock_buffer[n] = 0;
738        pid = atoi(lock_buffer);
739#endif /* LOCK_BINARY */
740        if (pid == getpid())
741            return 1;           /* somebody else locked it for us */
742        if (pid == 0
743            || (kill(pid, 0) == -1 && errno == ESRCH)) {
744            if (unlink (lock_file) == 0) {
745                notice("Removed stale lock on %s (pid %d)", dev, pid);
746                continue;
747            }
748            warn("Couldn't remove stale lock on %s", dev);
749        } else
750            notice("Device %s is locked by pid %d", dev, pid);
751        break;
752    }
753
754    if (fd < 0) {
755        lock_file[0] = 0;
756        return -1;
757    }
758
759    pid = getpid();
760#ifndef LOCK_BINARY
761    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
762    write (fd, lock_buffer, 11);
763#else
764    write(fd, &pid, sizeof (pid));
765#endif
766    close(fd);
767    return 0;
768
769#endif
770}
771
772/*
773 * relock - called to update our lockfile when we are about to detach,
774 * thus changing our pid (we fork, the child carries on, and the parent dies).
775 * Note that this is called by the parent, with pid equal to the pid
776 * of the child.  This avoids a potential race which would exist if
777 * we had the child rewrite the lockfile (the parent might die first,
778 * and another process could think the lock was stale if it checked
779 * between when the parent died and the child rewrote the lockfile).
780 */
781int
782relock(int pid)
783{
784#ifdef LOCKLIB
785    /* XXX is there a way to do this? */
786    return -1;
787#else /* LOCKLIB */
788
789    int fd;
790    char lock_buffer[12];
791
792    if (lock_file[0] == 0)
793        return -1;
794    fd = open(lock_file, O_WRONLY, 0);
795    if (fd < 0) {
796        error("Couldn't reopen lock file %s: %m", lock_file);
797        lock_file[0] = 0;
798        return -1;
799    }
800
801#ifndef LOCK_BINARY
802    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
803    write (fd, lock_buffer, 11);
804#else
805    write(fd, &pid, sizeof(pid));
806#endif /* LOCK_BINARY */
807    close(fd);
808    return 0;
809
810#endif /* LOCKLIB */
811}
812
813/*
814 * unlock - remove our lockfile
815 */
816void
817unlock(void)
818{
819    if (lock_file[0]) {
820#ifdef LOCKLIB
821        (void) rmlock(lock_file, (void *) 0);
822#else
823        unlink(lock_file);
824#endif
825        lock_file[0] = 0;
826    }
827}
Note: See TracBrowser for help on using the repository browser.