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>