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.
49 #include <sys/param.h>
50 #include <sys/types.h>
53 #include <sys/resource.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
58 #include <sys/mkdev.h>
64 extern char *strerror();
67 /* Don't log to stdout until we're sure it's ok to do so. */
70 static void pr_log
__P((void *, const char *, ...));
71 static void logit
__P((int, const char *, va_list));
72 static void vslp_printer
__P((void *, const char *, ...));
73 static void format_packet
__P((u_char
*, int,
74 void (*) (void *, const char *, ...), void *));
82 * strllen - like strlen, but doesn't run past end of input.
91 for (ret
= 0; ret
< len
; ret
++)
98 * slprintf - format a message into a buffer. Like sprintf except we
99 * also specify the length of the output buffer, and we handle %m
100 * (error message), %v (visible string), %q (quoted string), %t
101 * (current time), %I (IP address), %P (PPP packet), and %B (sequence
102 * of bytes) formats. Doesn't do floating-point formats. Returns the
103 * number of chars put into buf.
106 slprintf
__V((char *buf
, int buflen
, const char *fmt
, ...))
111 #if defined(__STDC__)
118 buf
= va_arg(args
, char *);
119 buflen
= va_arg(args
, int);
120 fmt
= va_arg(args
, const char *);
122 n
= vslprintf(buf
, buflen
, fmt
, args
);
128 * Print to file or, if argument is NULL, to syslog at debug level.
131 flprintf
__V((FILE *strptr
, const char *fmt
, ...))
135 char buf
[1024], *bp
, *nlp
, *ebp
;
137 #if defined(__STDC__)
143 strptr
= va_arg(args
, FILE *);
144 fmt
= va_arg(args
, const char *);
146 n
= vslprintf(buf
, sizeof (buf
), fmt
, args
);
148 if (strptr
== NULL
) {
152 if ((nlp
= strchr(bp
, '\n')) == NULL
)
156 syslog(LOG_DEBUG
, "%s", bp
);
161 n
= fwrite(buf
, 1, n
, strptr
);
167 * vslprintf - like slprintf, takes a va_list instead of a list of args.
169 #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
172 vslprintf(buf
, buflen
, fmt
, args
)
179 int width
, prec
, fillch
;
180 int base
, len
, neg
, quoted
;
191 char num
[32]; /* 2^64 is 20 chars decimal, 22 octal */
194 static const char hexchars
[] = "0123456789abcdef";
195 struct buffer_info bufinfo
;
200 for (f
= fmt
; *f
!= '%' && *f
!= 0; ++f
)
206 (void) memcpy(buf
, fmt
, len
);
222 width
= va_arg(args
, int);
226 width
= width
* 10 + c
- '0';
233 prec
= va_arg(args
, int);
238 prec
= prec
* 10 + c
- '0';
261 val
= va_arg(args
, uint64_t);
265 val
= va_arg(args
, unsigned long);
267 val
= va_arg(args
, unsigned int);
273 sval
= va_arg(args
, int64_t);
277 sval
= va_arg(args
, long);
279 sval
= va_arg(args
, int);
290 val
= va_arg(args
, uint64_t);
294 val
= va_arg(args
, unsigned long);
296 val
= va_arg(args
, unsigned int);
303 val
= va_arg(args
, uint64_t);
307 val
= va_arg(args
, unsigned long);
309 val
= va_arg(args
, unsigned int);
313 val
= (unsigned long) va_arg(args
, void *);
318 str
= va_arg(args
, const char *);
321 num
[0] = va_arg(args
, int);
326 str
= strerror(errno
);
329 ip
= va_arg(args
, u_int32_t
);
331 (void) slprintf(num
, sizeof(num
), "%d.%d.%d.%d", (ip
>> 24) & 0xff,
332 (ip
>> 16) & 0xff, (ip
>> 8) & 0xff, ip
& 0xff);
338 mstr
+= 4; /* chop off the day name */
339 mstr
[15] = 0; /* chop off year and newline */
340 str
= (const char *)mstr
;
342 case 'v': /* "visible" string */
343 case 'q': /* quoted string */
345 p
= va_arg(args
, unsigned char *);
346 if (fillch
== '0' && prec
>= 0) {
349 n
= strlen((char *)p
);
350 if (prec
>= 0 && n
> prec
)
353 while (n
> 0 && buflen
> 0) {
356 if (!quoted
&& c
>= 0x80) {
361 if (quoted
&& (c
== '"' || c
== '\\'))
362 (void) OUTCHAR('\\');
363 if (c
< 0x20 || (0x7f <= c
&& c
< 0xa0)) {
365 (void) OUTCHAR('\\');
367 case '\t': (void) OUTCHAR('t'); break;
368 case '\n': (void) OUTCHAR('n'); break;
369 case '\b': (void) OUTCHAR('b'); break;
370 case '\f': (void) OUTCHAR('f'); break;
373 (void) OUTCHAR(hexchars
[c
>> 4]);
374 (void) OUTCHAR(hexchars
[c
& 0xf]);
381 (void) OUTCHAR(c
^ 0x40);
388 case 'P': /* print PPP packet */
390 bufinfo
.len
= buflen
+ 1;
391 p
= va_arg(args
, unsigned char *);
392 n
= va_arg(args
, int);
393 format_packet(p
, n
, vslp_printer
, &bufinfo
);
395 buflen
= bufinfo
.len
- 1;
398 p
= va_arg(args
, unsigned char *);
399 if ((n
= prec
) > width
&& width
> 0)
401 /* For safety's sake */
408 (void) OUTCHAR(hexchars
[(c
>> 4) & 0xf]);
409 (void) OUTCHAR(hexchars
[c
& 0xf]);
411 if (prec
> width
&& width
> 0) {
420 --fmt
; /* so %z outputs %z etc. */
425 mstr
= num
+ sizeof(num
);
427 while (mstr
> num
+ neg
) {
428 *--mstr
= hexchars
[val
% base
];
430 if (--prec
<= 0 && val
== 0)
442 len
= num
+ sizeof(num
) - 1 - mstr
;
443 str
= (const char *)mstr
;
446 if (prec
>= 0 && len
> prec
)
452 if ((n
= width
- len
) > 0) {
460 (void) memcpy(buf
, str
, len
);
469 * vslp_printer - used in processing a %P format
472 vslp_printer
__V((void *arg
, const char *fmt
, ...))
476 struct buffer_info
*bi
;
478 #if defined(__STDC__)
484 arg
= va_arg(pvar
, void *);
485 fmt
= va_arg(pvar
, const char *);
488 bi
= (struct buffer_info
*) arg
;
489 n
= vslprintf(bi
->ptr
, bi
->len
, fmt
, pvar
);
497 * log_packet - format a packet and log it.
500 static char line
[256]; /* line to be logged accumulated here */
504 log_packet(p
, len
, prefix
, level
)
510 (void) strlcpy(line
, prefix
, sizeof(line
));
511 linep
= line
+ strlen(line
);
512 format_packet(p
, len
, pr_log
, (void *)level
);
514 syslog(level
, "%s", line
);
518 * format_packet - make a readable representation of a packet,
519 * calling `printer(arg, format, ...)' to output it.
522 format_packet(p
, len
, printer
, arg
)
525 void (*printer
) __P((void *, const char *, ...));
530 struct protent
*protp
;
532 if (len
>= PPP_HDRLEN
&& p
[0] == PPP_ALLSTATIONS
&& p
[1] == PPP_UI
) {
536 for (i
= 0; (protp
= protocols
[i
]) != NULL
; ++i
)
537 if (proto
== protp
->protocol
)
540 printer(arg
, "[%s", protp
->name
);
541 n
= (*protp
->printpkt
)(p
, len
, printer
, arg
);
546 for (i
= 0; (protp
= protocols
[i
]) != NULL
; ++i
)
547 if (proto
== (protp
->protocol
& ~0x8000))
549 if (protp
!= NULL
&& protp
->data_name
!= NULL
) {
550 printer(arg
, "[%s data] %8.*B", protp
->data_name
, len
, p
);
553 printer(arg
, "[proto=0x%x]", proto
);
557 printer(arg
, "%32.*B", len
, p
);
561 pr_log
__V((void *arg
, const char *fmt
, ...))
567 #if defined(__STDC__)
573 arg
= va_arg(pvar
, void *);
574 fmt
= va_arg(pvar
, const char *);
577 n
= vslprintf(buf
, sizeof(buf
), fmt
, pvar
);
580 if (linep
+ n
+ 1 > line
+ sizeof(line
)) {
581 syslog((int)arg
, "%s", line
);
584 (void) strlcpy(linep
, buf
, line
+ sizeof(line
) - linep
);
589 * print_string - print a readable representation of a string using
593 print_string(p
, len
, printer
, arg
)
596 void (*printer
) __P((void *, const char *, ...));
602 for (; len
> 0; --len
) {
605 if (c
== '\\' || c
== '"')
607 printer(arg
, "%c", c
);
620 printer(arg
, "\\%.3o", c
);
628 * logit - does the hard work for fatal et al.
631 logit(level
, fmt
, args
)
639 n
= vslprintf(buf
, sizeof(buf
), fmt
, args
);
640 syslog(level
, "%s", buf
);
641 if (log_to_fd
>= 0 && (level
!= LOG_DEBUG
|| debug
) &&
642 (!early_log
|| log_to_specific_fd
)) {
643 if (buf
[n
-1] != '\n')
645 if (write(log_to_fd
, buf
, n
) != n
)
651 * fatal - log an error message and die horribly.
654 fatal
__V((const char *fmt
, ...))
658 #if defined(__STDC__)
663 fmt
= va_arg(pvar
, const char *);
666 logit(LOG_ERR
, fmt
, pvar
);
669 die(1); /* as promised */
673 * error - log an error message.
676 error
__V((const char *fmt
, ...))
680 #if defined(__STDC__)
685 fmt
= va_arg(pvar
, const char *);
688 logit(LOG_ERR
, fmt
, pvar
);
693 * warn - log a warning message.
696 warn
__V((const char *fmt
, ...))
700 #if defined(__STDC__)
705 fmt
= va_arg(pvar
, const char *);
708 logit(LOG_WARNING
, fmt
, pvar
);
713 * notice - log a notice-level message.
716 notice
__V((const char *fmt
, ...))
720 #if defined(__STDC__)
725 fmt
= va_arg(pvar
, const char *);
728 logit(LOG_NOTICE
, fmt
, pvar
);
733 * info - log an informational message.
736 info
__V((const char *fmt
, ...))
740 #if defined(__STDC__)
745 fmt
= va_arg(pvar
, const char *);
748 logit(LOG_INFO
, fmt
, pvar
);
753 * dbglog - log a debug message.
756 dbglog
__V((const char *fmt
, ...))
760 #if defined(__STDC__)
765 fmt
= va_arg(pvar
, const char *);
768 logit(LOG_DEBUG
, fmt
, pvar
);
773 * Code names for regular PPP messages. Used by LCP and most NCPs,
774 * not used by authentication protocols.
777 code_name(int code
, int shortflag
)
779 static const char *codelist
[] = {
780 "Vendor-Extension", "Configure-Request", "Configure-Ack",
781 "Configure-Nak", "Configure-Reject", "Terminate-Request",
782 "Terminate-Ack", "Code-Reject", "Protocol-Reject",
783 "Echo-Request", "Echo-Reply", "Discard-Request",
784 "Identification", "Time-Remaining",
785 "Reset-Request", "Reset-Ack"
787 static const char *shortcode
[] = {
788 "VendExt", "ConfReq", "ConfAck",
789 "ConfNak", "ConfRej", "TermReq",
790 "TermAck", "CodeRej", "ProtRej",
791 "EchoReq", "EchoRep", "DiscReq",
793 "ResetReq", "ResetAck"
795 static char msgbuf
[64];
797 if (code
< 0 || code
>= sizeof (codelist
) / sizeof (*codelist
)) {
799 (void) slprintf(msgbuf
, sizeof (msgbuf
), "Code#%d", code
);
801 (void) slprintf(msgbuf
, sizeof (msgbuf
), "unknown code %d", code
);
802 return ((const char *)msgbuf
);
804 return (shortflag
? shortcode
[code
] : codelist
[code
]);
807 /* Procedures for locking the serial device using a lock file. */
810 #define LOCK_DIR "/var/lock"
813 #define LOCK_DIR "/var/spool/locks"
815 #define LOCK_DIR "/var/spool/lock"
818 #endif /* LOCK_DIR */
820 static char lock_file
[MAXPATHLEN
];
823 * lock - create a lock file for the named device
832 result
= mklock (dev
, NULL
);
834 (void) strlcpy(lock_file
, sizeof(lock_file
), dev
);
839 notice("Device %s is locked by pid %d", dev
, result
);
841 error("Can't create lock file %s", lock_file
);
846 char lock_buffer
[12];
852 if (stat(dev
, &sbuf
) < 0) {
853 error("Can't get device number for %s: %m", dev
);
856 if ((sbuf
.st_mode
& S_IFMT
) != S_IFCHR
) {
857 error("Can't lock %s: not a character device", dev
);
860 (void) slprintf(lock_file
, sizeof(lock_file
), "%s/LK.%03d.%03d.%03d",
861 LOCK_DIR
, major(sbuf
.st_dev
),
862 major(sbuf
.st_rdev
), minor(sbuf
.st_rdev
));
866 if ((p
= strrchr(dev
, '/')) != NULL
)
868 (void) slprintf(lock_file
, sizeof(lock_file
), "%s/LCK..%s", LOCK_DIR
, dev
);
871 while ((fd
= open(lock_file
, O_EXCL
| O_CREAT
| O_RDWR
, 0644)) < 0) {
872 if (errno
!= EEXIST
) {
873 error("Can't create lock file %s: %m", lock_file
);
877 /* Read the lock file to find out who has the device locked. */
878 fd
= open(lock_file
, O_RDONLY
, 0);
880 if (errno
== ENOENT
) /* This is just a timing problem. */
882 error("Can't open existing lock file %s: %m", lock_file
);
886 n
= read(fd
, lock_buffer
, 11);
888 n
= read(fd
, &pid
, sizeof(pid
));
889 #endif /* LOCK_BINARY */
893 error("Can't read pid from lock file %s", lock_file
);
897 /* See if the process still exists. */
900 pid
= atoi(lock_buffer
);
901 #endif /* LOCK_BINARY */
903 return (1); /* somebody else locked it for us */
905 || (kill(pid
, 0) == -1 && errno
== ESRCH
)) {
906 if (unlink (lock_file
) == 0) {
907 notice("Removed stale lock on %s (pid %d)", dev
, pid
);
910 warn("Couldn't remove stale lock on %s", dev
);
912 notice("Device %s is locked by pid %d", dev
, pid
);
923 (void) slprintf(lock_buffer
, sizeof(lock_buffer
), "%10d\n", pid
);
924 (void) write (fd
, lock_buffer
, 11);
926 (void) write(fd
, &pid
, sizeof (pid
));
935 * relock - called to update our lockfile when we are about to detach,
936 * thus changing our pid (we fork, the child carries on, and the parent dies).
937 * Note that this is called by the parent, with pid equal to the pid
938 * of the child. This avoids a potential race which would exist if
939 * we had the child rewrite the lockfile (the parent might die first,
940 * and another process could think the lock was stale if it checked
941 * between when the parent died and the child rewrote the lockfile).
948 /* XXX is there a way to do this? */
953 char lock_buffer
[12];
955 if (lock_file
[0] == 0)
957 fd
= open(lock_file
, O_WRONLY
, 0);
959 error("Couldn't reopen lock file %s: %m", lock_file
);
965 (void) slprintf(lock_buffer
, sizeof(lock_buffer
), "%10d\n", pid
);
966 (void) write (fd
, lock_buffer
, 11);
968 (void) write(fd
, &pid
, sizeof(pid
));
969 #endif /* LOCK_BINARY */
977 * unlock - remove our lockfile
984 (void) rmlock(lock_file
, NULL
);
986 (void) unlink(lock_file
);
993 signal_name(int signum
)
995 #if defined(SOL2) || defined(__linux__) || defined(_linux_)
998 if ((cp
= strsignal(signum
)) != NULL
)
1001 extern char *sys_siglist
[];
1002 extern int sys_nsig
;
1004 if (signum
>= 0 && signum
< sys_nsig
&& sys_siglist
[signum
] != NULL
)
1005 return (sys_siglist
[signum
]);