Annotation of embedaddon/mpd/src/util.c, revision 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>