source: rtems/cpukit/pppd/utils.c @ 33a1a4db

5
Last change on this file since 33a1a4db was 33a1a4db, checked in by Peng Fan <van.freenix@…>, on 04/05/16 at 12:45:55

cpukit: pppd: fix compile warning

rcsid is defined, but not used. So discard it.

Signed-off-by: Peng Fan <van.freenix@…>

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