CPU: Wrong CPU Load %.
[tomato.git] / release / src / router / ppp / pppd / utils.c
blob70f74644886937882352cc6af04e3e63d84b0bbb
1 /*
2 * utils.c - various utility functions used in pppd.
4 * Copyright (c) 1999 The Australian National University.
5 * All rights reserved.
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.
20 #define RCSID "$Id: utils.c,v 1.1.1.4 2003/10/14 08:09:53 sparq Exp $"
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 <syslog.h>
31 #include <netdb.h>
32 #include <utmp.h>
33 #include <pwd.h>
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #include <sys/stat.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #ifdef SVR4
43 #include <sys/mkdev.h>
44 #endif
46 #include "pppd.h"
48 static const char rcsid[] = RCSID;
50 #if defined(SUNOS4)
51 extern char *strerror();
52 #endif
54 static void logit __P((int, char *, va_list));
55 static void log_write __P((int, char *));
56 static void vslp_printer __P((void *, char *, ...));
57 static void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
58 void *));
60 struct buffer_info {
61 char *ptr;
62 int len;
66 * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
67 * always leaves destination null-terminated (for len > 0).
69 size_t
70 strlcpy(dest, src, len)
71 char *dest;
72 const char *src;
73 size_t len;
75 size_t ret = strlen(src);
77 if (len != 0) {
78 if (ret < len)
79 strcpy(dest, src);
80 else {
81 strncpy(dest, src, len - 1);
82 dest[len-1] = 0;
85 return ret;
89 * strlcat - like strcat/strncat, doesn't overflow destination buffer,
90 * always leaves destination null-terminated (for len > 0).
92 size_t
93 strlcat(dest, src, len)
94 char *dest;
95 const char *src;
96 size_t len;
98 size_t dlen = strlen(dest);
100 return dlen + strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
105 * slprintf - format a message into a buffer. Like sprintf except we
106 * also specify the length of the output buffer, and we handle
107 * %r (recursive format), %m (error message), %v (visible string),
108 * %q (quoted string), %t (current time) and %I (IP address) formats.
109 * Doesn't do floating-point formats.
110 * Returns the number of chars put into buf.
113 slprintf __V((char *buf, int buflen, char *fmt, ...))
115 va_list args;
116 int n;
118 #if defined(__STDC__)
119 va_start(args, fmt);
120 #else
121 char *buf;
122 int buflen;
123 char *fmt;
124 va_start(args);
125 buf = va_arg(args, char *);
126 buflen = va_arg(args, int);
127 fmt = va_arg(args, char *);
128 #endif
129 n = vslprintf(buf, buflen, fmt, args);
130 va_end(args);
131 return n;
135 * vslprintf - like slprintf, takes a va_list instead of a list of args.
137 #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
140 vslprintf(buf, buflen, fmt, args)
141 char *buf;
142 int buflen;
143 char *fmt;
144 va_list args;
146 int c, i, n;
147 int width, prec, fillch;
148 int base, len, neg, quoted;
149 unsigned long val = 0;
150 char *str, *f, *buf0;
151 unsigned char *p;
152 char num[32];
153 time_t t;
154 u_int32_t ip;
155 static char hexchars[] = "0123456789abcdef";
156 struct buffer_info bufinfo;
158 buf0 = buf;
159 --buflen;
160 while (buflen > 0) {
161 for (f = fmt; *f != '%' && *f != 0; ++f)
163 if (f > fmt) {
164 len = f - fmt;
165 if (len > buflen)
166 len = buflen;
167 memcpy(buf, fmt, len);
168 buf += len;
169 buflen -= len;
170 fmt = f;
172 if (*fmt == 0)
173 break;
174 c = *++fmt;
175 width = 0;
176 prec = -1;
177 fillch = ' ';
178 if (c == '0') {
179 fillch = '0';
180 c = *++fmt;
182 if (c == '*') {
183 width = va_arg(args, int);
184 c = *++fmt;
185 } else {
186 while (isdigit(c)) {
187 width = width * 10 + c - '0';
188 c = *++fmt;
191 if (c == '.') {
192 c = *++fmt;
193 if (c == '*') {
194 prec = va_arg(args, int);
195 c = *++fmt;
196 } else {
197 prec = 0;
198 while (isdigit(c)) {
199 prec = prec * 10 + c - '0';
200 c = *++fmt;
204 str = 0;
205 base = 0;
206 neg = 0;
207 ++fmt;
208 switch (c) {
209 case 'd':
210 i = va_arg(args, int);
211 if (i < 0) {
212 neg = 1;
213 val = -i;
214 } else
215 val = i;
216 base = 10;
217 break;
218 case 'u':
219 val = va_arg(args, unsigned int);
220 base = 10;
221 break;
222 case 'o':
223 val = va_arg(args, unsigned int);
224 base = 8;
225 break;
226 case 'x':
227 case 'X':
228 val = va_arg(args, unsigned int);
229 base = 16;
230 break;
231 case 'p':
232 val = (unsigned long) va_arg(args, void *);
233 base = 16;
234 neg = 2;
235 break;
236 case 's':
237 str = va_arg(args, char *);
238 break;
239 case 'c':
240 num[0] = va_arg(args, int);
241 num[1] = 0;
242 str = num;
243 break;
244 case 'm':
245 str = strerror(errno);
246 break;
247 case 'I':
248 ip = va_arg(args, u_int32_t);
249 ip = ntohl(ip);
250 slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
251 (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
252 str = num;
253 break;
254 case 'r':
255 f = va_arg(args, char *);
256 #ifndef __powerpc__
257 n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
258 #else
259 /* On the powerpc, a va_list is an array of 1 structure */
260 n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
261 #endif
262 buf += n;
263 buflen -= n;
264 continue;
265 case 't':
266 time(&t);
267 str = ctime(&t);
268 str += 4; /* chop off the day name */
269 str[15] = 0; /* chop off year and newline */
270 break;
271 case 'v': /* "visible" string */
272 case 'q': /* quoted string */
273 quoted = c == 'q';
274 p = va_arg(args, unsigned char *);
275 if (fillch == '0' && prec >= 0) {
276 n = prec;
277 } else {
278 n = strlen((char *)p);
279 if (prec >= 0 && n > prec)
280 n = prec;
282 while (n > 0 && buflen > 0) {
283 c = *p++;
284 --n;
285 if (!quoted && c >= 0x80) {
286 OUTCHAR('M');
287 OUTCHAR('-');
288 c -= 0x80;
290 if (quoted && (c == '"' || c == '\\'))
291 OUTCHAR('\\');
292 if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
293 if (quoted) {
294 OUTCHAR('\\');
295 switch (c) {
296 case '\t': OUTCHAR('t'); break;
297 case '\n': OUTCHAR('n'); break;
298 case '\b': OUTCHAR('b'); break;
299 case '\f': OUTCHAR('f'); break;
300 default:
301 OUTCHAR('x');
302 OUTCHAR(hexchars[c >> 4]);
303 OUTCHAR(hexchars[c & 0xf]);
305 } else {
306 if (c == '\t')
307 OUTCHAR(c);
308 else {
309 OUTCHAR('^');
310 OUTCHAR(c ^ 0x40);
313 } else
314 OUTCHAR(c);
316 continue;
317 case 'P': /* print PPP packet */
318 bufinfo.ptr = buf;
319 bufinfo.len = buflen + 1;
320 p = va_arg(args, unsigned char *);
321 n = va_arg(args, int);
322 format_packet(p, n, vslp_printer, &bufinfo);
323 buf = bufinfo.ptr;
324 buflen = bufinfo.len - 1;
325 continue;
326 case 'B':
327 p = va_arg(args, unsigned char *);
328 for (n = prec; n > 0; --n) {
329 c = *p++;
330 if (fillch == ' ')
331 OUTCHAR(' ');
332 OUTCHAR(hexchars[(c >> 4) & 0xf]);
333 OUTCHAR(hexchars[c & 0xf]);
335 continue;
336 default:
337 *buf++ = '%';
338 if (c != '%')
339 --fmt; /* so %z outputs %z etc. */
340 --buflen;
341 continue;
343 if (base != 0) {
344 str = num + sizeof(num);
345 *--str = 0;
346 while (str > num + neg) {
347 *--str = hexchars[val % base];
348 val = val / base;
349 if (--prec <= 0 && val == 0)
350 break;
352 switch (neg) {
353 case 1:
354 *--str = '-';
355 break;
356 case 2:
357 *--str = 'x';
358 *--str = '0';
359 break;
361 len = num + sizeof(num) - 1 - str;
362 } else {
363 len = strlen(str);
364 if (prec >= 0 && len > prec)
365 len = prec;
367 if (width > 0) {
368 if (width > buflen)
369 width = buflen;
370 if ((n = width - len) > 0) {
371 buflen -= n;
372 for (; n > 0; --n)
373 *buf++ = fillch;
376 if (len > buflen)
377 len = buflen;
378 memcpy(buf, str, len);
379 buf += len;
380 buflen -= len;
382 *buf = 0;
383 return buf - buf0;
387 * vslp_printer - used in processing a %P format
389 static void
390 vslp_printer __V((void *arg, char *fmt, ...))
392 int n;
393 va_list pvar;
394 struct buffer_info *bi;
396 #if defined(__STDC__)
397 va_start(pvar, fmt);
398 #else
399 void *arg;
400 char *fmt;
401 va_start(pvar);
402 arg = va_arg(pvar, void *);
403 fmt = va_arg(pvar, char *);
404 #endif
406 bi = (struct buffer_info *) arg;
407 n = vslprintf(bi->ptr, bi->len, fmt, pvar);
408 va_end(pvar);
410 bi->ptr += n;
411 bi->len -= n;
414 #ifdef unused
416 * log_packet - format a packet and log it.
419 void
420 log_packet(p, len, prefix, level)
421 u_char *p;
422 int len;
423 char *prefix;
424 int level;
426 init_pr_log(prefix, level);
427 format_packet(p, len, pr_log, &level);
428 end_pr_log();
430 #endif /* unused */
433 * format_packet - make a readable representation of a packet,
434 * calling `printer(arg, format, ...)' to output it.
436 static void
437 format_packet(p, len, printer, arg)
438 u_char *p;
439 int len;
440 void (*printer) __P((void *, char *, ...));
441 void *arg;
443 int i, n;
444 u_short proto;
445 struct protent *protp;
447 if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
448 p += 2;
449 GETSHORT(proto, p);
450 len -= PPP_HDRLEN;
451 for (i = 0; (protp = protocols[i]) != NULL; ++i)
452 if (proto == protp->protocol)
453 break;
454 if (protp != NULL) {
455 printer(arg, "[%s", protp->name);
456 n = (*protp->printpkt)(p, len, printer, arg);
457 printer(arg, "]");
458 p += n;
459 len -= n;
460 } else {
461 for (i = 0; (protp = protocols[i]) != NULL; ++i)
462 if (proto == (protp->protocol & ~0x8000))
463 break;
464 if (protp != 0 && protp->data_name != 0) {
465 printer(arg, "[%s data]", protp->data_name);
466 if (len > 8)
467 printer(arg, "%.8B ...", p);
468 else
469 printer(arg, "%.*B", len, p);
470 len = 0;
471 } else
472 printer(arg, "[proto=0x%x]", proto);
476 if (len > 32)
477 printer(arg, "%.32B ...", p);
478 else
479 printer(arg, "%.*B", len, p);
483 * init_pr_log, end_pr_log - initialize and finish use of pr_log.
486 static char line[256]; /* line to be logged accumulated here */
487 static char *linep; /* current pointer within line */
488 static int llevel; /* level for logging */
490 void
491 init_pr_log(prefix, level)
492 char *prefix;
493 int level;
495 linep = line;
496 if (prefix != NULL) {
497 strlcpy(line, prefix, sizeof(line));
498 linep = line + strlen(line);
500 llevel = level;
503 void
504 end_pr_log()
506 if (linep != line) {
507 *linep = 0;
508 log_write(llevel, line);
513 * pr_log - printer routine for outputting to syslog
515 void
516 pr_log __V((void *arg, char *fmt, ...))
518 int l, n;
519 va_list pvar;
520 char *p, *eol;
521 char buf[256];
523 #if defined(__STDC__)
524 va_start(pvar, fmt);
525 #else
526 void *arg;
527 char *fmt;
528 va_start(pvar);
529 arg = va_arg(pvar, void *);
530 fmt = va_arg(pvar, char *);
531 #endif
533 n = vslprintf(buf, sizeof(buf), fmt, pvar);
534 va_end(pvar);
536 p = buf;
537 eol = strchr(buf, '\n');
538 if (linep != line) {
539 l = (eol == NULL)? n: eol - buf;
540 if (linep + l < line + sizeof(line)) {
541 if (l > 0) {
542 memcpy(linep, buf, l);
543 linep += l;
545 if (eol == NULL)
546 return;
547 p = eol + 1;
548 eol = strchr(p, '\n');
550 *linep = 0;
551 log_write(llevel, line);
552 linep = line;
555 while (eol != NULL) {
556 *eol = 0;
557 log_write(llevel, p);
558 p = eol + 1;
559 eol = strchr(p, '\n');
562 /* assumes sizeof(buf) <= sizeof(line) */
563 l = buf + n - p;
564 if (l > 0) {
565 memcpy(line, p, n);
566 linep = line + l;
571 * print_string - print a readable representation of a string using
572 * printer.
574 void
575 print_string(p, len, printer, arg)
576 char *p;
577 int len;
578 void (*printer) __P((void *, char *, ...));
579 void *arg;
581 int c;
583 printer(arg, "\"");
584 for (; len > 0; --len) {
585 c = *p++;
586 if (' ' <= c && c <= '~') {
587 if (c == '\\' || c == '"')
588 printer(arg, "\\");
589 printer(arg, "%c", c);
590 } else {
591 switch (c) {
592 case '\n':
593 printer(arg, "\\n");
594 break;
595 case '\r':
596 printer(arg, "\\r");
597 break;
598 case '\t':
599 printer(arg, "\\t");
600 break;
601 default:
602 printer(arg, "\\%.3o", c);
606 printer(arg, "\"");
610 * logit - does the hard work for fatal et al.
612 static void
613 logit(level, fmt, args)
614 int level;
615 char *fmt;
616 va_list args;
618 int n;
619 char buf[1024];
621 n = vslprintf(buf, sizeof(buf), fmt, args);
622 log_write(level, buf);
625 static void
626 log_write(level, buf)
627 int level;
628 char *buf;
630 syslog(level, "%s", buf);
631 if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
632 int n = strlen(buf);
634 if (n > 0 && buf[n-1] == '\n')
635 --n;
636 if (write(log_to_fd, buf, n) != n
637 || write(log_to_fd, "\n", 1) != 1)
638 log_to_fd = -1;
643 * fatal - log an error message and die horribly.
645 void
646 fatal __V((char *fmt, ...))
648 va_list pvar;
650 #if defined(__STDC__)
651 va_start(pvar, fmt);
652 #else
653 char *fmt;
654 va_start(pvar);
655 fmt = va_arg(pvar, char *);
656 #endif
658 logit(LOG_ERR, fmt, pvar);
659 va_end(pvar);
661 die(1); /* as promised */
665 * error - log an error message.
667 void
668 error __V((char *fmt, ...))
670 va_list pvar;
672 #if defined(__STDC__)
673 va_start(pvar, fmt);
674 #else
675 char *fmt;
676 va_start(pvar);
677 fmt = va_arg(pvar, char *);
678 #endif
680 logit(LOG_ERR, fmt, pvar);
681 va_end(pvar);
685 * warn - log a warning message.
687 void
688 warn __V((char *fmt, ...))
690 va_list pvar;
692 #if defined(__STDC__)
693 va_start(pvar, fmt);
694 #else
695 char *fmt;
696 va_start(pvar);
697 fmt = va_arg(pvar, char *);
698 #endif
700 logit(LOG_WARNING, fmt, pvar);
701 va_end(pvar);
705 * notice - log a notice-level message.
707 void
708 notice __V((char *fmt, ...))
710 va_list pvar;
712 #if defined(__STDC__)
713 va_start(pvar, fmt);
714 #else
715 char *fmt;
716 va_start(pvar);
717 fmt = va_arg(pvar, char *);
718 #endif
720 logit(LOG_NOTICE, fmt, pvar);
721 va_end(pvar);
725 * info - log an informational message.
727 void
728 info __V((char *fmt, ...))
730 va_list pvar;
732 #if defined(__STDC__)
733 va_start(pvar, fmt);
734 #else
735 char *fmt;
736 va_start(pvar);
737 fmt = va_arg(pvar, char *);
738 #endif
740 logit(LOG_INFO, fmt, pvar);
741 va_end(pvar);
745 * dbglog - log a debug message.
747 void
748 dbglog __V((char *fmt, ...))
750 va_list pvar;
752 #if defined(__STDC__)
753 va_start(pvar, fmt);
754 #else
755 char *fmt;
756 va_start(pvar);
757 fmt = va_arg(pvar, char *);
758 #endif
760 logit(LOG_DEBUG, fmt, pvar);
761 va_end(pvar);
764 /* Procedures for locking the serial device using a lock file. */
765 #ifndef LOCK_DIR
766 #ifdef _linux_
767 #define LOCK_DIR "/var/lock"
768 #else
769 #ifdef SVR4
770 #define LOCK_DIR "/var/spool/locks"
771 #else
772 #define LOCK_DIR "/var/spool/lock"
773 #endif
774 #endif
775 #endif /* LOCK_DIR */
777 static char lock_file[MAXPATHLEN];
780 * lock - create a lock file for the named device
783 lock(dev)
784 char *dev;
786 #ifdef LOCKLIB
787 int result;
789 result = mklock (dev, (void *) 0);
790 if (result == 0) {
791 strlcpy(lock_file, sizeof(lock_file), dev);
792 return 0;
795 if (result > 0)
796 notice("Device %s is locked by pid %d", dev, result);
797 else
798 error("Can't create lock file %s", lock_file);
799 return -1;
801 #else /* LOCKLIB */
803 char lock_buffer[12];
804 int fd, pid, n;
806 #ifdef SVR4
807 struct stat sbuf;
809 if (stat(dev, &sbuf) < 0) {
810 error("Can't get device number for %s: %m", dev);
811 return -1;
813 if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
814 error("Can't lock %s: not a character device", dev);
815 return -1;
817 slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
818 LOCK_DIR, major(sbuf.st_dev),
819 major(sbuf.st_rdev), minor(sbuf.st_rdev));
820 #else
821 char *p;
823 if ((p = strrchr(dev, '/')) != NULL)
824 dev = p + 1;
825 slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
826 #endif
828 while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
829 if (errno != EEXIST) {
830 error("Can't create lock file %s: %m", lock_file);
831 break;
834 /* Read the lock file to find out who has the device locked. */
835 fd = open(lock_file, O_RDONLY, 0);
836 if (fd < 0) {
837 if (errno == ENOENT) /* This is just a timing problem. */
838 continue;
839 error("Can't open existing lock file %s: %m", lock_file);
840 break;
842 #ifndef LOCK_BINARY
843 n = read(fd, lock_buffer, 11);
844 #else
845 n = read(fd, &pid, sizeof(pid));
846 #endif /* LOCK_BINARY */
847 close(fd);
848 fd = -1;
849 if (n <= 0) {
850 error("Can't read pid from lock file %s", lock_file);
851 break;
854 /* See if the process still exists. */
855 #ifndef LOCK_BINARY
856 lock_buffer[n] = 0;
857 pid = atoi(lock_buffer);
858 #endif /* LOCK_BINARY */
859 if (pid == getpid())
860 return 1; /* somebody else locked it for us */
861 if (pid == 0
862 || (kill(pid, 0) == -1 && errno == ESRCH)) {
863 if (unlink (lock_file) == 0) {
864 notice("Removed stale lock on %s (pid %d)", dev, pid);
865 continue;
867 warn("Couldn't remove stale lock on %s", dev);
868 } else
869 notice("Device %s is locked by pid %d", dev, pid);
870 break;
873 if (fd < 0) {
874 lock_file[0] = 0;
875 return -1;
878 pid = getpid();
879 #ifndef LOCK_BINARY
880 slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
881 write (fd, lock_buffer, 11);
882 #else
883 write(fd, &pid, sizeof (pid));
884 #endif
885 close(fd);
886 return 0;
888 #endif
892 * relock - called to update our lockfile when we are about to detach,
893 * thus changing our pid (we fork, the child carries on, and the parent dies).
894 * Note that this is called by the parent, with pid equal to the pid
895 * of the child. This avoids a potential race which would exist if
896 * we had the child rewrite the lockfile (the parent might die first,
897 * and another process could think the lock was stale if it checked
898 * between when the parent died and the child rewrote the lockfile).
901 relock(pid)
902 int pid;
904 #ifdef LOCKLIB
905 return -1;
906 #else /* LOCKLIB */
908 int fd;
909 char lock_buffer[12];
911 if (lock_file[0] == 0)
912 return -1;
913 fd = open(lock_file, O_WRONLY, 0);
914 if (fd < 0) {
915 error("Couldn't reopen lock file %s: %m", lock_file);
916 lock_file[0] = 0;
917 return -1;
920 #ifndef LOCK_BINARY
921 slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
922 write (fd, lock_buffer, 11);
923 #else
924 write(fd, &pid, sizeof(pid));
925 #endif /* LOCK_BINARY */
926 close(fd);
927 return 0;
929 #endif /* LOCKLIB */
933 * unlock - remove our lockfile
935 void
936 unlock()
938 if (lock_file[0]) {
939 #ifdef LOCKLIB
940 (void) rmlock(lock_file, (void *) 0);
941 #else
942 unlink(lock_file);
943 #endif
944 lock_file[0] = 0;