Annotation of embedaddon/mpd/src/util.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * util.c
4: *
5: * Written by Archie Cobbs <archie@freebsd.org>
6: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
7: * See ``COPYRIGHT.whistle''
8: */
9:
10: #include "ppp.h"
11: #include "util.h"
12: #include <termios.h>
13:
14: #include <netdb.h>
15: #include <tcpd.h>
16: #include <sys/wait.h>
17: #include <sys/sysctl.h>
18: #include <net/route.h>
19: #include <netinet/if_ether.h>
20:
21: /*
22: * DEFINITIONS
23: */
24:
25: #define MAX_FILENAME 1000
26: #define MAX_LINE_ARGS 50
27: #define BIG_LINE_SIZE 1000
28: #define MAX_OPEN_DELAY 2
29: #define MAX_LOCK_ATTEMPTS 30
30:
31: /*
32: * INTERNAL VARIABLES
33: */
34:
35: static const u_int16_t Crc16Table[256] = {
36: /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
37: /* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
38: /* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
39: /* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
40: /* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
41: /* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
42: /* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
43: /* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
44: /* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
45: /* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
46: /* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
47: /* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
48: /* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
49: /* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
50: /* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
51: /* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
52: /* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
53: /* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
54: /* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
55: /* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
56: /* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
57: /* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
58: /* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
59: /* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
60: /* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
61: /* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
62: /* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
63: /* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
64: /* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
65: /* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
66: /* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
67: /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
68: };
69:
70: static FILE *lockFp = NULL;
71:
72: /*
73: * INTERNAL FUNCTIONS
74: */
75:
76: static int UuLock(const char *devname);
77: static int UuUnlock(const char *devname);
78:
79: static void Escape(char *line);
80: static char *ReadLine(FILE *fp, int *lineNum, char *result, int resultsize);
81:
82: static char HexVal(char c);
83:
84: static void IndexConfFile(FILE *fp, struct configfile **cf);
85:
86: struct configfiles *ConfigFilesIndex=NULL;
87:
88: #undef isspace
89: #define isspace(c) (((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\r')?1:0)
90:
91: /*
92: * LengthenArray()
93: */
94:
95: void
96: LengthenArray(void *array, size_t esize, int *alenp, const char *type)
97: {
98: void **const arrayp = (void **)array;
99: void *newa;
100:
101: newa = Malloc(type, (*alenp + 1) * esize);
102: if (*arrayp != NULL) {
103: memcpy(newa, *arrayp, *alenp * esize);
104: Freee(*arrayp);
105: }
106: *arrayp = newa;
107: (*alenp)++;
108: }
109:
110: /*
111: * ExecCmd()
112: */
113:
114: int
115: ExecCmd(int log, const char *label, const char *fmt, ...)
116: {
117: int rtn;
118: char cmd[BIG_LINE_SIZE];
119: char cmdn[BIG_LINE_SIZE];
120: va_list ap;
121:
122: va_start(ap, fmt);
123: vsnprintf(cmd, sizeof(cmd), fmt, ap);
124: va_end(ap);
125: strcpy(cmdn, cmd);
126:
127: /* Log command on the console */
128:
129: Log(log, ("[%s] system: %s", label, cmd));
130:
131: /* Hide any stdout output of command */
132:
133: snprintf(cmdn + strlen(cmdn), sizeof(cmdn) - strlen(cmdn), " >/dev/null 2>&1");
134:
135: /* Do command */
136:
137: if ((rtn = system(cmdn)))
138: Log(log|LG_ERR, ("[%s] system: command \"%s\" returned %d", label, cmd, rtn));
139:
140: /* Return command's return value */
141:
142: return(rtn);
143: }
144:
145: /*
146: * ExecCmdNosh()
147: */
148:
149: int
150: ExecCmdNosh(int log, const char *label, const char *fmt, ...)
151: {
152: int rtn;
153: char cmd[BIG_LINE_SIZE];
154: char *cmdp = &(cmd[0]);
155: char *argv[256];
156: char **arg;
157: va_list ap;
158:
159: pid_t pid, savedpid;
160: int pstat;
161: struct sigaction ign, intact, quitact;
162: sigset_t newsigblock, oldsigblock;
163:
164: va_start(ap, fmt);
165: vsnprintf(cmd, sizeof(cmd), fmt, ap);
166: va_end(ap);
167:
168: /* Log command on the console */
169: Log(log, ("[%s] exec: %s", label, cmd));
170:
171: /* Parce args */
172: for (arg = &argv[0]; (*arg = strsep(&cmdp, " \t")) != NULL;) {
173: if (**arg != '\0') {
174: if (++arg >= &argv[255])
175: break;
176: }
177: }
178: *arg = NULL;
179:
180: /* Do command */
181:
182: /*
183: * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
184: * existing signal dispositions.
185: */
186: ign.sa_handler = SIG_IGN;
187: (void)sigemptyset(&ign.sa_mask);
188: ign.sa_flags = 0;
189: (void)sigaction(SIGINT, &ign, &intact);
190: (void)sigaction(SIGQUIT, &ign, &quitact);
191: (void)sigemptyset(&newsigblock);
192: (void)sigaddset(&newsigblock, SIGCHLD);
193: (void)sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
194: switch(pid = fork()) {
195: case -1: /* error */
196: break;
197: case 0: /* child */
198: /*
199: * Restore original signal dispositions and exec the command.
200: */
201: (void)sigaction(SIGINT, &intact, NULL);
202: (void)sigaction(SIGQUIT, &quitact, NULL);
203: (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
204: close(1);
205: open("/dev/null", O_WRONLY);
206: close(2);
207: open("/dev/null", O_WRONLY);
208: execv(argv[0], argv);
209: exit(127);
210: default: /* parent */
211: savedpid = pid;
212: do {
213: pid = wait4(savedpid, &pstat, 0, (struct rusage *)0);
214: } while (pid == -1 && errno == EINTR);
215: break;
216: }
217: (void)sigaction(SIGINT, &intact, NULL);
218: (void)sigaction(SIGQUIT, &quitact, NULL);
219: (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
220:
221: rtn = (pid == -1 ? -1 : pstat);
222:
223: if (rtn)
224: Log(log|LG_ERR, ("[%s] system: command \"%s\" returned %d", label, cmd, rtn));
225:
226: /* Return command's return value */
227: return(rtn);
228: }
229:
230: /*
231: * ParseLine()
232: *
233: * Parse arguments, respecting double quotes and backslash escapes.
234: * Returns number of arguments, at most "max_args". This destroys
235: * the original line. The arguments returned are Malloc()'d strings
236: * which must be freed by the caller using FreeArgs().
237: */
238:
239: int
240: ParseLine(char *line, char *av[], int max_args, int copy)
241: {
242: int ac;
243: char *s, *arg;
244:
245: /* Get args one at a time */
246:
247: for (ac = 0; ac < max_args; ac++)
248: {
249:
250: /* Skip white space */
251:
252: while (*line && isspace(*line))
253: line++;
254:
255: /* Done? */
256:
257: if (*line == 0)
258: break;
259:
260: /* Get normal or quoted arg */
261:
262: if (*line == '"')
263: {
264:
265: /* Stop only upon matching quote or NUL */
266:
267: for (arg = ++line; *line; line++)
268: if (*line == '"')
269: {
270: *line++ = 0;
271: break;
272: }
273: else if (*line == '\\' && line[1] != 0)
274: {
275: strcpy(line, line + 1);
276: Escape(line);
277: }
278: }
279: else
280: {
281:
282: /* NUL terminate this argument at first white space */
283:
284: for (arg = line; *line && !isspace(*line); line++);
285: if (*line)
286: *line++ = 0;
287:
288: /* Convert characters */
289:
290: for (s = arg; *s; s++)
291: if (*s == '\\')
292: {
293: strcpy(s, s + 1);
294: Escape(s);
295: }
296: }
297:
298: /* Make a copy of this arg */
299:
300: if (copy) {
301: strcpy(av[ac] = Malloc(MB_CMD, strlen(arg) + 1), arg);
302: }
303: else
304: av[ac] = arg;
305: }
306:
307: #if 0
308: {
309: int k;
310:
311: printf("ParseLine: %d args:\n", ac);
312: for (k = 0; k < ac; k++)
313: printf(" [%2d] \"%s\"\n", k, av[k]);
314: }
315: #endif
316:
317: return(ac);
318: }
319:
320: /*
321: * FreeArgs()
322: */
323:
324: void
325: FreeArgs(int ac, char *av[])
326: {
327: while (ac > 0)
328: Freee(av[--ac]);
329: }
330:
331: /*
332: * Escape()
333: *
334: * Give a string, interpret the beginning characters as an escape
335: * code and return with that code converted.
336: */
337:
338: static void
339: Escape(char *line)
340: {
341: int x, k;
342: char *s = line;
343:
344: switch (*line)
345: {
346: case 't': *s = '\t'; return;
347: case 'n': *s = '\n'; return;
348: case 'r': *s = '\r'; return;
349: case 's': *s = ' '; return;
350: case '"': *s = '"'; return;
351: case '0': case '1': case '2': case '3':
352: case '4': case '5': case '6': case '7':
353: for (x = k = 0; k < 3 && *s >= '0' && *s <= '7'; s++)
354: x = (x << 3) + (*s - '0');
355: *--s = x;
356: break;
357: case 'x':
358: for (s++, x = k = 0; k < 2 && isxdigit(*s); s++)
359: x = (x << 4) + (isdigit(*s) ? (*s - '0') : (tolower(*s) - 'a' + 10));
360: *--s = x;
361: break;
362: default:
363: return;
364: }
365: strcpy(line, s);
366: }
367:
368: /*
369: * ReadFile()
370: *
371: * Read the commands specified for the target in the specified
372: * file, which can be found in the PATH_CONF_DIR directory.
373: * Returns negative if the file or target was not found.
374: */
375:
376: int
377: ReadFile(const char *filename, const char *target,
378: int (*func)(Context ctx, int ac, char *av[], const char *file, int line), Context ctx)
379: {
380: FILE *fp;
381: int ac;
382: char *av[MAX_LINE_ARGS];
383: char *line;
384: char buf[BIG_LINE_SIZE];
385: struct configfile *cf;
386: int lineNum;
387:
388: /* Open file */
389:
390: if ((fp = OpenConfFile(filename, &cf)) == NULL)
391: return(-1);
392:
393: /* Find label */
394:
395: if (SeekToLabel(fp, target, &lineNum, cf) < 0) {
396: fclose(fp);
397: return(-1);
398: }
399:
400: /* Execute command list */
401:
402: while ((line = ReadFullLine(fp, &lineNum, buf, sizeof(buf))) != NULL)
403: {
404: if (!isspace(*line))
405: {
406: break;
407: }
408: ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 0);
409: (*func)(ctx, ac, av, filename, lineNum);
410: }
411:
412: /* Done */
413:
414: fclose(fp);
415: return(0);
416: }
417:
418: /*
419: * IndexConfFile()
420: *
421: * Scan config file for labels
422: */
423:
424: static void
425: IndexConfFile(FILE *fp, struct configfile **cf)
426: {
427: char *s, *line;
428: char buf[BIG_LINE_SIZE];
429: struct configfile **tmp;
430: int lineNum;
431:
432: /* Start at beginning */
433:
434: rewind(fp);
435: lineNum = 0;
436:
437: tmp=cf;
438:
439: /* Find label */
440:
441: while ((line = ReadFullLine(fp, &lineNum, buf, sizeof(buf))) != NULL)
442: {
443: if (isspace(*line))
444: continue;
445: if ((s = strtok(line, " \t\f:"))) {
446: (*tmp)=Malloc(MB_CMDL, sizeof(struct configfile));
447: (*tmp)->label=strcpy(Malloc(MB_CMDL, strlen(s)+1),s);
448: (*tmp)->linenum=lineNum;
449: (*tmp)->seek=ftello(fp);
450: tmp=&((*tmp)->next);
451: }
452: }
453: }
454:
455: /*
456: * SeekToLabel()
457: *
458: * Find a label in file and position file pointer just after it
459: */
460:
461: int
462: SeekToLabel(FILE *fp, const char *label, int *lineNum, struct configfile *cf)
463: {
464: char *s, *line;
465: char buf[BIG_LINE_SIZE];
466: struct configfile *tmp;
467:
468: if (cf) { /* Trying to use index */
469: tmp=cf;
470: while (tmp && strcmp(tmp->label,label)) {
471: tmp=tmp->next;
472: }
473: if (tmp) {
474: fseeko(fp,tmp->seek, SEEK_SET);
475: if (lineNum)
476: *lineNum=tmp->linenum;
477: return(0);
478: }
479: } else { /* There are no index */
480:
481: /* Start at beginning */
482: rewind(fp);
483: if (lineNum)
484: *lineNum = 0;
485:
486: /* Find label */
487:
488: while ((line = ReadFullLine(fp, lineNum, buf, sizeof(buf))) != NULL)
489: {
490: if (isspace(*line))
491: continue;
492: if ((s = strtok(line, " \t\f:")) && !strcmp(s, label))
493: return(0);
494: }
495: }
496:
497: /* Not found */
498: Log(LG_ERR, ("Label '%s' not found", label));
499: return(-1);
500: }
501:
502: /*
503: * OpenConfFile()
504: *
505: * Open a configuration file
506: */
507:
508: FILE *
509: OpenConfFile(const char *name, struct configfile **cf)
510: {
511: char pathname[MAX_FILENAME];
512: FILE *fp;
513: struct configfiles **tmp;
514:
515: /* Build full pathname */
516: if (name[0] == '/')
517: snprintf(pathname, sizeof(pathname), "%s", name);
518: else
519: snprintf(pathname, sizeof(pathname), "%s/%s", gConfDirectory, name);
520:
521: /* Open file */
522:
523: if ((fp = fopen(pathname, "r")) == NULL)
524: {
525: Perror("%s: Can't open file '%s'", __FUNCTION__, pathname);
526: return(NULL);
527: }
528: (void) fcntl(fileno(fp), F_SETFD, 1);
529:
530: if (cf) {
531: tmp=&ConfigFilesIndex;
532: while ((*tmp) && strcmp((*tmp)->filename,name)) {
533: tmp=&((*tmp)->next);
534: }
535: if (!(*tmp)) {
536: (*tmp) = Malloc(MB_CMD, sizeof(struct configfiles));
537: (*tmp)->filename = strcpy(Malloc(MB_CMD, strlen(name)+1),name);
538: (*tmp)->sections = NULL;
539: (*tmp)->next = NULL;
540: IndexConfFile(fp, &((*tmp)->sections));
541: }
542: *cf=(*tmp)->sections;
543: }
544:
545: return(fp);
546: }
547:
548: /*
549: * ReadFullLine()
550: *
551: * Read a full line, respecting backslash continuations.
552: * Returns pointer to Malloc'd storage, which must be Freee'd
553: */
554:
555: char *
556: ReadFullLine(FILE *fp, int *lineNum, char *result, int resultsize)
557: {
558: int len, linelen, resultlinesize, continuation;
559: char line[BIG_LINE_SIZE];
560: char real_line[BIG_LINE_SIZE];
561: char *resultline;
562:
563: if (result!=NULL && resultsize>0) {
564: resultline=result;
565: resultlinesize=resultsize;
566: } else {
567: resultline=line;
568: resultlinesize=sizeof(line);
569: }
570:
571: resultline[0] = 0;
572: linelen = 0;
573: continuation = TRUE;
574:
575: while ( continuation )
576: {
577:
578: /* Get next real line */
579:
580: if (ReadLine(fp, lineNum, real_line, sizeof(real_line)) == NULL) {
581: if (*resultline)
582: break;
583: else
584: return(NULL);
585: }
586:
587: /* Strip trailing white space, detect backslash */
588:
589: for (len = strlen(real_line);
590: len > 0 && isspace(real_line[len - 1]);
591: len--) {};
592: real_line[len] = 0;
593:
594: if ((continuation = (len && real_line[len - 1] == '\\')))
595: real_line[len - 1] = ' ';
596:
597: /* Append real line to what we've got so far */
598:
599: strlcpy(resultline + linelen, real_line, resultlinesize - linelen);
600: linelen += len;
601: if (linelen > sizeof(line) - 1)
602: linelen = sizeof(line) - 1;
603: }
604:
605: /* Report any overflow */
606:
607: if (linelen >= sizeof(line) - 1)
608: Log(LG_ERR, ("warning: line too long, truncated"));
609:
610: /* Copy line and return */
611:
612: if (result!=NULL && resultsize>0)
613: return resultline;
614: else
615: return strcpy(Malloc(MB_CMD, linelen + 1), resultline);
616: }
617:
618: /*
619: * ReadLine()
620: *
621: * Read a line, skipping blank lines & comments. A comment
622: * is a line whose first non-white-space character is a hash.
623: */
624:
625: static char *
626: ReadLine(FILE *fp, int *lineNum, char *result, int resultsize)
627: {
628: int empty;
629: char *s;
630: int ch;
631:
632: if ((!result) || (resultsize <= 0))
633: return (NULL);
634:
635: /* Get first non-empty, non-commented line */
636: empty = TRUE;
637: while ( empty ) {
638:
639: /* Read next line from file */
640: if ((fgets(result, resultsize, fp)) == NULL)
641: return(NULL);
642: if (lineNum)
643: (*lineNum)++;
644:
645: /* Truncate long lines */
646: if (strlen(result) > (resultsize - 2)) {
647: Log(LG_ERR, ("warning: line too long, truncated"));
648: while ((ch = getc(fp)) != EOF && ch != '\n');
649: }
650:
651: /* Ignore comments */
652: s = result + strspn(result, " \t");
653: if (*s == '#') {
654: *s = 0;
655: } else {
656: /* Is this line empty? */
657: for ( ; *s; s++) {
658: if (!isspace(*s)) {
659: empty = FALSE;
660: break;
661: }
662: }
663: }
664: }
665:
666: return(result);
667: }
668:
669: /*
670: * OpenSerialDevice()
671: *
672: * Open and configure a serial device. Call ExclusiveCloseDevice()
673: * to close a file descriptor returned by this function.
674: */
675:
676: int
677: OpenSerialDevice(const char *label, const char *path, int baudrate)
678: {
679: struct termios attr;
680: int fd;
681:
682: /* Open & lock serial port */
683:
684: if ((fd = ExclusiveOpenDevice(label, path)) < 0)
685: return(-1);
686:
687: /* Set non-blocking I/O */
688:
689: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
690: {
691: Perror("[%s] can't set \"%s\" to non-blocking", label, path);
692: goto failed;
693: }
694:
695: /* Set serial port raw mode, baud rate, hardware flow control, etc. */
696:
697: if (tcgetattr(fd, &attr) < 0)
698: {
699: Perror("[%s] can't tcgetattr \"%s\"", label, path);
700: goto failed;
701: }
702:
703: cfmakeraw(&attr);
704:
705: attr.c_cflag &= ~(CSIZE|PARENB|PARODD);
706: attr.c_cflag |= (CS8|CREAD|CLOCAL|HUPCL|CCTS_OFLOW|CRTS_IFLOW);
707: attr.c_iflag &= ~(IXANY|IMAXBEL|ISTRIP|IXON|IXOFF|BRKINT|ICRNL|INLCR);
708: attr.c_iflag |= (IGNBRK|IGNPAR);
709: attr.c_oflag &= ~OPOST;
710: attr.c_lflag = 0;
711:
712: cfsetspeed(&attr, (speed_t) baudrate);
713:
714: if (tcsetattr(fd, TCSANOW, &attr) < 0)
715: {
716: Perror("[%s] can't tcsetattr \"%s\"", label, path);
717: failed:
718: ExclusiveCloseDevice(label, fd, path);
719: return(-1);
720: }
721:
722: /* OK */
723:
724: return(fd);
725: }
726:
727: /*
728: * ExclusiveOpenDevice()
729: */
730:
731: int
732: ExclusiveOpenDevice(const char *label, const char *pathname)
733: {
734: int fd, locked = FALSE;
735: const char *ttyname = NULL;
736: time_t startTime;
737:
738: /* Lock device UUCP style, if it resides in /dev */
739:
740: if (!strncmp(pathname, "/dev/", 5))
741: {
742: ttyname = pathname + 5;
743: if (UuLock(ttyname) < 0)
744: {
745: Log(LG_ERR, ("[%s] can't lock device %s", label, ttyname));
746: return(-1);
747: }
748: locked = TRUE;
749: }
750:
751: /* Open it, but give up after so many interruptions */
752:
753: for (startTime = time(NULL);
754: (fd = open(pathname, O_RDWR, 0)) < 0
755: && time(NULL) < startTime + MAX_OPEN_DELAY; )
756: if (errno != EINTR)
757: {
758: Perror("[%s] can't open %s", label, pathname);
759: if (locked)
760: UuUnlock(ttyname);
761: return(-1);
762: }
763:
764: /* Did we succeed? */
765:
766: if (fd < 0)
767: {
768: Log(LG_ERR, ("[%s] can't open %s after %d secs",
769: label, pathname, MAX_OPEN_DELAY));
770: if (locked)
771: UuUnlock(ttyname);
772: return(-1);
773: }
774: (void) fcntl(fd, F_SETFD, 1);
775:
776: /* Done */
777:
778: return(fd);
779: }
780:
781: /*
782: * ExclusiveCloseDevice()
783: */
784:
785: void
786: ExclusiveCloseDevice(const char *label, int fd, const char *pathname)
787: {
788: int rtn = -1;
789: const char *ttyname;
790: time_t startTime;
791:
792: /* Close file(s) */
793:
794: for (startTime = time(NULL);
795: time(NULL) < startTime + MAX_OPEN_DELAY && (rtn = close(fd)) < 0; )
796: if (errno != EINTR)
797: {
798: Perror("[%s] can't close %s", label, pathname);
799: break;
800: }
801:
802: /* Did we succeed? */
803:
804: if ((rtn < 0) && (errno == EINTR))
805: {
806: Log(LG_ERR, ("[%s] can't close %s after %d secs",
807: label, pathname, MAX_OPEN_DELAY));
808: DoExit(EX_ERRDEAD);
809: }
810:
811: /* Remove lock */
812:
813: if (!strncmp(pathname, "/dev/", 5))
814: {
815: ttyname = pathname + 5;
816: if (UuUnlock(ttyname) < 0)
817: Perror("[%s] can't unlock %s", label, ttyname);
818: }
819: }
820:
821: /*
822: * UuLock()
823: *
824: * Try to atomically create lockfile. Returns negative if failed.
825: */
826:
827: static int
828: UuLock(const char *ttyname)
829: {
830: int fd, pid;
831: char tbuf[sizeof(PATH_LOCKFILENAME) + MAX_FILENAME];
832: char pid_buf[64];
833:
834: snprintf(tbuf, sizeof(tbuf), PATH_LOCKFILENAME, ttyname);
835: if ((fd = open(tbuf, O_RDWR|O_CREAT|O_EXCL, 0664)) < 0)
836: {
837:
838: /* File is already locked; Check to see if the process
839: * holding the lock still exists */
840:
841: if ((fd = open(tbuf, O_RDWR, 0)) < 0)
842: {
843: Perror("%s: open(%s)", __FUNCTION__, tbuf);
844: return(-1);
845: }
846:
847: if (read(fd, pid_buf, sizeof(pid_buf)) <= 0)
848: {
849: (void)close(fd);
850: Perror("%s: read", __FUNCTION__);
851: return(-1);
852: }
853:
854: pid = atoi(pid_buf);
855:
856: if (kill(pid, 0) == 0 || errno != ESRCH)
857: {
858: (void)close(fd); /* process is still running */
859: return(-1);
860: }
861:
862: /* The process that locked the file isn't running, so we'll lock it */
863:
864: if (lseek(fd, (off_t) 0, L_SET) < 0)
865: {
866: (void)close(fd);
867: Perror("%s: lseek", __FUNCTION__);
868: return(-1);
869: }
870: }
871:
872: /* Finish the locking process */
873:
874: sprintf(pid_buf, "%10u\n", (int) gPid);
875: if (write(fd, pid_buf, strlen(pid_buf)) != strlen(pid_buf))
876: {
877: (void)close(fd);
878: (void)unlink(tbuf);
879: Perror("%s: write", __FUNCTION__);
880: return(-1);
881: }
882: (void)close(fd);
883: return(0);
884: }
885:
886: /*
887: * UuUnlock()
888: */
889:
890: static int
891: UuUnlock(const char *ttyname)
892: {
893: char tbuf[sizeof(PATH_LOCKFILENAME) + MAX_FILENAME];
894:
895: (void) sprintf(tbuf, PATH_LOCKFILENAME, ttyname);
896: return(unlink(tbuf));
897: }
898:
899: /*
900: * GenerateMagic()
901: *
902: * Generate random number which will be used as magic number.
903: * This could be made a little more "random"...
904: */
905:
906: u_long
907: GenerateMagic(void)
908: {
909: time_t now;
910: struct timeval tval;
911:
912: time(&now);
913: gettimeofday(&tval, NULL);
914: now += (tval.tv_sec ^ tval.tv_usec) + getppid();
915: now *= gPid;
916: return(now);
917: }
918:
919: /*
920: * PIDCheck()
921: *
922: * See if process is already running and deal with PID file.
923: */
924:
925: int
926: PIDCheck(const char *filename, int killem)
927: {
928: int fd = -1, n_tries;
929:
930: /* Sanity */
931:
932: assert(!lockFp);
933:
934: /* Atomically open and lock file */
935:
936: for (n_tries = 0;
937: n_tries < MAX_LOCK_ATTEMPTS
938: && (fd = open(filename, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644)) < 0;
939: n_tries++)
940: {
941: int nscan, old_pid;
942: FILE *fp;
943:
944: /* Abort on any unexpected errors */
945:
946: if (errno != EAGAIN)
947: {
948: Perror("%s: open(%s)", __FUNCTION__, filename);
949: return(-1);
950: }
951:
952: /* We're already running ... see who it is */
953:
954: if ((fp = fopen(filename, "r")) == NULL)
955: {
956: Perror("%s: fopen(%s)", __FUNCTION__, filename);
957: return(-1);
958: }
959:
960: /* If there's a PID in there, sniff it out */
961:
962: nscan = fscanf(fp, "%d", &old_pid);
963: fclose(fp);
964: if (nscan != 1)
965: {
966: Log(LG_ERR, ("%s: contents mangled", filename));
967: return(-1);
968: }
969:
970: /* Maybe kill the other guy */
971:
972: if (!killem)
973: {
974: Log(LG_ERR, ("already running as process %d", old_pid));
975: return(-1);
976: }
977: if (kill(old_pid, SIGTERM) < 0)
978: switch (errno)
979: {
980: case ESRCH:
981: Log(LG_ERR, ("process %d no longer exists", old_pid));
982: break;
983: default:
984: Perror("%s: kill(%d)", __FUNCTION__, old_pid);
985: return(-1);
986: }
987:
988: /* Wait and try again */
989:
990: Log(LG_ERR, ("waiting for process %d to die...", old_pid));
991: sleep(1);
992: }
993: if (n_tries == MAX_LOCK_ATTEMPTS)
994: {
995: Log(LG_ERR, ("can't lock %s after %d attempts", filename, n_tries));
996: return(-1);
997: }
998:
999: /* Close on exec */
1000:
1001: (void) fcntl(fd, F_SETFD, 1);
1002:
1003: /* Create a stream on top of file descriptor */
1004:
1005: if ((lockFp = fdopen(fd, "r+")) == NULL)
1006: {
1007: Perror("%s: fdopen", __FUNCTION__);
1008: return(-1);
1009: }
1010: setbuf(lockFp, NULL);
1011:
1012: /* Write my PID in there */
1013:
1014: rewind(lockFp);
1015: fprintf(lockFp, "%u\n", (u_int) gPid);
1016: fflush(lockFp);
1017: (void) ftruncate(fileno(lockFp), ftell(lockFp));
1018: return(0);
1019: }
1020:
1021: /*
1022: * GetInetSocket()
1023: *
1024: * Get a TCP socket and bind it to an address. Set SO_REUSEADDR on the socket.
1025: */
1026:
1027: int
1028: GetInetSocket(int type, struct u_addr *addr, in_port_t port, int block, char *ebuf, size_t len)
1029: {
1030: int sock;
1031: static int one = 1;
1032: struct sockaddr_storage sa;
1033:
1034: u_addrtosockaddr(addr,port,&sa);
1035:
1036: /* Get and bind non-blocking socket */
1037:
1038: if ((sock = socket(sa.ss_family, type, type == SOCK_STREAM ? IPPROTO_TCP : 0)) < 0)
1039: {
1040: snprintf(ebuf, len, "socket: %s", strerror(errno));
1041: return(-1);
1042: }
1043: (void) fcntl(sock, F_SETFD, 1);
1044: if (!block)
1045: {
1046: if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
1047: {
1048: snprintf(ebuf, len, "can't set socket non-blocking: %s", strerror(errno));
1049: close(sock);
1050: return(-1);
1051: }
1052: }
1053: if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
1054: {
1055: snprintf(ebuf, len, "setsockopt: %s", strerror(errno));
1056: close(sock);
1057: return(-1);
1058: }
1059:
1060: if (bind(sock, (struct sockaddr *) &sa, sa.ss_len) < 0)
1061: {
1062: snprintf(ebuf, len, "bind: %s", strerror(errno));
1063: close(sock);
1064: return(-1);
1065: }
1066:
1067: return(sock);
1068: }
1069:
1070:
1071: /*
1072: * TcpGetListenPort()
1073: *
1074: * Get port for incoming telnet connections
1075: */
1076:
1077: int
1078: TcpGetListenPort(struct u_addr *addr, in_port_t port, int block)
1079: {
1080: char ebuf[100];
1081: int sock;
1082: int saverrno;
1083:
1084: /* Get socket */
1085:
1086: if ((sock = GetInetSocket(SOCK_STREAM, addr, port, block, ebuf, sizeof(ebuf))) < 0)
1087: {
1088: saverrno = errno;
1089: Log(LG_ERR, ("%s", ebuf));
1090: errno = saverrno;
1091: return(-1);
1092: }
1093:
1094: /* Make socket available for connections */
1095:
1096: if (listen(sock, 2) < 0)
1097: {
1098: Perror("%s: listen", __FUNCTION__);
1099: (void) close(sock);
1100: return(-1);
1101: }
1102:
1103: /* Done */
1104:
1105: return(sock);
1106: }
1107:
1108:
1109: /*
1110: * TcpAcceptConnection()
1111: *
1112: * Accept next connection on port
1113: */
1114:
1115: int
1116: TcpAcceptConnection(int sock, struct sockaddr_storage *addr, int block)
1117: {
1118: int new_sock;
1119: socklen_t size=sizeof(struct sockaddr_storage);
1120:
1121: /* Accept incoming connection */
1122:
1123: memset(addr, 0, sizeof(*addr));
1124: if ((new_sock = accept(sock, (struct sockaddr *) addr, &size)) < 0) {
1125: Perror("%s: accept", __FUNCTION__);
1126: return(-1);
1127: }
1128:
1129: #ifdef USE_WRAP
1130: if (Enabled(&gGlobalConf.options, GLOBAL_CONF_TCPWRAPPER)) {
1131: struct request_info req;
1132: request_init(&req, RQ_DAEMON, "mpd", RQ_FILE, new_sock, NULL);
1133: fromhost(&req);
1134: if (!hosts_access(&req)) {
1135: Log(LG_ERR, ("refused connection (tcp-wrapper) from %s",
1136: eval_client(&req)));
1137: close(new_sock);
1138: return(-1);
1139: }
1140: }
1141: #endif
1142:
1143: if (!block)
1144: {
1145: (void) fcntl(new_sock, F_SETFD, 1);
1146: if (fcntl(new_sock, F_SETFL, O_NONBLOCK) < 0) {
1147: Perror("%s: fcntl", __FUNCTION__);
1148: return(-1);
1149: }
1150: }
1151:
1152: /* Done */
1153:
1154: return(new_sock);
1155: }
1156:
1157:
1158: /*
1159: * ShowMesg()
1160: */
1161:
1162: void
1163: ShowMesg(int log, const char *pref, const char *buf, int len)
1164: {
1165: char *s, mesg[256];
1166:
1167: if (len > 0)
1168: {
1169: if (len > sizeof(mesg) - 1)
1170: len = sizeof(mesg) - 1;
1171: memcpy(mesg, buf, len);
1172: mesg[len] = 0;
1173: for (s = strtok(mesg, "\r\n"); s; s = strtok(NULL, "\r\n"))
1174: Log(log, ("[%s] MESG: %s", pref, s));
1175: }
1176: }
1177:
1178: /*
1179: * Bin2Hex()
1180: */
1181:
1182: char *
1183: Bin2Hex(const unsigned char *bin, size_t len)
1184: {
1185: static char hexconvtab[] = "0123456789abcdef";
1186: size_t i, j;
1187: char *buf;
1188:
1189: buf = Malloc(MB_UTIL, len * 2 + 1);
1190: for (i = j = 0; i < len; i++) {
1191: buf[j++] = hexconvtab[bin[i] >> 4];
1192: buf[j++] = hexconvtab[bin[i] & 15];
1193: }
1194: buf[j] = 0;
1195: return buf;
1196: }
1197:
1198: /*
1199: * Hex2Bin()
1200: */
1201:
1202: u_char *
1203: Hex2Bin(char *hexstr)
1204: {
1205: int i;
1206: u_char *binval;
1207:
1208: binval = Malloc(MB_UTIL, strlen(hexstr) / 2);
1209:
1210: for (i = 0; i < strlen(hexstr) / 2; i++) {
1211: binval[i] = 16 * HexVal(hexstr[2*i]) + HexVal(hexstr[2*i+1]);
1212: }
1213:
1214: return binval;
1215: }
1216:
1217: static char
1218: HexVal(char c)
1219: {
1220: if (c >= '0' && c <= '9') {
1221: return (c - '0');
1222: } else if (c >= 'a' && c <= 'z') {
1223: return (c - 'a' + 10);
1224: } else if (c >= 'A' && c <= 'Z') {
1225: return (c - 'A' + 10);
1226: } else {
1227: return (-1);
1228: }
1229: }
1230:
1231: /*
1232: * Crc16()
1233: *
1234: * Compute the 16 bit frame check value, per RFC 1171 Appendix B,
1235: * on an array of bytes.
1236: */
1237:
1238: u_short
1239: Crc16(u_short crc, u_char *cp, int len)
1240: {
1241: while (len--)
1242: crc = (crc >> 8) ^ Crc16Table[(crc ^ *cp++) & 0xff];
1243: return(crc);
1244: }
1245:
1246: /*
1247: * GetAnyIpAddress()
1248: *
1249: * Get any non-loopback IP address owned by this machine
1250: * Prefer addresses from non-point-to-point interfaces.
1251: */
1252:
1253: int
1254: GetAnyIpAddress(struct u_addr *ipaddr, const char *ifname)
1255: {
1256: int s, p2p = 0;
1257: struct in_addr ipa = { 0 };
1258: static struct in_addr nipa = { 0 };
1259: static int have_nipa = 0;
1260: struct ifreq *ifr, *ifend;
1261: struct ifreq ifreq;
1262: struct ifconf ifc;
1263: unsigned int buffsize = IFCONF_BUFFSIZE;
1264:
1265: /* use cached IP to reduce number of syscalls */
1266: if (ifname == NULL && have_nipa) {
1267: in_addrtou_addr(&nipa, ipaddr);
1268: return(0);
1269: }
1270:
1271: /* Get socket */
1272: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1273: Perror("%s: Socket creation error", __FUNCTION__);
1274: return(-1);
1275: }
1276:
1277: /* Try simple call for the first IP on interface */
1278: if (ifname != NULL) {
1279: strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
1280: if (ioctl(s, SIOCGIFADDR, &ifreq) < 0) {
1281: if (errno != ENXIO)
1282: Perror("%s: ioctl(SIOCGIFADDR)", __FUNCTION__);
1283: close(s);
1284: return(-1);
1285: }
1286: ipa = ((struct sockaddr_in *)&ifreq.ifr_ifru.ifru_addr)->sin_addr;
1287: if ((ntohl(ipa.s_addr)>>24) == 127)
1288: ipa.s_addr = 0; /* We don't like 127.0.0.1 */
1289: }
1290:
1291: /* If simple is not enouth try complex call */
1292: if (ipa.s_addr == 0) {
1293: struct ifreq *ifs;
1294: while (1) {
1295: ifc.ifc_len = buffsize;
1296: ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len);
1297: if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
1298: Freee(ifs);
1299: if (errno != ENXIO)
1300: Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__);
1301: close(s);
1302: return(-1);
1303: }
1304:
1305: /* if used size is too close to allocated size retry with a larger buffer */
1306: if (ifc.ifc_len + 128 < buffsize)
1307: break;
1308:
1309: Freee(ifs);
1310: if (buffsize >= IFCONF_BUFFMAXSIZE) {
1311: Log(LG_ERR, ("%s: Max buffer size reached", __FUNCTION__));
1312: close(s);
1313: return(-1);
1314: }
1315: buffsize *= 2;
1316: }
1317:
1318: for (ifend = (struct ifreq *)(void *)(ifc.ifc_buf + ifc.ifc_len),
1319: ifr = ifc.ifc_req;
1320: ifr < ifend;
1321: ifr = (struct ifreq *)(void *)((char *) &ifr->ifr_addr
1322: + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
1323: if (ifr->ifr_addr.sa_family == AF_INET) {
1324:
1325: if (ifname!=NULL && strcmp(ifname,ifr->ifr_name))
1326: continue;
1327:
1328: /* Check that the interface is up; prefer non-p2p and non-loopback */
1329: strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1330: if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
1331: continue;
1332: if ((ifreq.ifr_flags & IFF_UP) != IFF_UP)
1333: continue;
1334: if ((ifreq.ifr_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) && ipa.s_addr)
1335: continue;
1336: if ((ntohl(((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr.s_addr)>>24)==127)
1337: continue;
1338:
1339: /* Save IP address and interface name */
1340: ipa = ((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr;
1341: p2p = (ifreq.ifr_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0;
1342:
1343: if (!p2p) break;
1344: }
1345: }
1346: Freee(ifs);
1347: }
1348: close(s);
1349:
1350: /* Found? */
1351: if (ipa.s_addr == 0)
1352: return(-1);
1353: if (ifname == NULL) {
1354: nipa = ipa;
1355: have_nipa = 1;
1356: }
1357: in_addrtou_addr(&ipa, ipaddr);
1358: return(0);
1359: }
1360:
1361: /*
1362: * GetEther()
1363: *
1364: * Get the hardware address of an interface on the the same subnet as addr.
1365: * If addr == NULL, finds the address of any local ethernet interface.
1366: */
1367:
1368: int
1369: GetEther(struct u_addr *addr, struct sockaddr_dl *hwaddr)
1370: {
1371: int s;
1372: struct ifreq *ifr, *bifr, *ifend, *ifp;
1373: u_int32_t ina, mask, bmask;
1374: struct ifreq ifreq;
1375: struct ifconf ifc;
1376: struct ifreq *ifs;
1377: unsigned int buffsize = IFCONF_BUFFSIZE;
1378:
1379: static struct sockaddr_dl nhwaddr;
1380: static int have_nhwaddr = 0;
1381:
1382: /* cache value to reduce number of syscalls */
1383: if (addr == NULL && have_nhwaddr) {
1384: memcpy(hwaddr, &nhwaddr,
1385: sizeof(*hwaddr));
1386: return(0);
1387: }
1388:
1389: /* Get interface list */
1390: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1391: Perror("%s: Socket creation error", __FUNCTION__);
1392: return(-1);
1393: }
1394:
1395: while (1) {
1396: ifc.ifc_len = buffsize;
1397: ifc.ifc_req = ifs = Malloc(MB_UTIL, ifc.ifc_len);
1398: if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
1399: Freee(ifs);
1400: Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__);
1401: close(s);
1402: return(-1);
1403: }
1404:
1405: /* if used size is too close to allocated size retry with a larger buffer */
1406: if (ifc.ifc_len + 128 < buffsize)
1407: break;
1408:
1409: Freee(ifs);
1410: if (buffsize >= IFCONF_BUFFMAXSIZE) {
1411: Log(LG_ERR, ("%s: Max buffer size reached", __FUNCTION__));
1412: close(s);
1413: return(-1);
1414: }
1415: buffsize *= 2;
1416: }
1417:
1418: /*
1419: * Scan through looking for an interface with an IP
1420: * address on same subnet as `addr'.
1421: */
1422: bifr = NULL;
1423: bmask = 0;
1424: for (ifend = (struct ifreq *)(void *)(ifc.ifc_buf + ifc.ifc_len),
1425: ifr = ifc.ifc_req;
1426: ifr < ifend;
1427: ifr = (struct ifreq *)(void *)((char *) &ifr->ifr_addr
1428: + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
1429: if (ifr->ifr_addr.sa_family == AF_INET) {
1430:
1431: /* Save IP address and interface name */
1432: ina = ((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr.s_addr;
1433: strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1434: ifreq.ifr_addr = ifr->ifr_addr;
1435:
1436: /* Check that the interface is up, and not point-to-point or loopback */
1437: if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
1438: continue;
1439: if ((ifreq.ifr_flags &
1440: (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1441: != (IFF_UP|IFF_BROADCAST))
1442: continue;
1443:
1444: if (addr) {
1445: /* Get its netmask and check that it's on the right subnet */
1446: if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
1447: continue;
1448: mask = ((struct sockaddr_in *)(void *)&ifreq.ifr_addr)->sin_addr.s_addr;
1449: if ((addr->u.ip4.s_addr & mask) != (ina & mask))
1450: continue;
1451: /* Is this the best match? */
1452: if (mask >= bmask) {
1453: bmask = mask;
1454: bifr = ifr;
1455: }
1456: continue;
1457: }
1458:
1459: /* OK */
1460: bifr = ifr;
1461: break;
1462: }
1463: }
1464: close(s);
1465:
1466: /* Found? */
1467: if (bifr == NULL) {
1468: Freee(ifs);
1469: return(-1);
1470: }
1471:
1472: /* Now scan again looking for a link-level address for this interface */
1473: for (ifp = bifr, ifr = ifc.ifc_req; ifr < ifend; ) {
1474: if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
1475: && ifr->ifr_addr.sa_family == AF_LINK) {
1476: if (addr == NULL) {
1477: memcpy(&nhwaddr, (struct sockaddr_dl *)(void *)&ifr->ifr_addr,
1478: sizeof(*hwaddr));
1479: have_nhwaddr = 1;
1480: }
1481: memcpy(hwaddr, (struct sockaddr_dl *)(void *)&ifr->ifr_addr,
1482: sizeof(*hwaddr));
1483: Freee(ifs);
1484: return(0);
1485: }
1486: ifr = (struct ifreq *)(void *)((char *)&ifr->ifr_addr
1487: + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
1488: }
1489:
1490: /* Not found! */
1491: Freee(ifs);
1492: return(-1);
1493: }
1494:
1495: int
1496: GetPeerEther(struct u_addr *addr, struct sockaddr_dl *hwaddr)
1497: {
1498: int mib[6];
1499: size_t needed;
1500: char *lim, *buf, *next;
1501: struct rt_msghdr *rtm;
1502: struct sockaddr_inarp *sin2;
1503: struct sockaddr_dl *sdl;
1504: int st, found_entry = 0;
1505:
1506: mib[0] = CTL_NET;
1507: mib[1] = PF_ROUTE;
1508: mib[2] = 0;
1509: mib[3] = addr->family;
1510: mib[4] = NET_RT_FLAGS;
1511: #ifdef RTF_LLINFO
1512: mib[5] = RTF_LLINFO;
1513: #else
1514: mib[5] = 0;
1515: #endif
1516: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
1517: Log(LG_ERR, ("route-sysctl-estimate"));
1518: return (0);
1519: }
1520: if (needed == 0) /* empty table */
1521: return 0;
1522: buf = NULL;
1523: for (;;) {
1524: if (buf)
1525: Freee(buf);
1526: buf = Malloc(MB_UTIL, needed);
1527: st = sysctl(mib, 6, buf, &needed, NULL, 0);
1528: if (st == 0 || errno != ENOMEM)
1529: break;
1530: needed += needed / 8;
1531: }
1532: if (st == -1) {
1533: Log(LG_ERR, ("actual retrieval of routing table"));
1534: Freee(buf);
1535: return (0);
1536: }
1537: lim = buf + needed;
1538: for (next = buf; next < lim; next += rtm->rtm_msglen) {
1539: rtm = (struct rt_msghdr *)next;
1540: sin2 = (struct sockaddr_inarp *)(rtm + 1);
1541: if (addr->u.ip4.s_addr == sin2->sin_addr.s_addr) {
1542: sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
1543: memcpy(hwaddr, sdl, sdl->sdl_len);
1544: found_entry = 1;
1545: break;
1546: }
1547: }
1548: Freee(buf);
1549: return (found_entry);
1550: }
1551:
1552: /*
1553: * Decode ASCII message
1554: */
1555: void
1556: ppp_util_ascify(char *buf, size_t bsiz, const char *data, size_t len)
1557: {
1558: char *bp;
1559: int i;
1560:
1561: for (bp = buf, i = 0; i < len; i++) {
1562: const char ch = (char)data[i];
1563:
1564: if (bsiz < 3)
1565: break;
1566: switch (ch) {
1567: case '\t':
1568: *bp++ = '\\';
1569: *bp++ = 't';
1570: bsiz -= 2;
1571: break;
1572: case '\n':
1573: *bp++ = '\\';
1574: *bp++ = 'n';
1575: bsiz -= 2;
1576: break;
1577: case '\r':
1578: *bp++ = '\\';
1579: *bp++ = 'r';
1580: bsiz -= 2;
1581: break;
1582: default:
1583: if (isprint(ch & 0x7f)) {
1584: *bp++ = ch;
1585: bsiz--;
1586: } else {
1587: *bp++ = '^';
1588: *bp++ = '@' + (ch & 0x1f);
1589: bsiz -= 2;
1590: }
1591: break;
1592: }
1593: }
1594: *bp = '\0';
1595: }
1596:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>