source: rtems/c/src/libnetworking/pppd/utils.c @ 4ca43d7

4.104.114.84.9
Last change on this file since 4ca43d7 was 4ca43d7, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 20, 2005 at 5:00:38 PM

2005-01-20 Joel Sherrill <joel@…>

PR 736/pppd

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