source: rtems/cpukit/pppd/utils.c @ ed92e28

4.104.114.84.95
Last change on this file since ed92e28 was d08e825b, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/27/07 at 15:47:35

Eliminate P().

  • Property mode set to 100644
File size: 16.5 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(buf, buflen, fmt, args)
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    unsigned long val = 0;
106    char *str, *f, *buf0;
107    unsigned char *p;
108    char num[32];
109    time_t t;
110    u_int32_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 = (unsigned long) 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, u_int32_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(p, len, prefix, level)
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(p, len, printer, arg)
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(p_arg, len, printer, arg)
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(level, fmt, args)
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(dev)
666    char *dev;
667{
668#ifdef LOCKLIB
669    int result;
670
671    result = mklock (dev, (void *) 0);
672    if (result == 0) {
673        strlcpy(lock_file, sizeof(lock_file), dev);
674        return 0;
675    }
676
677    if (result > 0)
678        notice("Device %s is locked by pid %d", dev, result);
679    else
680        error("Can't create lock file %s", lock_file);
681    return -1;
682
683#else /* LOCKLIB */
684
685    char lock_buffer[12];
686    int fd, pid, n;
687
688#ifdef SVR4
689    struct stat sbuf;
690
691    if (stat(dev, &sbuf) < 0) {
692        error("Can't get device number for %s: %m", dev);
693        return -1;
694    }
695    if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
696        error("Can't lock %s: not a character device", dev);
697        return -1;
698    }
699    slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
700             LOCK_DIR, major(sbuf.st_dev),
701             major(sbuf.st_rdev), minor(sbuf.st_rdev));
702#else
703    char *p;
704
705    if ((p = strrchr(dev, '/')) != NULL)
706        dev = p + 1;
707    slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
708#endif
709
710    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
711        if (errno != EEXIST) {
712            error("Can't create lock file %s: %m", lock_file);
713            break;
714        }
715
716        /* Read the lock file to find out who has the device locked. */
717        fd = open(lock_file, O_RDONLY, 0);
718        if (fd < 0) {
719            if (errno == ENOENT) /* This is just a timing problem. */
720                continue;
721            error("Can't open existing lock file %s: %m", lock_file);
722            break;
723        }
724#ifndef LOCK_BINARY
725        n = read(fd, lock_buffer, 11);
726#else
727        n = read(fd, &pid, sizeof(pid));
728#endif /* LOCK_BINARY */
729        close(fd);
730        fd = -1;
731        if (n <= 0) {
732            error("Can't read pid from lock file %s", lock_file);
733            break;
734        }
735
736        /* See if the process still exists. */
737#ifndef LOCK_BINARY
738        lock_buffer[n] = 0;
739        pid = atoi(lock_buffer);
740#endif /* LOCK_BINARY */
741        if (pid == getpid())
742            return 1;           /* somebody else locked it for us */
743        if (pid == 0
744            || (kill(pid, 0) == -1 && errno == ESRCH)) {
745            if (unlink (lock_file) == 0) {
746                notice("Removed stale lock on %s (pid %d)", dev, pid);
747                continue;
748            }
749            warn("Couldn't remove stale lock on %s", dev);
750        } else
751            notice("Device %s is locked by pid %d", dev, pid);
752        break;
753    }
754
755    if (fd < 0) {
756        lock_file[0] = 0;
757        return -1;
758    }
759
760    pid = getpid();
761#ifndef LOCK_BINARY
762    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
763    write (fd, lock_buffer, 11);
764#else
765    write(fd, &pid, sizeof (pid));
766#endif
767    close(fd);
768    return 0;
769
770#endif
771}
772
773/*
774 * relock - called to update our lockfile when we are about to detach,
775 * thus changing our pid (we fork, the child carries on, and the parent dies).
776 * Note that this is called by the parent, with pid equal to the pid
777 * of the child.  This avoids a potential race which would exist if
778 * we had the child rewrite the lockfile (the parent might die first,
779 * and another process could think the lock was stale if it checked
780 * between when the parent died and the child rewrote the lockfile).
781 */
782int
783relock(pid)
784    int pid;
785{
786#ifdef LOCKLIB
787    /* XXX is there a way to do this? */
788    return -1;
789#else /* LOCKLIB */
790
791    int fd;
792    char lock_buffer[12];
793
794    if (lock_file[0] == 0)
795        return -1;
796    fd = open(lock_file, O_WRONLY, 0);
797    if (fd < 0) {
798        error("Couldn't reopen lock file %s: %m", lock_file);
799        lock_file[0] = 0;
800        return -1;
801    }
802
803#ifndef LOCK_BINARY
804    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
805    write (fd, lock_buffer, 11);
806#else
807    write(fd, &pid, sizeof(pid));
808#endif /* LOCK_BINARY */
809    close(fd);
810    return 0;
811
812#endif /* LOCKLIB */
813}
814
815/*
816 * unlock - remove our lockfile
817 */
818void
819unlock()
820{
821    if (lock_file[0]) {
822#ifdef LOCKLIB
823        (void) rmlock(lock_file, (void *) 0);
824#else
825        unlink(lock_file);
826#endif
827        lock_file[0] = 0;
828    }
829}
Note: See TracBrowser for help on using the repository browser.