File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / util.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:32:47 2012 UTC (12 years, 4 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_6, HEAD
mpd

    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>