home *** CD-ROM | disk | FTP | other *** search
/ PC Press: Internet / PC_PRESS.ISO / software / dos / misc / inar-100.exe / SRC / CF / CF.C next >
Encoding:
C/C++ Source or Header  |  1995-05-21  |  58.9 KB  |  2,280 lines

  1. /*
  2.  * cf.c
  3.  *
  4.  * Configuration program for PCroute 3.00 and packet drivers
  5.  *
  6.  * This program generates the configuration files for the various
  7.  * components that together convert an ordinary PC into an IP router.
  8.  * The necessary informations are taken from a master input file which
  9.  * contains the configuration data in a special description language.
  10.  *
  11.  * This program was originaly developed with the gcc 2.4.5 compiler
  12.  * under UNIX and was then compiled with TurboC 2.0. Therefore, it
  13.  * shouldn't contain any compiler specific constructions.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <stdarg.h>
  21. #include <mem.h>
  22. #include "cf.h"
  23.  
  24. /* function prototypes */
  25. uint parse_handler(unchar *cp, void **ap);
  26. uint xlate_handler(unchar *cp, void **ap);
  27.  
  28. uint net_handler(unchar *cp, void **ap);
  29. uint gateway_handler(unchar *cp, void **ap);
  30.  
  31. uint ip_handler(unchar *cp, void **ap);
  32. uint dec_handler(unchar *cp, void **ap);
  33. uint hex_handler(unchar *cp, void **ap);
  34. uint str_handler(unchar *cp, void **ap);
  35. uint strlist_handler(unchar *cp, void **ap);
  36. uint set_handler(unchar *cp, void **ap);
  37. int fprint_ip(FILE *file, ip *inet);
  38. netip to_netip(ip address);
  39.  
  40. void read_config(void);
  41. void parser(key *first);
  42. int get_cmd(unchar **keyword, unchar **remainder);
  43. key *get_key(unchar *keyword, key *first);
  44. xlate *get_xlate(unchar *keyword, xlate *first);
  45. uint get_interface(unchar *name);
  46. uint get_id(unchar *name);
  47. uint get_dupe(unchar *name, uint my_num);
  48. uint get_gateway(unchar *interface, unchar *link, uint limit);
  49. uint get_first_link(unchar *name);
  50. uint get_next_link(unchar *name, uint next);
  51. uint get_first_route(unchar *interface);
  52. uint get_next_route(unchar *interface, uint next);
  53. var *get_var(unchar *name);
  54. void fix_interfaces(void);
  55. void fix_routes(void);
  56. void fix_sources(void);
  57. void check_status(void);
  58. void traverse_status(key *kptr, uint ln);
  59. void complete_entries(void);
  60. uint make_flags(key *kptr);
  61. void write_pcroute_config(void);
  62. void write_ispa_config(void);
  63. void write_start_file(void);
  64. void expand_line(unchar *ptr, uint bufsize);
  65. void mklower(unchar *ptr);
  66. void *xmalloc(uint size);
  67. void eexit(uint line, unchar *fmt, ...);
  68.  
  69.  
  70. /*
  71.  * The following arrays of structures contain most of the syntax rules
  72.  * of the description language. They are used by the parser.
  73.  */
  74. xlate priority[] = {
  75.     {"emergency", 1},
  76.     {"alert", 2},
  77.     {"critical", 3},
  78.     {"error", 4},
  79.     {"warning", 5},
  80.     {"notice", 6},
  81.     {"info", 7},
  82.     {"debug", 8},
  83.     {NULL, 0}
  84. };
  85.  
  86. key logsource[] = {
  87.     {"system", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  88.     {"routing", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  89.     {"monitor", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  90.     {"endlogsource", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  91. };
  92.  
  93. key syslog[] = {
  94.     {"host", T_REQUIRED, S_NOTSET, ip_handler, NULL, 0},
  95.     {"priority", T_REQUIRED, S_NOTSET, xlate_handler, priority, 0},
  96.     {"logsource", T_REQUIRED, S_NOTSET, parse_handler, logsource, 0},
  97.     {"endsyslog", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  98. };
  99.  
  100. key global[] = {
  101.     {"syslog", T_OPTIONAL, S_NOTSET, parse_handler, syslog, 0},
  102.     {"bootp", T_OPTIONAL, S_NOTSET, ip_handler, NULL, 0},
  103.     {"transitnet", T_OPTIONAL, S_NOTSET, ip_handler, NULL, 0},
  104.     {"transitmask", T_OPTIONAL, S_NOTSET, ip_handler, NULL, 0},
  105.     {"prefix", T_OPTIONAL, S_NOTSET, str_handler, NULL, 0},
  106.     {"suffix", T_OPTIONAL, S_NOTSET, str_handler, NULL, 0},
  107.     {"endglobal", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  108. };
  109.  
  110. xlate itype[] = {
  111.     {"ethernet", IT_ETHERNET},
  112.     {"point2point", IT_POINT2POINT},
  113.     {"isdn", IT_ISDN},
  114.     {NULL, 0}
  115. };
  116.  
  117. key iattributes[] = {
  118.     {"send_rip", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  119.     {"listen_rip", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  120.     {"send_default_route", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  121.     {"listen_default_route", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  122.     {"poison_reverse", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  123.     {"no_directed_broadcast", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  124.     {"no_icmp_redirects", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  125.     {"hidden_interface", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  126.     {"host_route_split", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  127.     {"unreachable_network", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  128.     {"route_broadcasts", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  129.     {"global_broadcast", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  130.     {"broadcast_0", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  131.     {"proxy_arp", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  132.     {"no_reverse_check", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  133.     {"endattributes", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  134. };
  135.  
  136. xlate dsyslog[] = {
  137.     {"off", DS_OFF},
  138.     {"on", DS_ON},
  139.     {NULL, 0}
  140. };
  141.  
  142. key idriver[] = {
  143.     {"command", T_REQUIRED, S_NOTSET, str_handler, NULL, 0},
  144.     {"controller", T_REQUIRED, S_NOTSET, dec_handler, NULL, 0},
  145.     {"index", T_REQUIRED, S_NOTSET, dec_handler, NULL, 0},
  146.     {"syslog", T_REQUIRED, S_NOTSET, xlate_handler, dsyslog, 0},
  147.     {"options", T_OPTIONAL, S_NOTSET, str_handler, NULL, 0},
  148.     {"prefix", T_OPTIONAL, S_NOTSET, str_handler, NULL, 0},
  149.     {"suffix", T_OPTIONAL, S_NOTSET, str_handler, NULL, 0},
  150.     {"enddriver", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  151. };
  152.  
  153. key interface[] = {
  154.     {"name", T_REQUIRED, S_NOTSET, str_handler, NULL, 0},
  155.     {"routename", T_INHIBITED, S_NOTSET, str_handler, NULL, 0},
  156.     {"type", T_REQUIRED, S_NOTSET, xlate_handler, itype, 0},
  157.     {"address", T_REQUIRED, S_NOTSET, ip_handler, NULL, 0},
  158.     {"gateway", T_OPTIONAL, S_NOTSET, ip_handler, NULL, 0},
  159.     {"net", T_INHIBITED, S_NOTSET, ip_handler, NULL, 0},
  160.     {"netmask", T_REQUIRED, S_NOTSET, ip_handler, NULL, 0},
  161.     {"metric", T_REQUIRED, S_NOTSET, dec_handler, NULL, 0},
  162.     {"attributes", T_OPTIONAL, S_NOTSET, parse_handler, iattributes, 0},
  163.     {"driver", T_REQUIRED, S_NOTSET, parse_handler, idriver, 0},
  164.     {"endinterface", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  165. };
  166.  
  167. key rattributes[] = {
  168.     {"hidden_route", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  169.     {"host_route_split", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  170.     {"transient_route", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  171.     {"unreachable_network", T_OPTIONAL, S_NOTSET, NULL, NULL, 0},
  172.     {"endattributes", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  173. };
  174.  
  175. key route[] = {
  176.     {"name", T_REQUIRED, S_NOTSET, str_handler, NULL, 0},
  177.     {"net", T_REQUIRED, S_NOTSET, net_handler, NULL, 0},
  178.     {"netmask", T_REQUIRED, S_NOTSET, ip_handler, NULL, 0},
  179.     {"interface", T_REQUIRED, S_NOTSET, str_handler, NULL, 0},
  180.     {"link", T_OPTIONAL, S_NOTSET, str_handler, NULL, 0},
  181.     {"gateway", T_REQUIRED, S_NOTSET, gateway_handler, NULL, 0},
  182.     {"metric", T_REQUIRED, S_NOTSET, dec_handler, NULL, 0},
  183.     {"attributes", T_OPTIONAL, S_NOTSET, parse_handler, rattributes, 0},
  184.     {"endroute", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  185. };
  186.  
  187. xlate droute[] = {
  188.     {"deny", DR_DENY},
  189.     {"permit", DR_PERMIT},
  190.     {NULL, 0}
  191. };
  192.  
  193. key source[] = {
  194.     {"refer", T_REQUIRED, S_NOTSET, strlist_handler, NULL, 0},
  195.     {"net", T_REQUIRED, S_NOTSET, net_handler, NULL, 0},
  196.     {"netmask", T_REQUIRED, S_NOTSET, ip_handler, NULL, 0},
  197.     {"attach", T_REQUIRED, S_NOTSET, strlist_handler, NULL, 0},
  198.     {"route", T_REQUIRED, S_NOTSET, xlate_handler, droute, 0},
  199.     {"endsource", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  200. };
  201.  
  202. key link[] = {
  203.     {"name", T_REQUIRED, S_NOTSET, str_handler, NULL, 0},
  204.     {"address", T_REQUIRED, S_NOTSET, strlist_handler, NULL, 0},
  205.     {"options", T_OPTIONAL, S_NOTSET, str_handler, NULL, 0},
  206.     {"endlink", T_TERMINAL, S_NOTSET, NULL, NULL, 0}
  207. };
  208.  
  209. key config[] = {
  210.     {"global", T_OPTIONAL, S_NOTSET, parse_handler, global, 0},
  211.     {"interface", T_REQUIRED, S_NOTSET, parse_handler, interface, 0},
  212.     {"route", T_OPTIONAL, S_NOTSET, parse_handler, route, 0},
  213.     {"source", T_OPTIONAL, S_NOTSET, parse_handler, source, 0},
  214.     {"link", T_OPTIONAL, S_NOTSET, parse_handler, link, 0},
  215.     {"set", T_OPTIONAL, S_NOTSET, set_handler, NULL, 0}
  216. };
  217.  
  218. /* global variables and arrays */
  219. uint line = 1;
  220. uint num_globals = 0;
  221. uint num_interfaces = 0;
  222. uint num_routes = 0;
  223. uint num_internal_routes = 0;
  224. uint num_sources = 0;
  225. uint num_links = 0;
  226. FILE *src_file;
  227. unchar *prg_name;
  228. ip *default_ip;
  229. var *var_head = NULL;
  230.  
  231. key globals[MAX_GLOBALS];
  232. key interfaces[MAX_INTERFACES];
  233. key routes[MAX_ROUTES];
  234. key sources[MAX_SOURCES];
  235. key links[MAX_LINKS];
  236. ip transit_nets[MAX_INTERFACES];
  237. ip_t transit_offsets[MAX_INTERFACES];
  238. int transit_use_default[MAX_INTERFACES];
  239. unchar default_ip_ascii[] = "0.0.0.0";
  240. unchar transit_net_ascii[] = TRANSIT_NET;
  241. unchar transit_mask_ascii[] = TRANSIT_MASK;
  242. unchar host_mask_ascii[] = "255.255.255.255";
  243. unchar pcr_cfg_base[] = PCR_CFG_BASE;
  244. unchar pcr_cfg_tail[] = PCR_CFG_TAIL;
  245. unchar pcr_cfg_name[sizeof pcr_cfg_base + sizeof pcr_cfg_tail];
  246. unchar ispa_cfg_base[] = ISPA_CFG_BASE;
  247. unchar ispa_cfg_tail[] = ISPA_CFG_TAIL;
  248. unchar ispa_cfg_name[sizeof ispa_cfg_base + sizeof ispa_cfg_tail];
  249. unchar start_file_name[] = START_FILE_NAME;
  250. unchar version[] = "@(#)cf.c    1.00";
  251.  
  252.  
  253. int main(int argc, char *argv[])
  254. {
  255.     prg_name = argv[0];
  256.  
  257.     printf("INAR configuration compiler (version 1.00)\n");
  258.  
  259.     if (argc != 2) {
  260.         fprintf(stderr, "%s: wrong number of arguments\n", prg_name);
  261.         exit(2);
  262.     }
  263.  
  264.     /* open the description file */
  265.     if ((src_file = fopen(argv[1], "rt")) == NULL) {
  266.         fprintf(stderr, "%s: can't open file `%s'\n", prg_name, argv[1]);
  267.         exit(2);
  268.     }
  269.  
  270.     /* read and parse the description */
  271.     read_config();
  272.     fclose(src_file);
  273.  
  274.     /* clean up the description's internal representation */
  275.     fix_interfaces();
  276.     fix_routes();
  277.     fix_sources();
  278.     check_status();
  279.     complete_entries();
  280.  
  281.         /* now generate the various config files */
  282.     write_pcroute_config();
  283.     write_ispa_config();
  284.     write_start_file();
  285.  
  286.     /* some statistics */
  287.     printf("Globals: %u, Interfaces: %u, Routes: %u, Sources: %u, Links: %u\n",
  288.             num_globals,
  289.             num_interfaces,
  290.             num_routes - num_internal_routes,
  291.             num_sources,
  292.             num_links);
  293.     exit(0);
  294. }
  295.  
  296. /*
  297.  * Read the description file and parse it.
  298.  */
  299. void read_config(void)
  300. {
  301.     unchar    *keyword, *remainder;
  302.     register key     *kptr;
  303.  
  304.     for (;;) {
  305.         if (!get_cmd(&keyword, &remainder))
  306.             return;    /* return on EOF */
  307.  
  308.         if ((kptr = get_key(keyword, config)) == NULL)
  309.             eexit(line, "illegal keyword `%s'", keyword);
  310.  
  311.         /* determine the root type of the entry */
  312.         switch (kptr - config) {
  313.             case 0:    /* global */
  314.                 if (num_globals >= MAX_GLOBALS)
  315.                     eexit(line, "too many global entries");
  316.                 (void) memcpy((void *) &globals[num_globals],
  317.                         (void *) kptr, sizeof(key));
  318.                 kptr = &globals[num_globals];
  319.                 ++num_globals;
  320.                 break;
  321.  
  322.             case 1:    /* interface */
  323.                 if (num_interfaces >= MAX_INTERFACES)
  324.                     eexit(line, "too many interface entries");
  325.                 (void) memcpy((void *) &interfaces[num_interfaces],
  326.                         (void *) kptr, sizeof(key));
  327.                 kptr = &interfaces[num_interfaces];
  328.                 ++num_interfaces;
  329.                 break;
  330.  
  331.             case 2:    /* route */
  332.                 if (num_routes >= MAX_ROUTES)
  333.                     eexit(line, "too many route entries");
  334.                 (void) memcpy((void *) &routes[num_routes],
  335.                         (void *) kptr, sizeof(key));
  336.                 kptr = &routes[num_routes];
  337.                 ++num_routes;
  338.                 break;
  339.  
  340.             case 3:    /* source */
  341.                 if (num_sources >= MAX_SOURCES)
  342.                     eexit(line, "too many source entries");
  343.                 (void) memcpy((void *) &sources[num_sources],
  344.                         (void *) kptr, sizeof(key));
  345.                 kptr = &sources[num_sources];
  346.                 ++num_sources;
  347.                 break;
  348.  
  349.             case 4:    /* link */
  350.                 if (num_links >= MAX_LINKS)
  351.                     eexit(line, "too many link entries");
  352.                 (void) memcpy((void *) &links[num_links],
  353.                         (void *) kptr, sizeof(key));
  354.                 kptr = &links[num_links];
  355.                 ++num_links;
  356.                 break;
  357.  
  358.             case 5:    /* set */
  359.                 {
  360.                     key    dummy;
  361.  
  362.                     (void) memcpy((void *) &dummy,
  363.                         (void *) kptr, sizeof(key));
  364.                     kptr = &dummy;
  365.                 }
  366.                 break;
  367.  
  368.             default:
  369.                 eexit(line, "impossible error");
  370.                 break;
  371.         }
  372.  
  373.  
  374.         /* fill in the root structure */
  375.         kptr->line = line;
  376.         kptr->status = S_SET;
  377.  
  378.         /*
  379.          * If there is a handler for sub-keywords assigned this
  380.          * will lead to recursive parsing of the entry.
  381.          */
  382.         if (kptr->handler)
  383.             kptr->status = (*kptr->handler)(remainder, &kptr->arg);
  384.     }
  385. }
  386.  
  387. /*
  388.  * Recursively parse the description file entries.
  389.  */
  390. void parser(key *first)
  391. {
  392.     unchar    *keyword, *remainder;
  393.     register key     *kptr;
  394.  
  395.     for (;;) {
  396.         if (!get_cmd(&keyword, &remainder))
  397.             eexit(line, "unexpected end of file");
  398.  
  399.         if ((kptr = get_key(keyword, first)) == NULL)
  400.             eexit(line, "illegal keyword `%s'", keyword);
  401.  
  402.         if (kptr->status != S_NOTSET)
  403.             eexit(line, "duplicate keyword `%s'", keyword);
  404.  
  405.         /* fill in the current keyword's structure */
  406.         kptr->line = line;
  407.         kptr->status = S_SET;
  408.  
  409.         /*
  410.          * Return if we've found the closing brace of this
  411.          * recursion level.
  412.          */
  413.         if (kptr->type == T_TERMINAL)
  414.             return;
  415.  
  416.         /*
  417.          * If there is a handler for sub-keywords assigned this
  418.          * will lead to recursive parsing of the entry.
  419.          */
  420.         if (kptr->handler)
  421.             kptr->status = (*kptr->handler)(remainder, &kptr->arg);
  422.     }
  423. }
  424.  
  425. /*
  426.  * Read the next line from the description file and return the keyword
  427.  * and the remainder of the line. This function returns TRUE if it
  428.  * delivers a valid line and FALSE on EOF.
  429.  */
  430. int get_cmd(unchar **keyword, unchar **remainder)
  431. {
  432.     static unchar    inbuf[INBUF_SIZE];
  433.     static uint    lcnt = 0;
  434.     register unchar    *ptr;
  435.     unchar    *iptr;
  436.     register uint    c;
  437.  
  438.     iptr = inbuf;
  439.     line += lcnt;
  440.     lcnt = 0;
  441.  
  442.     for (;;) {
  443.         /* read in the next line */
  444.         if (fgets(iptr, &inbuf[INBUF_SIZE] - iptr, src_file) == NULL)
  445.             return FALSE;
  446.  
  447.         /* skip leading white spaces */
  448.         for (ptr = iptr; (c = *ptr) == ' ' || c == '\t'; ++ptr)
  449.             ;
  450.  
  451.         if (ptr != iptr) {
  452.             /* remove leading white spaces */
  453.             (void) memmove(iptr, ptr, strlen(ptr) + 1);
  454.         }
  455.  
  456.         /* fix newline */
  457.         if ((ptr = strchr(iptr, '\n')) == NULL)
  458.             if (feof(src_file))
  459.                 ptr = strchr(iptr, '\0');
  460.             else
  461.                 eexit(line + lcnt, "line too long");
  462.         else
  463.             *ptr = '\0';
  464.  
  465.         ++lcnt;
  466.  
  467.         if (--ptr >= inbuf && *ptr == '\\') {
  468.             iptr = ptr;
  469.             continue;
  470.         }
  471.  
  472.         /* special character handling */
  473.         expand_line(inbuf, INBUF_SIZE);
  474.  
  475.         /* now get rid of trailing white spaces */
  476.         for (ptr = strchr(inbuf, '\0') - 1;
  477.             ptr >= inbuf && ((c = *ptr) == ' ' || c == '\t');
  478.             --ptr)
  479.             ;
  480.         *++ptr = '\0';
  481.  
  482.         /* skip leading white spaces */
  483.         for (ptr = inbuf; (c = *ptr) == ' ' || c == '\t'; ++ptr)
  484.             ;
  485.  
  486.         if (c == '\0') {
  487.             iptr = inbuf;
  488.             line += lcnt;
  489.             lcnt = 0;
  490.             continue;    /* line is empty */
  491.         }
  492.  
  493.         *keyword = ptr;
  494.  
  495.         /* advance to the next white space or EOL */
  496.         for (; (c = *ptr) != ' ' && c != '\t' && c != '\0'; ++ptr)
  497.             *ptr = tolower(c);
  498.         if (c == '\0') {
  499.             *remainder = NULL;    /* no remainder */
  500.             return TRUE;
  501.         }
  502.         *ptr = '\0';
  503.  
  504.         /* skip white spaces */
  505.         for (++ptr; (c = *ptr) == ' ' || c == '\t'; ++ptr)
  506.             ;
  507.  
  508.         *remainder = ptr;
  509.  
  510.         return TRUE;
  511.     }
  512. }
  513.  
  514. /*
  515.  * Lookup a keyword structure matching the current keyword. If one was
  516.  * found return a pointer to it, otherwise NULL.
  517.  */
  518. key *get_key(register unchar *keyword, key *first)
  519. {
  520.     register key    *kptr;
  521.  
  522.     /* lookup matching entry */
  523.     for (kptr = first; kptr->type != T_TERMINAL; ++kptr)
  524.         if (*kptr->keyword == *keyword
  525.                 && !strcmp(kptr->keyword, keyword))
  526.             return kptr;    /* found */
  527.  
  528.     /* check terminal entry */
  529.     if (*kptr->keyword == *keyword
  530.             && !strcmp(kptr->keyword, keyword))
  531.         return kptr;    /* found */
  532.  
  533.     return NULL;    /* not found */
  534. }
  535.  
  536. /*
  537.  * Lookup an xlate structure matching the current keyword. If one was
  538.  * found return a pointer to it, otherwise NULL.
  539.  */
  540. xlate *get_xlate(register unchar *keyword, xlate *first)
  541. {
  542.     register xlate    *xptr;
  543.  
  544.     /* lookup matching entry */
  545.     for (xptr = first; xptr->keyword; ++xptr)
  546.         if (*xptr->keyword == *keyword
  547.                 && !strcmp(xptr->keyword, keyword))
  548.             return xptr;    /* found */
  549.  
  550.     return NULL;    /* not found */
  551. }
  552.  
  553. /*
  554.  * Lookup an interface entry by its name.
  555.  *
  556.  * Must not be called before fix_interfaces() has done its job !!!
  557.  */
  558. uint get_interface(unchar *name)
  559. {
  560.     register key    *kptr;
  561.     register uint    i;
  562.  
  563.     /* scan through the interface entries and compare the names */
  564.     for (i = 0; i < num_interfaces; ++i) {
  565.         kptr = get_key("name", (key *) interfaces[i].arg);
  566.         if (*((unchar *) kptr->arg) == *name
  567.                 && !strcmp((unchar *) kptr->arg, name))
  568.             return i;
  569.     }
  570.     fprintf(stderr, "%s: interface `%s' not found\n", prg_name, name);
  571.     exit(2);
  572. }
  573.  
  574. /*
  575.  * Lookup an interface or route entry by its name.
  576.  *
  577.  * Must not be called before interface and route entries have been
  578.  * completed in complete_entries() !!!
  579.  */
  580. uint get_id(unchar *name)
  581. {
  582.     register key    *kptr;
  583.     register uint    i;
  584.  
  585.     /* scan through the interface entries and compare the names */
  586.     for (i = 0; i < num_interfaces; ++i) {
  587.         kptr = get_key("routename", (key *) interfaces[i].arg);
  588.         if (kptr->arg == NULL)
  589.             continue;
  590.         if (*((unchar *) kptr->arg) == *name
  591.                 && !strcmp((unchar *) kptr->arg, name))
  592.             return i;
  593.     }
  594.     /* scan through the route entries and compare the names */
  595.     for (i = 0; i < num_routes; ++i) {
  596.         kptr = get_key("name", (key *) routes[i].arg);
  597.         if (*((unchar *) kptr->arg) == *name
  598.                 && !strcmp((unchar *) kptr->arg, name))
  599.             return i + num_interfaces;
  600.     }
  601.     fprintf(stderr, "%s: interface/route `%s' not found or not valid\n",
  602.             prg_name, name);
  603.     exit(2);
  604. }
  605.  
  606. /*
  607.  * Lookup duplicate interface or route entries by name.
  608.  *
  609.  * Must not be called before fix_interfaces() and fix_routes() have
  610.  * done their jobs !!!
  611.  */
  612. uint get_dupe(unchar *name, uint my_num)
  613. {
  614.     register key    *kptr;
  615.     register uint    i;
  616.     uint    start;
  617.  
  618.     start = my_num + 1;
  619.     if (start < num_interfaces) {
  620.         /* scan through the interface entries and compare the names */
  621.         for (i = start; i < num_interfaces; ++i) {
  622.             kptr = get_key("name", (key *) interfaces[i].arg);
  623.             if (*((unchar *) kptr->arg) == *name
  624.                     && !strcmp((unchar *) kptr->arg, name))
  625.                 return i;
  626.         }
  627.         start = 0;
  628.     } else
  629.         start -= num_interfaces;
  630.  
  631.     /* scan through the route entries and compare the names */
  632.     for (i = start; i < num_routes; ++i) {
  633.         kptr = get_key("name", (key *) routes[i].arg);
  634.         if (*((unchar *) kptr->arg) == *name
  635.                 && !strcmp((unchar *) kptr->arg, name))
  636.             return i + num_interfaces;
  637.     }
  638.  
  639.     return my_num;
  640. }
  641.  
  642. /*
  643.  * Check whether there is already an entry in the route table with
  644.  * the same interface and link name. Return its index if found,
  645.  * otherwise the index limit (one past the last route entry).
  646.  */
  647. uint get_gateway(unchar *interface, unchar *link, uint limit)
  648. {
  649.     register key    *kptr;
  650.     key    *first;
  651.     register uint    i;
  652.  
  653.     /* scan through the route entries and compare the names */
  654.     for (i = 0; i < limit; ++i) {
  655.         first = (key *) routes[i].arg;
  656.         kptr = get_key("interface", first);
  657.         if (*((unchar *) kptr->arg) != *interface
  658.                 || strcmp((unchar *) kptr->arg, interface))
  659.             continue;
  660.         kptr = get_key("link", first);
  661.         if (kptr->status == S_SET && *((unchar *) kptr->arg) == *link
  662.                 && !strcmp((unchar *) kptr->arg, link))
  663.             return i;
  664.     }
  665.     return limit;
  666. }
  667.  
  668. /*
  669.  * Get the first link that matches the given name.
  670.  */
  671. uint get_first_link(unchar *name)
  672. {
  673.     uint    result;
  674.  
  675.     /* we just call get_next_link() with a start index of 0 */
  676.     if ((result = get_next_link(name, 0)) < num_links)
  677.         return result;
  678.     fprintf(stderr, "%s: link `%s' not found\n", prg_name, name);
  679.     exit(2);
  680. }
  681.  
  682. /*
  683.  * Get the next link that matches the given name, starting the lookup
  684.  * at the specified index. Return its index if found, otherwise the
  685.  * index limit (one past the last link entry).
  686.  */
  687. uint get_next_link(unchar *name, uint next)
  688. {
  689.     register key    *kptr;
  690.     register uint    i;
  691.  
  692.     /* scan through the link entries and compare the names */
  693.     for (i = next; i < num_links; ++i) {
  694.         kptr = get_key("name", (key *) links[i].arg);
  695.         if (*((unchar *) kptr->arg) == *name
  696.                 && !strcmp((unchar *) kptr->arg, name))
  697.             return i;
  698.     }
  699.     return num_links;
  700. }
  701.  
  702. /*
  703.  * Get the first route that points to the given interface.
  704.  */
  705. uint get_first_route(unchar *interface)
  706. {
  707.     /* we just call get_next_route() with a start index of 0 */
  708.     return get_next_route(interface, 0);
  709. }
  710.  
  711. /*
  712.  * Get the next route that points to the given interface, starting the
  713.  * lookup at the specified index. Return its index if found, otherwise
  714.  * the index limit (one past the last route entry).
  715.  */
  716. uint get_next_route(unchar *interface, uint next)
  717. {
  718.     register key    *kptr;
  719.     register uint    i;
  720.  
  721.     /* scan through the route entries and compare the names */
  722.     for (i = next; i < num_routes; ++i) {
  723.         kptr = get_key("interface", (key *) routes[i].arg);
  724.         if (*((unchar *) kptr->arg) == *interface
  725.                 && !strcmp((unchar *) kptr->arg, interface))
  726.             return i;
  727.     }
  728.     return num_routes;
  729. }
  730.  
  731. /*
  732.  * Get the variable with the given name.
  733.  */
  734. var *get_var(register unchar *name)
  735. {
  736.     register var    *vptr;
  737.  
  738.     for (vptr = var_head; vptr; vptr = vptr->next) {
  739.         if (*vptr->name == *name && !strcmp(vptr->name, name))
  740.             return vptr;
  741.     }
  742.     return NULL;
  743. }
  744.  
  745. /*
  746.  * The current keyword needs recursive parsing.
  747.  */
  748. uint parse_handler(unchar *cp, void **ap)
  749. {
  750.     register key    *kptr;
  751.     register void    *mptr;
  752.     uint    len;
  753.  
  754.     if ((kptr = (key *) *ap) == NULL)
  755.         eexit(line, "NULL argument pointer");
  756.  
  757.     /* calculate the length of the array we're about to copy */
  758.     while ((kptr++)->type != T_TERMINAL)
  759.         ;
  760.     len = (unchar *) kptr - (unchar *) *ap;
  761.     mptr = xmalloc(len);
  762.     (void) memcpy(mptr, *ap, len);
  763.  
  764.         /* now we parse the entry */
  765.     parser((key *) mptr);
  766.     *ap = mptr;
  767.     return S_TRAVERSE;
  768. }
  769.  
  770. /*
  771.  * The current keyword has a symbolic argument that needs to be
  772.  * translated into a numeric argument.
  773.  */
  774. uint xlate_handler(register unchar *cp, void **ap)
  775. {
  776.     xlate    *xptr;
  777.     register void    *mptr;
  778.  
  779.     if (cp == NULL)
  780.         eexit(line, "missing argument");
  781.     if (*ap == NULL)
  782.         eexit(line, "NULL argument pointer");
  783.     mklower(cp);
  784.  
  785.     /* lookup the matching entry */
  786.     if ((xptr = get_xlate(cp, (xlate *) *ap)) == NULL)
  787.         eexit(line, "illegal argument `%s'", cp);
  788.     mptr = xmalloc(sizeof(uint));
  789.     *((uint *) mptr) = xptr->val;
  790.     *ap = mptr;
  791.     return S_SET;
  792. }
  793.  
  794. /*
  795.  * The current keyword has a numeric IP address argument or one
  796.  * symbolic argument.
  797.  */
  798. uint net_handler(register unchar *cp, void **ap)
  799. {
  800.     if (cp == NULL)
  801.         eexit(line, "missing argument");
  802.     mklower(cp);
  803.     if (!strcmp("default", cp)) {
  804.         *ap = NULL;
  805.         return S_SET;
  806.     }
  807.     return ip_handler(cp, ap);
  808. }
  809.  
  810. /*
  811.  * The current keyword has a numeric IP address argument or one
  812.  * symbolic argument.
  813.  */
  814. uint gateway_handler(register unchar *cp, void **ap)
  815. {
  816.     if (cp == NULL)
  817.         eexit(line, "missing argument");
  818.     mklower(cp);
  819.     if (!strcmp("direct", cp)) {
  820.         *ap = NULL;
  821.         return S_SET;
  822.     }
  823.     return ip_handler(cp, ap);
  824. }
  825.  
  826. /*
  827.  * The current keyword has a numeric IP address argument.
  828.  */
  829. uint ip_handler(unchar *cp, void **ap)
  830. {
  831.     register void    *mptr;
  832.     uint    bytes[4];
  833.  
  834.     if (cp == NULL)
  835.         eexit(line, "missing argument");
  836.     if (sscanf(cp, "%u.%u.%u.%u", &bytes[0], &bytes[1], &bytes[2],
  837.                     &bytes[3]) != 4)
  838.         eexit(line, "illegal argument `%s'", cp);
  839.     mptr = xmalloc(sizeof(ip));
  840.     /* convert network byte order to internal byte order */
  841.     ((unchar *) mptr)[3] = bytes[0];
  842.     ((unchar *) mptr)[2] = bytes[1];
  843.     ((unchar *) mptr)[1] = bytes[2];
  844.     ((unchar *) mptr)[0] = bytes[3];
  845.     *ap = mptr;
  846.     return S_SET;
  847. }
  848.  
  849. /*
  850.  * The current keyword has a decimal argument.
  851.  */
  852. uint dec_handler(unchar *cp, void **ap)
  853. {
  854.     register void    *mptr;
  855.     uint    val;
  856.  
  857.     if (cp == NULL)
  858.         eexit(line, "missing argument");
  859.     if (sscanf(cp, "%u", &val) != 1)
  860.         eexit(line, "illegal argument `%s'", cp);
  861.     mptr = xmalloc(sizeof(uint));
  862.     *((uint *) mptr) = val;
  863.     *ap = mptr;
  864.     return S_SET;
  865. }
  866.  
  867. /*
  868.  * The current keyword has a hexadecimal argument.
  869.  */
  870. uint hex_handler(unchar *cp, void **ap)
  871. {
  872.     register void    *mptr;
  873.     uint    val;
  874.  
  875.     if (cp == NULL)
  876.         eexit(line, "missing argument");
  877.     if (sscanf(cp, "%x", &val) != 1)
  878.         eexit(line, "illegal argument `%s'", cp);
  879.     mptr = xmalloc(sizeof(uint));
  880.     *((uint *) mptr) = val;
  881.     *ap = mptr;
  882.     return S_SET;
  883. }
  884.  
  885. /*
  886.  * The current keyword has a character string argument.
  887.  */
  888. uint str_handler(unchar *cp, void **ap)
  889. {
  890.     register void    *mptr;
  891.     register uint    len;
  892.  
  893.     if (cp == NULL)
  894.         eexit(line, "missing argument");
  895.     len = strlen(cp) + 1;
  896.     mptr = xmalloc(len);
  897.     memcpy(mptr, (void *) cp, len);
  898.     *ap = mptr;
  899.     return S_SET;
  900. }
  901.  
  902. /*
  903.  * The current keyword has a list of comma separated character
  904.  * string arguments.
  905.  */
  906. uint strlist_handler(unchar *cp, void **ap)
  907. {
  908.     register unchar    *cptr;
  909.     unchar    *bptr, *tcptr;
  910.     unchar    **lptr, **clptr;
  911.     register uint    c;
  912.     uint    i, lc;
  913.  
  914.     (void) str_handler(cp, (void **) &bptr);
  915.  
  916.     /* count the fields */
  917.     for (cptr = bptr, i = 2; *cptr; ++cptr)
  918.         if (*cptr == ',')
  919.             ++i;
  920.     clptr = lptr = (unchar **) xmalloc(sizeof(unchar *) * i);
  921.     tcptr = bptr;
  922.  
  923.     do {
  924.         /* skip leading white spaces */
  925.         for (cptr = tcptr; (c = *cptr) == ' ' || c == '\t'; ++cptr)
  926.             ;
  927.         *clptr++ = bptr = cptr;
  928.         /* find next field separator */
  929.         for (; (c = *cptr) && c != ','; ++cptr)
  930.             ;
  931.         tcptr = cptr;
  932.         lc = c;
  933.         /* now get rid of trailing white spaces */
  934.         for (--cptr; cptr >= bptr && ((c = *cptr) == ' ' || c == '\t');
  935.                 --cptr)
  936.             ;
  937.         *++cptr = '\0';
  938.         ++tcptr;
  939.     } while (lc);
  940.  
  941.     *clptr = NULL;
  942.     *ap = (void *) lptr;
  943.     return S_SET;
  944. }
  945.  
  946. /*
  947.  * The current keyword has a variable assignment argument.
  948.  */
  949. uint set_handler(register unchar *cp, void **ap)
  950. {
  951.     var    *vptr;
  952.     void    *mptr;
  953.     unchar    *name, *val;
  954.     register uint    c;
  955.     uint    len;
  956.  
  957.     if (cp == NULL)
  958.         eexit(line, "missing argument");
  959.  
  960.     name = cp;
  961.  
  962.     /* advance to the next white space or EOL */
  963.     for (; (c = *cp) != ' ' && c != '\t' && c != '\0'; ++cp)
  964.         ;
  965.     if (c == '\0') {
  966.         val = NULL;    /* no value */
  967.     } else {
  968.         *cp = '\0';
  969.  
  970.         /* skip white spaces */
  971.         for (++cp; (c = *cp) == ' ' || c == '\t'; ++cp)
  972.             ;
  973.  
  974.         val = cp;
  975.     }
  976.  
  977.     /* find or create a var object */
  978.     if ((vptr = get_var(name)) == NULL) {
  979.         vptr = (var *) xmalloc(sizeof(var));
  980.         vptr->next = var_head;
  981.         var_head = vptr;
  982.         len = strlen(name) + 1;
  983.         mptr = xmalloc(len);
  984.         memcpy(mptr, (void *) name, len);
  985.         vptr->name = (unchar *) mptr;
  986.     } else if (vptr->val) {
  987.         free(vptr->val);
  988.     }
  989.  
  990.     /* assign a value to the var object */
  991.     if (val == NULL) {
  992.         vptr->val = NULL;
  993.     } else {
  994.         len = strlen(val) + 1;
  995.         mptr = xmalloc(len);
  996.         memcpy(mptr, (void *) val, len);
  997.         vptr->val = (unchar *) mptr;
  998.     }
  999.     return S_SET;
  1000. }
  1001.  
  1002. /*
  1003.  * Print a numeric IP address.
  1004.  */
  1005. int fprint_ip(FILE *file, register ip *inet)
  1006. {
  1007.     return fprintf(file, "%u.%u.%u.%u", ((unchar *) inet)[3],
  1008.                         ((unchar *) inet)[2],
  1009.                         ((unchar *) inet)[1],
  1010.                         ((unchar *) inet)[0]);
  1011. }
  1012.  
  1013. /*
  1014.  * Convert internal byte order to network byte order.
  1015.  */
  1016. netip to_netip(ip address)
  1017. {
  1018.     netip    netaddress;
  1019.  
  1020.     netaddress.addr[3] = ((unchar *) &address)[0];
  1021.     netaddress.addr[2] = ((unchar *) &address)[1];
  1022.     netaddress.addr[1] = ((unchar *) &address)[2];
  1023.     netaddress.addr[0] = ((unchar *) &address)[3];
  1024.     return netaddress;
  1025. }
  1026.  
  1027. /*
  1028.  * Change the type field of certain keyword entries depending on the
  1029.  * kind of interface they belong to.
  1030.  */
  1031. void fix_interfaces(void)
  1032. {
  1033.     register key    *kptr;
  1034.     register key    *first;
  1035.     key    *first1;
  1036.     uint    i, ln, type;
  1037.  
  1038.     if (num_interfaces < 2) {
  1039.         fprintf(stderr, "%s: less than two interfaces defined\n",
  1040.                     prg_name);
  1041.         exit(2);
  1042.     }
  1043.     for (i = 0; i < num_interfaces; ++i) {
  1044.         kptr = &interfaces[i];
  1045.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1046.             eexit(kptr->line, "interface traverse error");
  1047.         first = (key *) kptr->arg;
  1048.  
  1049.         /* determine the interface type */
  1050.         kptr = get_key("type", first);
  1051.         if (kptr->status != S_SET || kptr->arg == NULL)
  1052.             eexit(interfaces[i].line, "interface type not set");
  1053.         type = *((uint *) (kptr->arg));
  1054.         ln = kptr->line;
  1055.  
  1056.         kptr = get_key("name", first);
  1057.         if (kptr->status != S_SET || kptr->arg == NULL)
  1058.             eexit(interfaces[i].line, "interface name not set");
  1059.  
  1060.         if (type != IT_POINT2POINT) {
  1061.             kptr = get_key("gateway", first);
  1062.             kptr->type = T_INHIBITED;
  1063.         }
  1064.  
  1065.         /*
  1066.          * We don't need several keywords if this is a
  1067.          * point-to-point interface. So we inhibit them.
  1068.          */
  1069.         if (type != IT_ETHERNET) {
  1070.             kptr = get_key("netmask", first);
  1071.             kptr->type = T_INHIBITED;
  1072.  
  1073.             kptr = get_key("attributes", first);
  1074.             if (kptr->status == S_TRAVERSE) {
  1075.                 if (kptr->arg == NULL)
  1076.                     eexit(kptr->line,
  1077.                      "interface attributes traverse error");
  1078.                 first1 = (key *) kptr->arg;
  1079.                 kptr = get_key("no_directed_broadcast", first1);
  1080.                 kptr->type = T_INHIBITED;
  1081.                 kptr = get_key("no_icmp_redirects", first1);
  1082.                 kptr->type = T_INHIBITED;
  1083.                 kptr = get_key("hidden_interface", first1);
  1084.                 kptr->type = T_INHIBITED;
  1085.                 kptr = get_key("host_route_split", first1);
  1086.                 kptr->type = T_INHIBITED;
  1087.                 kptr = get_key("unreachable_network", first1);
  1088.                 kptr->type = T_INHIBITED;
  1089.                 kptr = get_key("route_broadcasts", first1);
  1090.                 kptr->type = T_INHIBITED;
  1091.                 kptr = get_key("global_broadcast", first1);
  1092.                 kptr->type = T_INHIBITED;
  1093.                 kptr = get_key("broadcast_0", first1);
  1094.                 kptr->type = T_INHIBITED;
  1095.                 kptr = get_key("proxy_arp", first1);
  1096.                 kptr->type = T_INHIBITED;
  1097.             }
  1098.         }
  1099.  
  1100.         kptr = get_key("driver", first);
  1101.         if (kptr->status == S_TRAVERSE) {
  1102.             if (kptr->arg == NULL)
  1103.                 eexit(kptr->line,
  1104.                     "interface driver traverse error");
  1105.             first1 = (key *) kptr->arg;
  1106.  
  1107.             /*
  1108.              * Each interface type has its own set of driver
  1109.              * keywords. We inhibit those we don't need.
  1110.              */
  1111.             switch (type) {
  1112.                 case IT_ETHERNET:
  1113.                 case IT_POINT2POINT:
  1114.                     kptr = get_key("controller", first1);
  1115.                     kptr->type = T_INHIBITED;
  1116.                     kptr = get_key("index", first1);
  1117.                     kptr->type = T_INHIBITED;
  1118.                     kptr = get_key("syslog", first1);
  1119.                     kptr->type = T_INHIBITED;
  1120.                     kptr = get_key("options", first1);
  1121.                     kptr->type = T_INHIBITED;
  1122.                     break;
  1123.  
  1124.                 case IT_ISDN:
  1125.                     kptr = get_key("command", first1);
  1126.                     kptr->type = T_INHIBITED;
  1127.                     break;
  1128.  
  1129.                 default:
  1130.                     eexit(ln, "impossible error");
  1131.                     break;
  1132.             }
  1133.         }
  1134.     }
  1135. }
  1136.  
  1137. /*
  1138.  * Change the type field of certain keyword entries depending on the
  1139.  * kind of interface the route they belong to points to.
  1140.  */
  1141. void fix_routes(void)
  1142. {
  1143.     register key    *kptr;
  1144.     register key    *first;
  1145.     uint    i, num, type;
  1146.  
  1147.     for (i = 0; i < num_routes; ++i) {
  1148.         kptr = &routes[i];
  1149.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1150.             eexit(kptr->line, "route traverse error");
  1151.         first = (key *) kptr->arg;
  1152.  
  1153.         /* determine the interface type */
  1154.         kptr = get_key("interface", first);
  1155.         if (kptr->status != S_SET || kptr->arg == NULL)
  1156.             eexit(routes[i].line, "route interface name not set");
  1157.         num = get_interface((unchar *) kptr->arg);
  1158.         kptr = (key *) interfaces[num].arg;
  1159.         kptr = get_key("type", kptr);
  1160.         type = *((uint *) kptr->arg);
  1161.  
  1162.         kptr = get_key("net", first);
  1163.         if (kptr->status != S_SET)
  1164.             eexit(routes[i].line, "route net not set");
  1165.         if (kptr->arg == NULL) {
  1166.             kptr = get_key("netmask", first);
  1167.             kptr->type = T_INHIBITED;
  1168.         }
  1169.  
  1170.         kptr = get_key("gateway", first);
  1171.         if (type == IT_ETHERNET) {
  1172.             if (kptr->status != S_SET)
  1173.                 eexit(routes[i].line, "route gateway not set");
  1174.             if (kptr->arg == NULL) {
  1175.                 kptr = get_key("metric", first);
  1176.                 kptr->type = T_INHIBITED;
  1177.             }
  1178.         } else
  1179.             kptr->type = T_INHIBITED;
  1180.  
  1181.         if (type != IT_ISDN) {
  1182.             kptr = get_key("link", first);
  1183.             kptr->type = T_INHIBITED;
  1184.         }
  1185.     }
  1186. }
  1187.  
  1188. /*
  1189.  * Change the type field of certain keyword entries depending on the
  1190.  * kind of network address.
  1191.  */
  1192. void fix_sources(void)
  1193. {
  1194.     register key    *kptr;
  1195.     register key    *first;
  1196.     uint    i;
  1197.  
  1198.     for (i = 0; i < num_sources; ++i) {
  1199.         kptr = &sources[i];
  1200.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1201.             eexit(kptr->line, "source traverse error");
  1202.         first = (key *) kptr->arg;
  1203.  
  1204.         kptr = get_key("refer", first);
  1205.         if (kptr->status == S_SET) {
  1206.             kptr = get_key("net", first);
  1207.             kptr->type = T_INHIBITED;
  1208.             kptr = get_key("netmask", first);
  1209.             kptr->type = T_INHIBITED;
  1210.         } else {
  1211.             kptr = get_key("net", first);
  1212.             if (kptr->status != S_SET)
  1213.                 eexit(sources[i].line, "source net not set");
  1214.             if (kptr->arg == NULL) {
  1215.                 kptr = get_key("netmask", first);
  1216.                 kptr->type = T_INHIBITED;
  1217.             }
  1218.             kptr = get_key("refer", first);
  1219.             kptr->type = T_INHIBITED;
  1220.         }
  1221.     }
  1222. }
  1223.  
  1224. /*
  1225.  * Traverse through the various keyword structures and make a generic
  1226.  * check of entry type vs. entry status.
  1227.  */
  1228. void check_status(void)
  1229. {
  1230.     register key    *kptr;
  1231.     register uint    i;
  1232.  
  1233.     for (i = 0; i < num_globals; ++i) {
  1234.         kptr = &globals[i];
  1235.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1236.             eexit(kptr->line, "%s traverse error", kptr->keyword);
  1237.         traverse_status((key *) kptr->arg, kptr->line);
  1238.     }
  1239.     for (i = 0; i < num_interfaces; ++i) {
  1240.         kptr = &interfaces[i];
  1241.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1242.             eexit(kptr->line, "%s traverse error", kptr->keyword);
  1243.         traverse_status((key *) kptr->arg, kptr->line);
  1244.     }
  1245.     for (i = 0; i < num_routes; ++i) {
  1246.         kptr = &routes[i];
  1247.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1248.             eexit(kptr->line, "%s traverse error", kptr->keyword);
  1249.         traverse_status((key *) kptr->arg, kptr->line);
  1250.     }
  1251.     for (i = 0; i < num_sources; ++i) {
  1252.         kptr = &sources[i];
  1253.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1254.             eexit(kptr->line, "%s traverse error", kptr->keyword);
  1255.         traverse_status((key *) kptr->arg, kptr->line);
  1256.     }
  1257.     for (i = 0; i < num_links; ++i) {
  1258.         kptr = &links[i];
  1259.         if (kptr->status != S_TRAVERSE || kptr->arg == NULL)
  1260.             eexit(kptr->line, "%s traverse error", kptr->keyword);
  1261.         traverse_status((key *) kptr->arg, kptr->line);
  1262.     }
  1263. }
  1264.  
  1265. /*
  1266.  * Do the actual recursive check of entry type vs. entry status.
  1267.  */
  1268. void traverse_status(register key *kptr, uint ln)
  1269. {
  1270.     for (; kptr->type != T_TERMINAL; ++kptr) {
  1271.         switch (kptr->status) {
  1272.             case S_NOTSET:
  1273.                 if (kptr->type == T_REQUIRED)
  1274.                     eexit(ln, "missing keyword `%s'",
  1275.                         kptr->keyword);
  1276.                 break;
  1277.  
  1278.             case S_SET:
  1279.                 if (kptr->type == T_INHIBITED)
  1280.                     eexit(kptr->line,
  1281.                         "illegal keyword `%s'",
  1282.                         kptr->keyword);
  1283.                 break;
  1284.  
  1285.             case S_TRAVERSE:
  1286.                 if (kptr->type == T_INHIBITED)
  1287.                     eexit(kptr->line,
  1288.                         "illegal keyword `%s'",
  1289.                         kptr->keyword);
  1290.                 if (kptr->arg == NULL)
  1291.                     eexit(kptr->line, "traverse error");
  1292.                 traverse_status((key *) kptr->arg, kptr->line);
  1293.                 break;
  1294.  
  1295.             default:
  1296.                 eexit(ln, "impossible error");
  1297.                 break;
  1298.         }
  1299.     }
  1300. }
  1301.  
  1302. /*
  1303.  * Fill in still missing keyword arguments that can be determined
  1304.  * automatically.
  1305.  */
  1306. void complete_entries(void)
  1307. {
  1308.     register key    *kptr;
  1309.     register key    *first;
  1310.     key    *kptr2, *first2;
  1311.     void    *mptr;
  1312.     unchar    *cptr1, *cptr2;
  1313.     unchar    **cpptr;
  1314.     ip    *transit_net, *transit_mask, *host_mask;
  1315.     ip_t    transit_net_size;
  1316.     ip    tmp;
  1317.     uint    i, num1, num2, type, cline;
  1318.  
  1319.     (void) ip_handler(default_ip_ascii, (void **) &default_ip);
  1320.     (void) ip_handler(transit_net_ascii, (void **) &transit_net);
  1321.     (void) ip_handler(transit_mask_ascii, (void **) &transit_mask);
  1322.     (void) ip_handler(host_mask_ascii, (void **) &host_mask);
  1323.  
  1324.     if (num_globals) {
  1325.         first = (key *) globals[0].arg;
  1326.         kptr = get_key("transitnet", first);
  1327.         if (kptr->status == S_SET && kptr->arg != NULL)
  1328.             transit_net = (ip *) kptr->arg;
  1329.         kptr = get_key("transitmask", first);
  1330.         if (kptr->status == S_SET && kptr->arg != NULL)
  1331.             transit_mask = (ip *) kptr->arg;
  1332.     }
  1333.  
  1334.     /* derive transit net size from transit net mask */
  1335.     transit_net_size = ~*transit_mask + 1;
  1336.  
  1337.     for (i = 0; i < num_interfaces; ++i) {
  1338.         first = (key *) interfaces[i].arg;
  1339.         kptr = get_key("name", first);
  1340.         num1 = get_dupe((unchar *) kptr->arg, i);
  1341.         if (num1 != i) {
  1342.             kptr = (num1 < num_interfaces)
  1343.                 ? (key *) interfaces[num1].arg
  1344.                 : (key *) routes[num1 - num_interfaces].arg;
  1345.             kptr = get_key("name", kptr);
  1346.             eexit(kptr->line, "duplicate interface/route name");
  1347.         }
  1348.         kptr = get_key("type", first);
  1349.         type = *((uint *) kptr->arg);
  1350.  
  1351.         if (type == IT_ETHERNET) {
  1352.             kptr = get_key("address", first);
  1353.             tmp = *((ip *) kptr->arg);
  1354.             kptr = get_key("netmask", first);
  1355.             tmp &= *((ip *) kptr->arg);
  1356.             kptr = get_key("net", first);
  1357.             mptr = xmalloc(sizeof(ip));
  1358.             *((ip *) mptr) = tmp;
  1359.             kptr->arg = mptr;
  1360.             kptr->status = S_SET;
  1361.  
  1362.             kptr = get_key("name", first);
  1363.             kptr2 = get_key("routename", first);
  1364.             kptr2->arg = kptr->arg;
  1365.             kptr->status = S_SET;
  1366.         } else {
  1367.             kptr = get_key("net", first);
  1368.             mptr = xmalloc(sizeof(ip));
  1369.             *((ip *) mptr) = *transit_net;
  1370.             kptr->arg = mptr;
  1371.             kptr->status = S_SET;
  1372.  
  1373.             kptr = get_key("netmask", first);
  1374.             mptr = xmalloc(sizeof(ip));
  1375.             *((ip *) mptr) = *transit_mask;
  1376.             kptr->arg = mptr;
  1377.             kptr->status = S_SET;
  1378.  
  1379.             /*
  1380.              * set the first transit net address for
  1381.              * each point-to-point interface.
  1382.              */
  1383.             kptr = get_key("gateway", first);
  1384.             if (kptr->status == S_SET) {
  1385.                 /* only for type point2point */
  1386.                 transit_nets[i] = *((ip *) kptr->arg);
  1387.                 transit_offsets[i] = 0;
  1388.  
  1389.                 /* construct a direct route for the gateway */
  1390.                 cline = kptr->line;
  1391.                 if (num_routes >= MAX_ROUTES)
  1392.                     eexit(cline, "too many route entries");
  1393.                 /* insert route in front of any other route */
  1394.                 if (num_routes)
  1395.                     (void) memmove((void *) &routes[1],
  1396.                             (void *) &routes[0],
  1397.                             sizeof(key)
  1398.                                 * num_routes);
  1399.                 ++num_routes;
  1400.                 ++num_internal_routes;
  1401.                 kptr = &routes[0];
  1402.                 (void) memcpy((void *) kptr,
  1403.                         (void *) &config[2],
  1404.                         sizeof(key));
  1405.  
  1406.                 mptr = xmalloc(sizeof route);
  1407.                 (void) memcpy(mptr, (void *) route,
  1408.                         sizeof route);
  1409.                 kptr->arg = mptr;
  1410.                 kptr->line = cline;
  1411.                 kptr->status = S_TRAVERSE;
  1412.  
  1413.                 first2 = (key *) mptr;
  1414.                 kptr = get_key("name", first2);
  1415.                 kptr2 = get_key("name", first);
  1416.                 kptr->arg = kptr2->arg;
  1417.                 kptr->line = cline;
  1418.                 kptr->status = S_SET;
  1419.  
  1420.                 kptr = get_key("net", first2);
  1421.                 mptr = xmalloc(sizeof(ip));
  1422.                 *((ip *) mptr) = transit_nets[i];
  1423.                 kptr->arg = mptr;
  1424.                 kptr->line = cline;
  1425.                 kptr->status = S_SET;
  1426.  
  1427.                 kptr = get_key("netmask", first2);
  1428.                 mptr = xmalloc(sizeof(ip));
  1429.                 *((ip *) mptr) = *host_mask;
  1430.                 kptr->arg = mptr;
  1431.                 kptr->line = cline;
  1432.                 kptr->status = S_SET;
  1433.  
  1434.                 kptr = get_key("interface", first2);
  1435.                 kptr2 = get_key("name", first);
  1436.                 kptr->arg = kptr2->arg;
  1437.                 kptr->line = cline;
  1438.                 kptr->status = S_SET;
  1439.  
  1440.                 kptr = get_key("gateway", first2);
  1441.                 mptr = xmalloc(sizeof(ip));
  1442.                 *((ip *) mptr) = *transit_net;
  1443.                 kptr->arg = mptr;
  1444.                 kptr->line = cline;
  1445.                 kptr->status = S_SET;
  1446.  
  1447.                 kptr = get_key("metric", first2);
  1448.                 mptr = xmalloc(sizeof(uint));
  1449.                 *((uint *) mptr) = 0;
  1450.                 kptr->arg = mptr;
  1451.                 kptr->line = cline;
  1452.                 kptr->status = S_SET;
  1453.  
  1454.                 kptr = get_key("attributes", first2);
  1455.                 mptr = xmalloc(sizeof rattributes);
  1456.                 (void) memcpy(mptr, (void *) rattributes,
  1457.                         sizeof rattributes);
  1458.                 kptr->arg = mptr;
  1459.                 kptr->line = cline;
  1460.                 kptr->status = S_TRAVERSE;
  1461.  
  1462.                 first2 = (key *) mptr;
  1463.                 kptr = get_key("hidden_route", first2);
  1464.                 kptr->line = cline;
  1465.                 kptr->status = S_SET;
  1466.             } else {
  1467.                 transit_nets[i] = *transit_net;
  1468.                 transit_offsets[i] = 1;
  1469.             }
  1470.             *transit_net += transit_net_size;
  1471.         }
  1472.     }
  1473.  
  1474.     for (i = 0; i < num_routes; ++i) {
  1475.         first = (key *) routes[i].arg;
  1476.         kptr = get_key("name", first);
  1477.         num1 = get_dupe((unchar *) kptr->arg, i + num_interfaces);
  1478.         if (num1 != i + num_interfaces) {
  1479.             kptr = (num1 < num_interfaces)
  1480.                 ? (key *) interfaces[num1].arg
  1481.                 : (key *) routes[num1 - num_interfaces].arg;
  1482.             kptr = get_key("name", kptr);
  1483.             eexit(kptr->line, "duplicate interface/route name");
  1484.         }
  1485.         kptr = get_key("interface", first);
  1486.         cptr1 = (unchar *) kptr->arg;
  1487.         num1 = get_interface(cptr1);
  1488.         kptr = get_key("type", (key *) interfaces[num1].arg);
  1489.         type = *((uint *) kptr->arg);
  1490.  
  1491.         kptr = get_key("net", first);
  1492.         if (kptr->arg == NULL) {
  1493.             kptr->arg = (void *) default_ip;
  1494.             kptr->status = S_SET;
  1495.             kptr = get_key("netmask", first);
  1496.             kptr->arg = (void *) default_ip;
  1497.             kptr->status = S_SET;
  1498.         } else {
  1499.             tmp = *((ip *) kptr->arg);
  1500.             kptr2 = get_key("netmask", first);
  1501.             tmp &= *((ip *) kptr2->arg);
  1502.             if (tmp != *((ip *) kptr->arg))
  1503.                 eexit(kptr2->line,
  1504.                     "netmask doesn't match route net");
  1505.         }
  1506.  
  1507.         switch (type) {
  1508.             case IT_ETHERNET:
  1509.                 kptr = get_key("gateway", first);
  1510.                 if (kptr->arg == NULL) {
  1511.                     kptr2 = get_key("net",
  1512.                             (key *) interfaces[num1].arg);
  1513.                     kptr->arg = kptr2->arg;
  1514.                     kptr->status = S_SET;
  1515.                     kptr = get_key("metric", first);
  1516.                     mptr = xmalloc(sizeof(uint));
  1517.                     *((uint *) mptr) = 0;
  1518.                     kptr->arg = mptr;
  1519.                     kptr->status = S_SET;
  1520.                 }
  1521.                 break;
  1522.  
  1523.             case IT_POINT2POINT:
  1524.                 kptr = get_key("gateway", first);
  1525.                 if (kptr->status != S_SET) {
  1526.                     mptr = xmalloc(sizeof(ip));
  1527.                     *((ip *) mptr) = transit_nets[num1]
  1528.                             + transit_offsets[num1];
  1529.                     kptr->arg = mptr;
  1530.                     kptr->status = S_SET;
  1531.                 }
  1532.                 break;
  1533.  
  1534.             case IT_ISDN:
  1535.                 kptr = get_key("link", first);
  1536.                 if (kptr->status != S_SET) {
  1537.                     transit_use_default[num1] = TRUE;
  1538.                     kptr = get_key("gateway", first);
  1539.                     mptr = xmalloc(sizeof(ip));
  1540.                     *((ip *) mptr) = transit_nets[num1] + 1;
  1541.                     kptr->arg = mptr;
  1542.                     kptr->status = S_SET;
  1543.                     break;
  1544.                 }
  1545.  
  1546.                 cptr2 = (unchar *) kptr->arg;
  1547.                 (void) get_first_link(cptr2);
  1548.                 num2 = get_gateway(cptr1, cptr2, i);
  1549.                 /*
  1550.                  * Determine the transit net address for
  1551.                  * this route. Calculate a new address if
  1552.                  * we can't use an already existing one.
  1553.                  */
  1554.                 if (num2 == i) {
  1555.                     /* not found */
  1556.                     if (++transit_offsets[num1]
  1557.                             >= (transit_net_size - 1))
  1558.                         eexit(kptr->line,
  1559.                             "too many links for interface `%s'",
  1560.                             cptr1);
  1561.                     kptr = get_key("gateway", first);
  1562.                     mptr = xmalloc(sizeof(ip));
  1563.                     *((ip *) mptr) = transit_nets[num1]
  1564.                             + transit_offsets[num1];
  1565.                     kptr->arg = mptr;
  1566.                     kptr->status = S_SET;
  1567.                 } else {
  1568.                     /* found */
  1569.                     kptr = get_key("gateway", first);
  1570.                     kptr2 = get_key("gateway",
  1571.                             (key *) routes[num2].arg);
  1572.                     kptr->arg = kptr2->arg;
  1573.                     kptr->status = S_SET;
  1574.                 }
  1575.                 break;
  1576.  
  1577.             default:
  1578.                 eexit(routes[i].line, "impossible error");
  1579.                 break;
  1580.         }
  1581.     }
  1582.  
  1583.     for (i = 0; i < num_sources; ++i) {
  1584.         first = (key *) sources[i].arg;
  1585.  
  1586.         kptr = get_key("net", first);
  1587.         if (kptr->status == S_SET) {
  1588.             if (kptr->arg == NULL) {
  1589.                 kptr->arg = (void *) default_ip;
  1590.                 kptr->status = S_SET;
  1591.                 kptr = get_key("netmask", first);
  1592.                 kptr->arg = (void *) default_ip;
  1593.                 kptr->status = S_SET;
  1594.             } else {
  1595.                 tmp = *((ip *) kptr->arg);
  1596.                 kptr2 = get_key("netmask", first);
  1597.                 tmp &= *((ip *) kptr2->arg);
  1598.                 if (tmp != *((ip *) kptr->arg))
  1599.                     eexit(kptr2->line,
  1600.                         "netmask doesn't match source net");
  1601.             }
  1602.         }
  1603.  
  1604.         /*
  1605.          * Check whether the refered and attached interfaces/routes
  1606.          * really exist.
  1607.          */
  1608.         kptr = get_key("refer", first);
  1609.         if (kptr->status == S_SET && kptr->arg != NULL)
  1610.             for (cpptr = (unchar **) kptr->arg; *cpptr; ++cpptr)
  1611.                 (void) get_id(*cpptr);
  1612.  
  1613.         kptr = get_key("attach", first);
  1614.         for (cpptr = (unchar **) kptr->arg; *cpptr; ++cpptr) {
  1615.             cptr1 = *cpptr;
  1616.             if (cptr1[0] == '+') {
  1617.                 if (cptr1[1] != '\0')
  1618.                     (void) get_interface(cptr1 + 1);
  1619.             } else if (cptr1[0] != '*' || cptr1[1] != '\0')
  1620.                 (void) get_id(cptr1);
  1621.         }
  1622.     }
  1623. }
  1624.  
  1625. /*
  1626.  * Convert attribute keywords to bit flags.
  1627.  */
  1628. uint make_flags(register key *kptr)
  1629. {
  1630.     uint    flags = 0;
  1631.     register uint    mask;
  1632.  
  1633.     for (mask = 1; kptr->type != T_TERMINAL; ++kptr, mask <<= 1)
  1634.         if (kptr->status == S_SET)
  1635.             flags |= mask;
  1636.     return flags;
  1637. }
  1638.  
  1639. /*
  1640.  * Write the PCroute config file.
  1641.  */
  1642. void write_pcroute_config(void)
  1643. {
  1644.     FILE    *pcroute_file;
  1645.     register key    *kptr;
  1646.     register key    *first;
  1647.     key    *kptr1, *first1;
  1648.     unchar    *cptr;
  1649.     unchar    **cpptr, **cpptr1;
  1650.     uint    i, type, flags, id, src_cnt, cnt;
  1651.     int    refer;
  1652.     ushort    count;
  1653.     pcr_header    head;
  1654.     pcr_interface    ifc;
  1655.     pcr_route    rt;
  1656.     pcr_bootp    bp;
  1657.     pcr_syslog    sl;
  1658.  
  1659.     (void) sprintf(pcr_cfg_name, "%s%u%s", pcr_cfg_base, num_interfaces,
  1660.                         pcr_cfg_tail);
  1661.     (void) unlink(pcr_cfg_name);
  1662.     if ((pcroute_file = fopen(pcr_cfg_name, "wb")) == NULL) {
  1663.         fprintf(stderr, "%s: can't open file `%s'\n", prg_name,
  1664.                 pcr_cfg_name);
  1665.         exit(2);
  1666.     }
  1667.  
  1668.     /* interfaces */
  1669.     head.type = IF_TYPE;
  1670.     head.version = IF_VERSION;
  1671.     head.len = sizeof ifc;
  1672.  
  1673.     for (i = 0; i < num_interfaces; ++i) {
  1674.         if (fwrite((void *) &head, sizeof head, 1, pcroute_file) != 1) {
  1675.             fprintf(stderr, "%s: error writing file `%s'\n",
  1676.                     prg_name, pcr_cfg_name);
  1677.             exit(2);
  1678.         }
  1679.  
  1680.         first = (key *) interfaces[i].arg;
  1681.         kptr = get_key("type", first);
  1682.         type = *((uint *) kptr->arg);
  1683.  
  1684.         kptr = get_key("address", first);
  1685.         ifc.address = to_netip(*((ip *) kptr->arg));
  1686.         kptr = get_key("net", first);
  1687.         ifc.net = to_netip(*((ip *) kptr->arg));
  1688.         kptr = get_key("netmask", first);
  1689.         ifc.netmask = to_netip(*((ip *) kptr->arg));
  1690.         kptr = get_key("metric", first);
  1691.         ifc.metric = (ushort) *((uint *) kptr->arg);
  1692.         flags = 0;
  1693.         kptr = get_key("attributes", first);
  1694.         if (kptr->status == S_TRAVERSE && kptr->arg != NULL)
  1695.             flags = make_flags((key *) kptr->arg);
  1696.         if (type != IT_ETHERNET)
  1697.             flags |= 0x2e0;
  1698.         ifc.flags = (ushort) flags;
  1699.         ifc.id = i + num_interfaces + 2;
  1700.  
  1701.         if (fwrite((void *) &ifc, sizeof ifc, 1, pcroute_file) != 1) {
  1702.             fprintf(stderr, "%s: error writing file `%s'\n",
  1703.                     prg_name, pcr_cfg_name);
  1704.             exit(2);
  1705.         }
  1706.     }
  1707.  
  1708.     /* routes and sources */
  1709.     /* calculate the real number of source routes */
  1710.     src_cnt = 0;
  1711.     for (i = 0; i < num_sources; ++i) {
  1712.         first = (key *) sources[i].arg;
  1713.         kptr = get_key("refer", first);
  1714.         if (kptr->status == S_SET && kptr->arg != NULL) {
  1715.             cnt = 0;
  1716.             for (cpptr = (unchar **) kptr->arg; *cpptr; ++cpptr)
  1717.                 ++cnt;
  1718.         } else
  1719.             cnt = 1;
  1720.         kptr = get_key("attach", first);
  1721.         for (cpptr = (unchar **) kptr->arg; *cpptr; ++cpptr)
  1722.             src_cnt += cnt;
  1723.     }
  1724.  
  1725.     head.type = RT_TYPE;
  1726.     head.version = RT_VERSION;
  1727.     head.len = sizeof rt * (num_routes + src_cnt) + sizeof count;
  1728.     if (fwrite((void *) &head, sizeof head, 1, pcroute_file) != 1) {
  1729.         fprintf(stderr, "%s: error writing file `%s'\n", prg_name,
  1730.                 pcr_cfg_name);
  1731.         exit(2);
  1732.     }
  1733.  
  1734.     count = num_routes + src_cnt;
  1735.     if (fwrite((void *) &count, sizeof count, 1, pcroute_file) != 1) {
  1736.         fprintf(stderr, "%s: error writing file `%s'\n", prg_name,
  1737.                 pcr_cfg_name);
  1738.         exit(2);
  1739.     }
  1740.  
  1741.     for (i = 0; i < num_routes; ++i) {
  1742.         first = (key *) routes[i].arg;
  1743.  
  1744.         kptr = get_key("net", first);
  1745.         rt.net = to_netip(*((ip *) kptr->arg));
  1746.         kptr = get_key("netmask", first);
  1747.         rt.netmask = to_netip(*((ip *) kptr->arg));
  1748.         kptr = get_key("gateway", first);
  1749.         rt.gateway = to_netip(*((ip *) kptr->arg));
  1750.         kptr = get_key("metric", first);
  1751.         rt.metric = (unchar) *((uint *) kptr->arg);
  1752.         flags = 0;
  1753.         kptr = get_key("attributes", first);
  1754.         if (kptr->status == S_TRAVERSE && kptr->arg != NULL)
  1755.             flags = make_flags((key *) kptr->arg);
  1756.         rt.flags = (unchar) flags;
  1757.         rt.id = i + num_interfaces * 2 + 2;
  1758.  
  1759.         if (fwrite((void *) &rt, sizeof rt, 1, pcroute_file) != 1) {
  1760.             fprintf(stderr, "%s: error writing file `%s'\n",
  1761.                     prg_name, pcr_cfg_name);
  1762.             exit(2);
  1763.         }
  1764.     }
  1765.  
  1766.     for (i = 0; i < num_sources; ++i) {
  1767.         first = (key *) sources[i].arg;
  1768.  
  1769.         rt.gateway = to_netip(*((ip *) default_ip));
  1770.         rt.metric = 0;
  1771.         kptr = get_key("route", first);
  1772.         if (*((uint *) kptr->arg) == DR_DENY)
  1773.             rt.flags = 0x50;
  1774.         else
  1775.             rt.flags = 0x40;
  1776.         kptr = get_key("refer", first);
  1777.         if (kptr->status == S_SET && kptr->arg != NULL) {
  1778.             refer = TRUE;
  1779.             cpptr1 = (unchar **) kptr->arg;
  1780.         } else
  1781.             refer = FALSE;
  1782.  
  1783.         do {
  1784.             if (refer) {
  1785.                 id = get_id(*cpptr1);
  1786.                 if (id < num_interfaces)
  1787.                     first1 = (key *) interfaces[id].arg;
  1788.                 else
  1789.                     first1 = (key *) routes[id
  1790.                             - num_interfaces].arg;
  1791.                 kptr1 = get_key("net", first1);
  1792.                 rt.net = to_netip(*((ip *) kptr1->arg));
  1793.                 kptr1 = get_key("netmask", first1);
  1794.                 rt.netmask = to_netip(*((ip *) kptr1->arg));
  1795.             } else {
  1796.                 kptr = get_key("net", first);
  1797.                 rt.net = to_netip(*((ip *) kptr->arg));
  1798.                 kptr = get_key("netmask", first);
  1799.                 rt.netmask = to_netip(*((ip *) kptr->arg));
  1800.             }
  1801.  
  1802.             kptr = get_key("attach", first);
  1803.             for (cpptr = (unchar **) kptr->arg; *cpptr; ++cpptr) {
  1804.                 cptr = *cpptr;
  1805.                 if (cptr[0] == '*' && cptr[1] == '\0')
  1806.                     rt.id = 0;
  1807.                 else if (cptr[0] == '+') {
  1808.                     if (cptr[1] == '\0')
  1809.                         rt.id = 1;
  1810.                     else
  1811.                         rt.id = get_interface(cptr + 1)
  1812.                                 + 2;
  1813.                 } else
  1814.                     rt.id = get_id(cptr) + num_interfaces
  1815.                             + 2;
  1816.  
  1817.                 if (fwrite((void *) &rt, sizeof rt, 1,
  1818.                             pcroute_file) != 1) {
  1819.                     fprintf(stderr,
  1820.                         "%s: error writing file `%s'\n",
  1821.                         prg_name, pcr_cfg_name);
  1822.                     exit(2);
  1823.                 }
  1824.             }
  1825.         } while (refer && *++cpptr1);
  1826.     }
  1827.  
  1828.     /* bootp */
  1829.     head.type = BP_TYPE;
  1830.     head.version = BP_VERSION;
  1831.     head.len = sizeof bp;
  1832.     if (fwrite((void *) &head, sizeof head, 1, pcroute_file) != 1) {
  1833.         fprintf(stderr, "%s: error writing file `%s'\n", prg_name,
  1834.                 pcr_cfg_name);
  1835.         exit(2);
  1836.     }
  1837.  
  1838.     bp.forward_address = to_netip(*default_ip);
  1839.  
  1840.     if (num_globals) {
  1841.         first = (key *) globals[0].arg;
  1842.         kptr = get_key("bootp", first);
  1843.         if (kptr->status == S_SET && kptr->arg != NULL)
  1844.             bp.forward_address = to_netip(*((ip *) kptr->arg));
  1845.     }
  1846.     if (fwrite((void *) &bp, sizeof bp, 1, pcroute_file) != 1) {
  1847.         fprintf(stderr, "%s: error writing file `%s'\n",
  1848.                 prg_name, pcr_cfg_name);
  1849.         exit(2);
  1850.     }
  1851.  
  1852.     /* syslog */
  1853.     head.type = SL_TYPE;
  1854.     head.version = SL_VERSION;
  1855.     head.len = sizeof sl;
  1856.     if (fwrite((void *) &head, sizeof head, 1, pcroute_file) != 1) {
  1857.         fprintf(stderr, "%s: error writing file `%s'\n", prg_name,
  1858.                 pcr_cfg_name);
  1859.         exit(2);
  1860.     }
  1861.  
  1862.     sl.log_host = to_netip(*default_ip);
  1863.     sl.log_priority = 0;
  1864.     sl.log_mask = 0xf;
  1865.  
  1866.     if (num_globals) {
  1867.         kptr = get_key("syslog", (key *) globals[0].arg);
  1868.         if (kptr->status == S_TRAVERSE && kptr->arg != NULL) {
  1869.             first = (key *) kptr->arg;
  1870.             kptr = get_key("host", first);
  1871.             sl.log_host = to_netip(*((ip *) kptr->arg));
  1872.             kptr = get_key("priority", first);
  1873.             sl.log_priority = (ushort) *((uint *) kptr->arg);
  1874.             flags = 0;
  1875.             kptr = get_key("logsource", first);
  1876.             if (kptr->status == S_TRAVERSE && kptr->arg != NULL)
  1877.                 flags = make_flags((key *) kptr->arg);
  1878.             sl.log_mask = (ushort) (flags ^ 0xf);
  1879.         }
  1880.     }
  1881.     if (fwrite((void *) &sl, sizeof sl, 1, pcroute_file) != 1) {
  1882.         fprintf(stderr, "%s: error writing file `%s'\n",
  1883.                 prg_name, pcr_cfg_name);
  1884.         exit(2);
  1885.     }
  1886.  
  1887.     if (fclose(pcroute_file)) {
  1888.         fprintf(stderr, "%s: can't close file `%s'\n", prg_name,
  1889.                 pcr_cfg_name);
  1890.         exit(2);
  1891.     }
  1892. }
  1893.  
  1894. /*
  1895.  * Write the ISPA config file(s).
  1896.  */
  1897. void write_ispa_config(void)
  1898. {
  1899.     FILE    *ispa_file;
  1900.     register key    *kptr;
  1901.     register key    *first;
  1902.     key    *kptr2, *first2;
  1903.     ip    *gptr;
  1904.     unchar    *cptr;
  1905.     ip    transit, transit_net;
  1906.     uint    i, num, num2, inum, type, cnt;
  1907.  
  1908.     transit = 0;
  1909.     inum = 1;
  1910.     for (i = 0; i < num_interfaces; ++i) {
  1911.         first = (key *) interfaces[i].arg;
  1912.         kptr = get_key("type", first);
  1913.         type = *((uint *) kptr->arg);
  1914.         if (type != IT_ISDN)
  1915.             continue;
  1916.  
  1917.         (void) sprintf(ispa_cfg_name, "%s%u%s", ispa_cfg_base, inum,
  1918.                             ispa_cfg_tail);
  1919.         (void) unlink(ispa_cfg_name);
  1920.         if ((ispa_file = fopen(ispa_cfg_name, "wt")) == NULL) {
  1921.             fprintf(stderr, "%s: can't open file `%s'\n", prg_name,
  1922.                     ispa_cfg_name);
  1923.             exit(2);
  1924.         }
  1925.  
  1926.         cnt = 0;
  1927.         kptr = get_key("name", first);
  1928.         cptr = (unchar *) kptr->arg;
  1929.         if ((num = get_first_route(cptr)) != num_routes) {
  1930.             do {
  1931.                 first = (key *) routes[num].arg;
  1932.                 kptr = get_key("gateway", first);
  1933.                 gptr = (ip *) kptr->arg;
  1934.                 if (*gptr <= transit)
  1935.                     continue;
  1936.                 transit = *gptr;
  1937.                 kptr = get_key("link", first);
  1938.                 if (kptr->status != S_SET)
  1939.                     continue;
  1940.                 num2 = get_first_link((unchar *) kptr->arg);
  1941.                 do {
  1942.                     fprint_ip(ispa_file, gptr);
  1943.                     first2 = (key *) links[num2].arg;
  1944.                     kptr2 = get_key("address", first2);
  1945.                     fprintf(ispa_file, " %s",
  1946.                         ((unchar **) kptr2->arg)[0]);
  1947.                     if (((unchar **) kptr2->arg)[1] != NULL)
  1948.                         fprintf(ispa_file, " %s",
  1949.                            ((unchar **) kptr2->arg)[1]);
  1950.                     kptr2 = get_key("options", first2);
  1951.                     if (kptr2->status == S_SET
  1952.                             && kptr2->arg != NULL)
  1953.                         fprintf(ispa_file, " %s",
  1954.                             (unchar *) kptr2->arg);
  1955.                     fprintf(ispa_file, "\n");
  1956.                     ++cnt;
  1957.                 } while ((num2 = get_next_link(
  1958.                             (unchar *) kptr->arg,
  1959.                             num2 + 1)) < num_links);
  1960.             } while ((num = get_next_route(cptr, num + 1))
  1961.                     < num_routes);
  1962.         }
  1963.  
  1964.         if (cnt == 0) {
  1965.             /* dummy entry */
  1966.             transit_net = transit_nets[i] + 2;
  1967.             fprint_ip(ispa_file, &transit_net);
  1968.             fprintf(ispa_file, " 0000\n");
  1969.         }
  1970.  
  1971.         if (fclose(ispa_file)) {
  1972.             fprintf(stderr, "%s: can't close file `%s'\n", prg_name,
  1973.                     ispa_cfg_name);
  1974.             exit(2);
  1975.         }
  1976.         ++inum;
  1977.     }
  1978. }
  1979.  
  1980. /*
  1981.  * Write the MS-DOS startup batch file.
  1982.  */
  1983. void write_start_file(void)
  1984. {
  1985.     FILE    *start_file;
  1986.     register key    *kptr;
  1987.     register key    *first;
  1988.     key    *first2;
  1989.     ip    *shptr;
  1990.     uint    i, type, inum;
  1991.  
  1992.     (void) unlink(start_file_name);
  1993.     if ((start_file = fopen(start_file_name, "wt")) == NULL) {
  1994.         fprintf(stderr, "%s: can't open file `%s'\n", prg_name,
  1995.                 start_file_name);
  1996.         exit(2);
  1997.     }
  1998.  
  1999.     shptr = NULL;
  2000.     if (num_globals) {
  2001.         first = (key *) globals[0].arg;
  2002.         kptr = get_key("syslog", first);
  2003.         if (kptr->status == S_TRAVERSE && kptr->arg != NULL) {
  2004.             kptr = get_key("host", (key *) kptr->arg);
  2005.             shptr = (ip *) kptr->arg;
  2006.         }
  2007.         kptr = get_key("prefix", first);
  2008.         if (kptr->status == S_SET && kptr->arg != NULL) {
  2009.             fprintf(start_file, (unchar *) kptr->arg,
  2010.                     num_interfaces);
  2011.             fprintf(start_file, "\n");
  2012.         }
  2013.     }
  2014.  
  2015.     /* each interface has its own packet driver invocation */
  2016.     inum = 1;
  2017.     for (i = 0; i < num_interfaces; ++i) {
  2018.         first = (key *) interfaces[i].arg;
  2019.         kptr = get_key("type", first);
  2020.         type = *((uint *) kptr->arg);
  2021.         kptr = get_key("driver", first);
  2022.         first2 = (key *) kptr->arg;
  2023.  
  2024.         kptr = get_key("prefix", first2);
  2025.         if (kptr->status == S_SET && kptr->arg != NULL) {
  2026.             fprintf(start_file, (unchar *) kptr->arg, BASE_INT + i);
  2027.             fprintf(start_file, "\n");
  2028.         }
  2029.  
  2030.         switch (type) {
  2031.             case IT_ETHERNET:
  2032.             case IT_POINT2POINT:
  2033.                 kptr = get_key("command", first2);
  2034.                 fprintf(start_file, (unchar *) kptr->arg,
  2035.                         BASE_INT + i);
  2036.                 fprintf(start_file, "\n");
  2037.                 break;
  2038.  
  2039.             case IT_ISDN:
  2040.                 fprintf(start_file, "%s", ISPA_NAME);
  2041.                 kptr = get_key("options", first2);
  2042.                 if (kptr->status == S_SET && kptr->arg != NULL)
  2043.                     fprintf(start_file, " %s",
  2044.                             (unchar *) kptr->arg);
  2045.                 kptr = get_key("controller", first2);
  2046.                 fprintf(start_file, " -c %u",
  2047.                             *((uint *) kptr->arg));
  2048.                 kptr = get_key("index", first2);
  2049.                 fprintf(start_file, " -e %u",
  2050.                             *((uint *) kptr->arg));
  2051.                 if (!transit_use_default[i])
  2052.                     fprintf(start_file, " -v");
  2053.                 kptr = get_key("syslog", first2);
  2054.                 if (*((uint *) kptr->arg) == DS_ON
  2055.                         && shptr != NULL) {
  2056.                     kptr = get_key("address", first);
  2057.                     fprintf(start_file, " -r ");
  2058.                     fprint_ip(start_file, shptr);
  2059.                     fprintf(start_file, ",");
  2060.                     fprint_ip(start_file, (ip *) kptr->arg);
  2061.                 }
  2062.                 fprintf(start_file, " 0x%x", BASE_INT + i);
  2063.                 (void) sprintf(ispa_cfg_name, "%s%u%s",
  2064.                         ispa_cfg_base, inum,
  2065.                         ispa_cfg_tail);
  2066.                 fprintf(start_file, " %s", ispa_cfg_name);
  2067.                 fprintf(start_file, "\n");
  2068.                 ++inum;
  2069.                 break;
  2070.  
  2071.             default:
  2072.                 eexit(interfaces[i].line, "impossible error");
  2073.                 break;
  2074.         }
  2075.  
  2076.         kptr = get_key("suffix", first2);
  2077.         if (kptr->status == S_SET && kptr->arg != NULL) {
  2078.             fprintf(start_file, (unchar *) kptr->arg, BASE_INT + i);
  2079.             fprintf(start_file, "\n");
  2080.         }
  2081.     }
  2082.  
  2083.     if (num_globals) {
  2084.         kptr = get_key("suffix", (key *) globals[0].arg);
  2085.         if (kptr->status == S_SET && kptr->arg != NULL) {
  2086.             fprintf(start_file, (unchar *) kptr->arg,
  2087.                     num_interfaces);
  2088.             fprintf(start_file, "\n");
  2089.         }
  2090.     }
  2091.  
  2092.     /*
  2093.      * Invoke the PCroute version with the necessary number
  2094.      * of interfaces.
  2095.      */
  2096.     fprintf(start_file, "p%u\n", num_interfaces);
  2097.  
  2098.     if (fclose(start_file)) {
  2099.         fprintf(stderr, "%s: can't close file `%s'\n", prg_name,
  2100.                 start_file_name);
  2101.         exit(2);
  2102.     }
  2103. }
  2104.  
  2105. /*
  2106.  * Handle special characters in the given line.
  2107.  */
  2108. void expand_line(register unchar *ptr, uint bufsize)
  2109. {
  2110.     var    *vptr;
  2111.     unchar    *maxptr, *start, *nptr, *rptr;
  2112.     register uint    c;
  2113.     uint    rlen, tlen, tmp;
  2114.     states    state;
  2115.  
  2116.     maxptr = &ptr[bufsize];
  2117.     state = NORMAL;
  2118.     c = 0;
  2119.     --ptr;
  2120.  
  2121.     for (;;) {
  2122.         if (c == 0 && (c = *++ptr) == 0)
  2123.             break;
  2124.  
  2125.         switch (state) {
  2126.             case NORMAL:
  2127.                 switch (c) {
  2128.                     case '\\':
  2129.                         start = ptr;
  2130.                         state = ESCAPE;
  2131.                         break;
  2132.                     case '$':
  2133.                         start = ptr;
  2134.                         state = VARC1;
  2135.                         break;
  2136.                     case '#':
  2137.                         *ptr = '\0';
  2138.                         --ptr;
  2139.                         break;
  2140.                 }
  2141.                 c = 0;
  2142.                 break;
  2143.  
  2144.             case ESCAPE:
  2145.                 switch (*ptr) {
  2146.                     case 'a': *ptr = '\a'; break;
  2147.                     case 'b': *ptr = '\b'; break;
  2148.                     case 'f': *ptr = '\f'; break;
  2149.                     case 'n': *ptr = '\n'; break;
  2150.                     case 'r': *ptr = '\r'; break;
  2151.                     case 't': *ptr = '\t'; break;
  2152.                     case 'v': *ptr = '\v'; break;
  2153.                     case '0':
  2154.                     case '1':
  2155.                     case '2':
  2156.                     case '3':
  2157.                         if (*(ptr + 1) >= '0'
  2158.                             && *(ptr + 1) <= '7'
  2159.                             && *(ptr + 2) >= '0'
  2160.                             && *(ptr + 2) <= '7') {
  2161.                             (void) sscanf(ptr,
  2162.                                     "%3o",
  2163.                                     &tmp);
  2164.                             ptr += 2;
  2165.                             *ptr = (unchar) tmp;
  2166.                         } else if (*ptr == '0')
  2167.                             *ptr = '\0';
  2168.                         break;
  2169.                     case 'x':
  2170.                         if (isxdigit(*(ptr + 1))
  2171.                             && isxdigit(*(ptr + 2))) {
  2172.                             (void) sscanf(ptr + 1,
  2173.                                     "%2x",
  2174.                                     &tmp);
  2175.                             ptr += 2;
  2176.                             *ptr = (unchar) tmp;
  2177.                         }
  2178.                         break;
  2179.                 }
  2180.                 (void) memmove((void *) start,
  2181.                         (void *) ptr, strlen(ptr) + 1);
  2182.                 ptr = start;
  2183.                 if (*ptr == '\0')
  2184.                     --ptr;
  2185.                 state = NORMAL;
  2186.                 c = 0;
  2187.                 break;
  2188.  
  2189.             case VARC1:
  2190.                 if (c == '(') {
  2191.                     state = VARC2;
  2192.                     c = 0;
  2193.                 } else {
  2194.                     state = NORMAL;
  2195.                 }
  2196.                 break;
  2197.  
  2198.             case VARC2:
  2199.                 nptr = ptr;
  2200.                 /* advance to the closing bracket or EOL */
  2201.                 for (; (c = *ptr) != ')' && c != '\0'; ++ptr)
  2202.                     ;
  2203.                 if (c == '\0')
  2204.                     eexit(line, "unexpected end of file");
  2205.                 *ptr = '\0';
  2206.                 ++ptr;
  2207.                 tlen = strlen(ptr);
  2208.                 /* get the value of the variable */
  2209.                 vptr = get_var(nptr);
  2210.                 if (vptr) {
  2211.                     rptr = vptr->val;
  2212.                     if (rptr)
  2213.                         rlen = strlen(rptr);
  2214.                     else
  2215.                         rlen = 0;
  2216.                 } else {
  2217.                     rptr = NULL;
  2218.                     rlen = 0;
  2219.                 }
  2220.                 /* check buffer size */
  2221.                 if (start + rlen + tlen >= maxptr)
  2222.                     eexit(line, "variable expansion too long");
  2223.                 /* make room for replacement string */
  2224.                 (void) memmove((void *) (start + rlen),
  2225.                         (void *) ptr, tlen + 1);
  2226.                 /* copy replacement string, if any */
  2227.                 if (rlen) {
  2228.                     (void) memcpy((void *) start,
  2229.                             (void *) rptr, rlen);
  2230.                 }
  2231.                 ptr = start + rlen - 1;
  2232.                 state = NORMAL;
  2233.                 c = 0;
  2234.                 break;
  2235.  
  2236.             default:
  2237.                 eexit(line, "impossible error");
  2238.                 break;
  2239.         }
  2240.     }
  2241. }
  2242.  
  2243. /*
  2244.  * Convert the given character string to lower case.
  2245.  */
  2246. void mklower(register unchar *ptr)
  2247. {
  2248.     register uint    c;
  2249.  
  2250.     for (; (c = *ptr); ++ptr)
  2251.         *ptr = tolower(c);
  2252. }
  2253.  
  2254. /*
  2255.  * Allocate memory from the heap and exit if no memory is available.
  2256.  */
  2257. void *xmalloc(uint size)
  2258. {
  2259.     void    *ptr;
  2260.  
  2261.     if ((ptr = (void *) malloc(size)) == NULL)
  2262.         eexit(line, "out of memory");
  2263.     return ptr;
  2264. }
  2265.  
  2266. /*
  2267.  * Print the given error message and exit.
  2268.  */
  2269. void eexit(uint line, unchar *fmt, ...)
  2270. {
  2271.     va_list    args;
  2272.  
  2273.     va_start(args, fmt);
  2274.     fprintf(stderr, "%s: line %u: ", prg_name, line);
  2275.     vfprintf(stderr, fmt, args);
  2276.     fprintf(stderr, "\n");
  2277.     va_end(args);
  2278.     exit(2);
  2279. }
  2280.