source: rtems/cpukit/pppd/utils.c @ 299a523

4.104.114.84.9
Last change on this file since 299a523 was 299a523, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 12, 2002 at 11:23:44 AM

2002-08-12 Joel Sherrill <joel@…>

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