2 * utils.c - various utility functions used in pppd.
4 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies.
11 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
15 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
18 * Copyright (c) 1999 The Australian National University.
19 * All rights reserved.
21 * Redistribution and use in source and binary forms are permitted
22 * provided that the above copyright notice and this paragraph are
23 * duplicated in all such forms and that any documentation,
24 * advertising materials, and other materials related to such
25 * distribution and use acknowledge that the software was developed
26 * by the Australian National University. The name of the University
27 * may not be used to endorse or promote products derived from this
28 * software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34 #pragma ident "%Z%%M% %I% %E% SMI"
35 #define RCSID "$Id: utils.c,v 1.10 2000/03/27 01:36:48 paulus Exp $"
52 #include <sys/param.h>
53 #include <sys/types.h>
56 #include <sys/resource.h>
58 #include <sys/socket.h>
59 #include <netinet/in.h>
61 #include <sys/mkdev.h>
66 #if !defined(lint) && !defined(_lint)
67 static const char rcsid
[] = RCSID
;
71 extern char *strerror();
74 /* Don't log to stdout until we're sure it's ok to do so. */
77 static void pr_log
__P((void *, const char *, ...));
78 static void logit
__P((int, const char *, va_list));
79 static void vslp_printer
__P((void *, const char *, ...));
80 static void format_packet
__P((u_char
*, int,
81 void (*) (void *, const char *, ...), void *));
89 * strllen - like strlen, but doesn't run past end of input.
98 for (ret
= 0; ret
< len
; ret
++)
105 * slprintf - format a message into a buffer. Like sprintf except we
106 * also specify the length of the output buffer, and we handle %m
107 * (error message), %v (visible string), %q (quoted string), %t
108 * (current time), %I (IP address), %P (PPP packet), and %B (sequence
109 * of bytes) formats. Doesn't do floating-point formats. Returns the
110 * number of chars put into buf.
113 slprintf
__V((char *buf
, int buflen
, const char *fmt
, ...))
118 #if defined(__STDC__)
125 buf
= va_arg(args
, char *);
126 buflen
= va_arg(args
, int);
127 fmt
= va_arg(args
, const char *);
129 n
= vslprintf(buf
, buflen
, fmt
, args
);
135 * Print to file or, if argument is NULL, to syslog at debug level.
138 flprintf
__V((FILE *strptr
, const char *fmt
, ...))
142 char buf
[1024], *bp
, *nlp
, *ebp
;
144 #if defined(__STDC__)
150 strptr
= va_arg(args
, FILE *);
151 fmt
= va_arg(args
, const char *);
153 n
= vslprintf(buf
, sizeof (buf
), fmt
, args
);
155 if (strptr
== NULL
) {
159 if ((nlp
= strchr(bp
, '\n')) == NULL
)
163 syslog(LOG_DEBUG
, "%s", bp
);
168 n
= fwrite(buf
, 1, n
, strptr
);
174 * vslprintf - like slprintf, takes a va_list instead of a list of args.
176 #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
179 vslprintf(buf
, buflen
, fmt
, args
)
186 int width
, prec
, fillch
;
187 int base
, len
, neg
, quoted
;
198 char num
[32]; /* 2^64 is 20 chars decimal, 22 octal */
201 static const char hexchars
[] = "0123456789abcdef";
202 struct buffer_info bufinfo
;
207 for (f
= fmt
; *f
!= '%' && *f
!= 0; ++f
)
213 (void) memcpy(buf
, fmt
, len
);
229 width
= va_arg(args
, int);
233 width
= width
* 10 + c
- '0';
240 prec
= va_arg(args
, int);
245 prec
= prec
* 10 + c
- '0';
268 val
= va_arg(args
, uint64_t);
272 val
= va_arg(args
, unsigned long);
274 val
= va_arg(args
, unsigned int);
280 sval
= va_arg(args
, int64_t);
284 sval
= va_arg(args
, long);
286 sval
= va_arg(args
, int);
297 val
= va_arg(args
, uint64_t);
301 val
= va_arg(args
, unsigned long);
303 val
= va_arg(args
, unsigned int);
310 val
= va_arg(args
, uint64_t);
314 val
= va_arg(args
, unsigned long);
316 val
= va_arg(args
, unsigned int);
320 val
= (unsigned long) va_arg(args
, void *);
325 str
= va_arg(args
, const char *);
328 num
[0] = va_arg(args
, int);
333 str
= strerror(errno
);
336 ip
= va_arg(args
, u_int32_t
);
338 (void) slprintf(num
, sizeof(num
), "%d.%d.%d.%d", (ip
>> 24) & 0xff,
339 (ip
>> 16) & 0xff, (ip
>> 8) & 0xff, ip
& 0xff);
345 mstr
+= 4; /* chop off the day name */
346 mstr
[15] = 0; /* chop off year and newline */
347 str
= (const char *)mstr
;
349 case 'v': /* "visible" string */
350 case 'q': /* quoted string */
352 p
= va_arg(args
, unsigned char *);
353 if (fillch
== '0' && prec
>= 0) {
356 n
= strlen((char *)p
);
357 if (prec
>= 0 && n
> prec
)
360 while (n
> 0 && buflen
> 0) {
363 if (!quoted
&& c
>= 0x80) {
368 if (quoted
&& (c
== '"' || c
== '\\'))
369 (void) OUTCHAR('\\');
370 if (c
< 0x20 || (0x7f <= c
&& c
< 0xa0)) {
372 (void) OUTCHAR('\\');
374 case '\t': (void) OUTCHAR('t'); break;
375 case '\n': (void) OUTCHAR('n'); break;
376 case '\b': (void) OUTCHAR('b'); break;
377 case '\f': (void) OUTCHAR('f'); break;
380 (void) OUTCHAR(hexchars
[c
>> 4]);
381 (void) OUTCHAR(hexchars
[c
& 0xf]);
388 (void) OUTCHAR(c
^ 0x40);
395 case 'P': /* print PPP packet */
397 bufinfo
.len
= buflen
+ 1;
398 p
= va_arg(args
, unsigned char *);
399 n
= va_arg(args
, int);
400 format_packet(p
, n
, vslp_printer
, &bufinfo
);
402 buflen
= bufinfo
.len
- 1;
405 p
= va_arg(args
, unsigned char *);
406 if ((n
= prec
) > width
&& width
> 0)
408 /* For safety's sake */
415 (void) OUTCHAR(hexchars
[(c
>> 4) & 0xf]);
416 (void) OUTCHAR(hexchars
[c
& 0xf]);
418 if (prec
> width
&& width
> 0) {
427 --fmt
; /* so %z outputs %z etc. */
432 mstr
= num
+ sizeof(num
);
434 while (mstr
> num
+ neg
) {
435 *--mstr
= hexchars
[val
% base
];
437 if (--prec
<= 0 && val
== 0)
449 len
= num
+ sizeof(num
) - 1 - mstr
;
450 str
= (const char *)mstr
;
453 if (prec
>= 0 && len
> prec
)
459 if ((n
= width
- len
) > 0) {
467 (void) memcpy(buf
, str
, len
);
476 * vslp_printer - used in processing a %P format
479 vslp_printer
__V((void *arg
, const char *fmt
, ...))
483 struct buffer_info
*bi
;
485 #if defined(__STDC__)
491 arg
= va_arg(pvar
, void *);
492 fmt
= va_arg(pvar
, const char *);
495 bi
= (struct buffer_info
*) arg
;
496 n
= vslprintf(bi
->ptr
, bi
->len
, fmt
, pvar
);
504 * log_packet - format a packet and log it.
507 static char line
[256]; /* line to be logged accumulated here */
511 log_packet(p
, len
, prefix
, level
)
517 (void) strlcpy(line
, prefix
, sizeof(line
));
518 linep
= line
+ strlen(line
);
519 format_packet(p
, len
, pr_log
, (void *)level
);
521 syslog(level
, "%s", line
);
525 * format_packet - make a readable representation of a packet,
526 * calling `printer(arg, format, ...)' to output it.
529 format_packet(p
, len
, printer
, arg
)
532 void (*printer
) __P((void *, const char *, ...));
537 struct protent
*protp
;
539 if (len
>= PPP_HDRLEN
&& p
[0] == PPP_ALLSTATIONS
&& p
[1] == PPP_UI
) {
543 for (i
= 0; (protp
= protocols
[i
]) != NULL
; ++i
)
544 if (proto
== protp
->protocol
)
547 printer(arg
, "[%s", protp
->name
);
548 n
= (*protp
->printpkt
)(p
, len
, printer
, arg
);
553 for (i
= 0; (protp
= protocols
[i
]) != NULL
; ++i
)
554 if (proto
== (protp
->protocol
& ~0x8000))
556 if (protp
!= NULL
&& protp
->data_name
!= NULL
) {
557 printer(arg
, "[%s data] %8.*B", protp
->data_name
, len
, p
);
560 printer(arg
, "[proto=0x%x]", proto
);
564 printer(arg
, "%32.*B", len
, p
);
568 pr_log
__V((void *arg
, const char *fmt
, ...))
574 #if defined(__STDC__)
580 arg
= va_arg(pvar
, void *);
581 fmt
= va_arg(pvar
, const char *);
584 n
= vslprintf(buf
, sizeof(buf
), fmt
, pvar
);
587 if (linep
+ n
+ 1 > line
+ sizeof(line
)) {
588 syslog((int)arg
, "%s", line
);
591 (void) strlcpy(linep
, buf
, line
+ sizeof(line
) - linep
);
596 * print_string - print a readable representation of a string using
600 print_string(p
, len
, printer
, arg
)
603 void (*printer
) __P((void *, const char *, ...));
609 for (; len
> 0; --len
) {
612 if (c
== '\\' || c
== '"')
614 printer(arg
, "%c", c
);
627 printer(arg
, "\\%.3o", c
);
635 * logit - does the hard work for fatal et al.
638 logit(level
, fmt
, args
)
646 n
= vslprintf(buf
, sizeof(buf
), fmt
, args
);
647 syslog(level
, "%s", buf
);
648 if (log_to_fd
>= 0 && (level
!= LOG_DEBUG
|| debug
) &&
649 (!early_log
|| log_to_specific_fd
)) {
650 if (buf
[n
-1] != '\n')
652 if (write(log_to_fd
, buf
, n
) != n
)
658 * fatal - log an error message and die horribly.
661 fatal
__V((const char *fmt
, ...))
665 #if defined(__STDC__)
670 fmt
= va_arg(pvar
, const char *);
673 logit(LOG_ERR
, fmt
, pvar
);
676 die(1); /* as promised */
680 * error - log an error message.
683 error
__V((const char *fmt
, ...))
687 #if defined(__STDC__)
692 fmt
= va_arg(pvar
, const char *);
695 logit(LOG_ERR
, fmt
, pvar
);
700 * warn - log a warning message.
703 warn
__V((const char *fmt
, ...))
707 #if defined(__STDC__)
712 fmt
= va_arg(pvar
, const char *);
715 logit(LOG_WARNING
, fmt
, pvar
);
720 * notice - log a notice-level message.
723 notice
__V((const char *fmt
, ...))
727 #if defined(__STDC__)
732 fmt
= va_arg(pvar
, const char *);
735 logit(LOG_NOTICE
, fmt
, pvar
);
740 * info - log an informational message.
743 info
__V((const char *fmt
, ...))
747 #if defined(__STDC__)
752 fmt
= va_arg(pvar
, const char *);
755 logit(LOG_INFO
, fmt
, pvar
);
760 * dbglog - log a debug message.
763 dbglog
__V((const char *fmt
, ...))
767 #if defined(__STDC__)
772 fmt
= va_arg(pvar
, const char *);
775 logit(LOG_DEBUG
, fmt
, pvar
);
780 * Code names for regular PPP messages. Used by LCP and most NCPs,
781 * not used by authentication protocols.
784 code_name(int code
, int shortflag
)
786 static const char *codelist
[] = {
787 "Vendor-Extension", "Configure-Request", "Configure-Ack",
788 "Configure-Nak", "Configure-Reject", "Terminate-Request",
789 "Terminate-Ack", "Code-Reject", "Protocol-Reject",
790 "Echo-Request", "Echo-Reply", "Discard-Request",
791 "Identification", "Time-Remaining",
792 "Reset-Request", "Reset-Ack"
794 static const char *shortcode
[] = {
795 "VendExt", "ConfReq", "ConfAck",
796 "ConfNak", "ConfRej", "TermReq",
797 "TermAck", "CodeRej", "ProtRej",
798 "EchoReq", "EchoRep", "DiscReq",
800 "ResetReq", "ResetAck"
802 static char msgbuf
[64];
804 if (code
< 0 || code
>= sizeof (codelist
) / sizeof (*codelist
)) {
806 (void) slprintf(msgbuf
, sizeof (msgbuf
), "Code#%d", code
);
808 (void) slprintf(msgbuf
, sizeof (msgbuf
), "unknown code %d", code
);
809 return ((const char *)msgbuf
);
811 return (shortflag
? shortcode
[code
] : codelist
[code
]);
814 /* Procedures for locking the serial device using a lock file. */
817 #define LOCK_DIR "/var/lock"
820 #define LOCK_DIR "/var/spool/locks"
822 #define LOCK_DIR "/var/spool/lock"
825 #endif /* LOCK_DIR */
827 static char lock_file
[MAXPATHLEN
];
830 * lock - create a lock file for the named device
839 result
= mklock (dev
, (void *) 0);
841 (void) strlcpy(lock_file
, sizeof(lock_file
), dev
);
846 notice("Device %s is locked by pid %d", dev
, result
);
848 error("Can't create lock file %s", lock_file
);
853 char lock_buffer
[12];
859 if (stat(dev
, &sbuf
) < 0) {
860 error("Can't get device number for %s: %m", dev
);
863 if ((sbuf
.st_mode
& S_IFMT
) != S_IFCHR
) {
864 error("Can't lock %s: not a character device", dev
);
867 (void) slprintf(lock_file
, sizeof(lock_file
), "%s/LK.%03d.%03d.%03d",
868 LOCK_DIR
, major(sbuf
.st_dev
),
869 major(sbuf
.st_rdev
), minor(sbuf
.st_rdev
));
873 if ((p
= strrchr(dev
, '/')) != NULL
)
875 (void) slprintf(lock_file
, sizeof(lock_file
), "%s/LCK..%s", LOCK_DIR
, dev
);
878 while ((fd
= open(lock_file
, O_EXCL
| O_CREAT
| O_RDWR
, 0644)) < 0) {
879 if (errno
!= EEXIST
) {
880 error("Can't create lock file %s: %m", lock_file
);
884 /* Read the lock file to find out who has the device locked. */
885 fd
= open(lock_file
, O_RDONLY
, 0);
887 if (errno
== ENOENT
) /* This is just a timing problem. */
889 error("Can't open existing lock file %s: %m", lock_file
);
893 n
= read(fd
, lock_buffer
, 11);
895 n
= read(fd
, &pid
, sizeof(pid
));
896 #endif /* LOCK_BINARY */
900 error("Can't read pid from lock file %s", lock_file
);
904 /* See if the process still exists. */
907 pid
= atoi(lock_buffer
);
908 #endif /* LOCK_BINARY */
910 return (1); /* somebody else locked it for us */
912 || (kill(pid
, 0) == -1 && errno
== ESRCH
)) {
913 if (unlink (lock_file
) == 0) {
914 notice("Removed stale lock on %s (pid %d)", dev
, pid
);
917 warn("Couldn't remove stale lock on %s", dev
);
919 notice("Device %s is locked by pid %d", dev
, pid
);
930 (void) slprintf(lock_buffer
, sizeof(lock_buffer
), "%10d\n", pid
);
931 (void) write (fd
, lock_buffer
, 11);
933 (void) write(fd
, &pid
, sizeof (pid
));
942 * relock - called to update our lockfile when we are about to detach,
943 * thus changing our pid (we fork, the child carries on, and the parent dies).
944 * Note that this is called by the parent, with pid equal to the pid
945 * of the child. This avoids a potential race which would exist if
946 * we had the child rewrite the lockfile (the parent might die first,
947 * and another process could think the lock was stale if it checked
948 * between when the parent died and the child rewrote the lockfile).
955 /* XXX is there a way to do this? */
960 char lock_buffer
[12];
962 if (lock_file
[0] == 0)
964 fd
= open(lock_file
, O_WRONLY
, 0);
966 error("Couldn't reopen lock file %s: %m", lock_file
);
972 (void) slprintf(lock_buffer
, sizeof(lock_buffer
), "%10d\n", pid
);
973 (void) write (fd
, lock_buffer
, 11);
975 (void) write(fd
, &pid
, sizeof(pid
));
976 #endif /* LOCK_BINARY */
984 * unlock - remove our lockfile
991 (void) rmlock(lock_file
, (void *) 0);
993 (void) unlink(lock_file
);
1000 signal_name(int signum
)
1002 #if defined(SOL2) || defined(__linux__) || defined(_linux_)
1005 if ((cp
= strsignal(signum
)) != NULL
)
1008 extern char *sys_siglist
[];
1009 extern int sys_nsig
;
1011 if (signum
>= 0 && signum
< sys_nsig
&& sys_siglist
[signum
] != NULL
)
1012 return (sys_siglist
[signum
]);