home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / install / net.c < prev    next >
C/C++ Source or Header  |  1997-10-24  |  31KB  |  1,220 lines

  1. #include <net/if.h>
  2. #include <net/route.h>
  3. #include <sys/ioctl.h>
  4. #include <sys/time.h>
  5. #include <sys/types.h>
  6.  
  7. #include <ctype.h>
  8. #include <errno.h>
  9. #include <netinet/in.h>
  10. #include <netinet/ip.h>
  11. #include <arpa/inet.h>
  12. #include <resolv.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <unistd.h>
  17.  
  18. #include "bootpc.h"
  19. #include "devices.h"
  20. #include "install.h"
  21. #include "log.h"
  22. #include "newt.h"
  23. #include "net.h"
  24. #include "perror.h"
  25. #include "windows.h"
  26.  
  27. struct intfconfig_s {
  28.     newtComponent ipLabel, nmLabel, gwLabel, nsLabel;
  29.     newtComponent ipEntry, nmEntry, gwEntry, nsEntry;
  30.     char * ip, * nm, * gw, * ns;
  31.     char * bootpState;
  32. };
  33.  
  34. struct netconfig_s {
  35.     newtComponent nsLabels[3], hnLabel, dnLabel;
  36.     newtComponent nsEntrys[3], hnEntry, dnEntry;
  37.     char * ns[3], * gw, * hn, * dn;
  38. };
  39.  
  40. static void ipCallback(newtComponent co, void * data);
  41. static void hnCallback(newtComponent co, void * data);
  42.  
  43. /* It's a bit gross, but setupNetworkInterface() will setup your general
  44.    networking information if bootp is used */
  45. static int setupNetworkInterface(struct netInterface * intf,
  46.                  struct netConfig * netc,
  47.                      struct driversLoaded ** dl, int justConfig);
  48. static int doBringUpNetworking(struct netInterface * intf, 
  49.                    struct netConfig * netc,
  50.                    struct driversLoaded ** dl, int justConfig);
  51. static int configureNetDevice(struct netInterface * intf);
  52. /* intf in configureNetwork is optional */
  53. static int configureNetwork(struct netConfig * netc, 
  54.                 struct netInterface * intf);
  55. static char * findAvailableNetDevice(void);
  56.  
  57. static int doBootp(char * device, struct netInterface * intf,
  58.            struct netConfig * netc) {
  59.     struct netInterface minInterface;
  60.     int rc;
  61.  
  62.     /* This is a bit of a hack, but it lets us use Jon Peatfield's bootp
  63.        code w/o hacking at it. It's written to allow test mode to work
  64.        as long as the runner sets the proper magic env variables. */
  65.  
  66.     if (!testing) {
  67.     logMessage("using bootp for device %s", device);
  68.  
  69.     minInterface.ip = minInterface.netmask = minInterface.network = 0;
  70.     minInterface.broadcast = 0xffffffff; 
  71.     strcpy(minInterface.dev, device);
  72.  
  73.     if (configureNetDevice(&minInterface)) {
  74.         logMessage("failed to setup minimal bootp interface %s", device);
  75.         return 1;
  76.     }
  77.  
  78.     winStatus(40, 3, "BOOTP", "Sending BOOTP request...");
  79.     rc = performBootp(device, "255.255.255.255", "", 10, 0, NULL, 0, 1,
  80.                 BP_PUT_ENV);
  81.     newtPopWindow();
  82.  
  83.     if (rc) {
  84.         logMessage("performBootp() failed w/ return %d", rc);
  85.         return 1;
  86.     }
  87.     }
  88.  
  89.     if (!getenv("BOOTP_IPADDR")) {
  90.     errorWindow("bootp query did not return an IP address");
  91.     return 1;
  92.     }
  93.     
  94.     /* These will be generated by bootpc.c even if they're not in the
  95.        bootp reply */
  96.  
  97.     inet_aton(getenv("BOOTP_IPADDR"), (struct in_addr *) &intf->ip);
  98.     inet_aton(getenv("BOOTP_NETMASK"), (struct in_addr *) &intf->netmask);
  99.     inet_aton(getenv("BOOTP_BROADCAST"), (struct in_addr *) 
  100.             &intf->broadcast);
  101.     inet_aton(getenv("BOOTP_NETWORK"), (struct in_addr *) 
  102.             &intf->network);
  103.  
  104.     intf->useBootp = 1;
  105.     intf->isConfigured = 1;
  106.     strcpy(intf->dev, device);
  107.  
  108.     if (getenv("BOOTP_GATEWAYS_1")) {
  109.     strcpy(netc->defaultGateway, getenv("BOOTP_GATEWAYS_1"));
  110.     netc->isConfigured = 1;
  111.     }
  112.  
  113.     if (getenv("BOOTP_DNSSRVS_1")) {
  114.     netc->nameserver[0] = strdup(getenv("BOOTP_DNSSRVS_1"));
  115.     netc->isConfigured = 1;
  116.     if (getenv("BOOTP_DNSSRVS_2"))  {
  117.         netc->nameserver[1] = strdup(getenv("BOOTP_DNSSRVS_2"));
  118.         if (getenv("BOOTP_DNSSRVS_3")) 
  119.         netc->nameserver[2] = strdup(getenv("BOOTP_DNSSRVS_3"));
  120.     }
  121.     }
  122.  
  123.     /* 
  124.     If bootp gave us a hostname and domain, use those. Otherwise,
  125.     we'll try and query the nameserver a bit later on. If that fails
  126.     as well, we'll try and use just the hostname BOOTP gave us.
  127.     */
  128.  
  129.     if (getenv("BOOTP_HOSTNAME") && getenv("BOOTP_DOMAIN")) {
  130.     logMessage("bootp returned hostname and domain name");
  131.     strcpy(netc->hostname, getenv("BOOTP_HOSTNAME"));
  132.     netc->isConfigured = 1;
  133.  
  134.     strcpy(netc->domainname, getenv("BOOTP_DOMAIN"));
  135.  
  136.     if (strcmp(netc->hostname, netc->domainname) &&
  137.         !strstr(netc->hostname, netc->domainname)) {
  138.         strcat(netc->hostname, ".");
  139.         strcat(netc->hostname, netc->domainname);
  140.     }
  141.     } 
  142.  
  143.     return 0;
  144. }
  145.  
  146. /* The interface/gateway needs to be configured before this will work! */
  147. static int guessHostname(struct netInterface * intf, struct netConfig * netc) {
  148.     struct in_addr addr;
  149.     char ips[50];
  150.  
  151.     if ((testing || intf->isUp) && netc->nameserver[0]) {
  152.     logMessage("using nameserver to find host and domain name");
  153.     writeResolvConf("/etc", netc);
  154.     memcpy(&addr, &intf->ip, sizeof(addr));
  155.     strcpy(ips, inet_ntoa(addr));
  156.     winStatus(40, 3, "Hostname", "Determing host name and domain...");
  157.         if (in2host(ips, BP_PUT_ENV)) {
  158.         newtPopWindow();
  159.         logMessage("reverse name lookup failed");
  160.  
  161.         if (getenv("BOOTP_HOSTNAME")) {
  162.         strcpy(netc->hostname, getenv("BOOTP_HOSTNAME"));
  163.         } 
  164.  
  165.         return 1;
  166.     } else {
  167.         newtPopWindow();
  168.         logMessage("reverse name lookup worked");
  169.         strcpy(netc->hostname, getenv("BOOTP_HOSTFULL"));
  170.         strcpy(netc->domainname, getenv("BOOTP_HOSTDOMAIN"));
  171.  
  172.         return 0;
  173.     }
  174.     }
  175.  
  176.     return 1;
  177. }
  178.  
  179. int addDefaultRoute(struct netConfig netc) {
  180.     int s;
  181.     struct rtentry route;
  182.     struct sockaddr_in addr;
  183.  
  184.     if (testing) return 0;
  185.  
  186.     if (!strlen(netc.defaultGateway)) return 0;
  187.  
  188.     s = socket(AF_INET, SOCK_DGRAM, 0);
  189.     if (s < 0) {
  190.     close(s);
  191.     errorWindow("socket: %s");
  192.     return 1;
  193.     }
  194.  
  195.     memset(&route, 0, sizeof(route));
  196.  
  197.     addr.sin_family = AF_INET;
  198.     addr.sin_port = 0;
  199.     inet_aton(netc.defaultGateway, &addr.sin_addr);
  200.     memcpy(&route.rt_gateway, &addr, sizeof(addr));
  201.  
  202.     addr.sin_addr.s_addr = INADDR_ANY;
  203.     memcpy(&route.rt_dst, &addr, sizeof(addr));
  204.     memcpy(&route.rt_genmask, &addr, sizeof(addr));
  205.  
  206.     route.rt_flags = RTF_UP | RTF_GATEWAY;
  207.     route.rt_metric = 0;
  208.  
  209.     if (ioctl(s, SIOCADDRT, &route)) {
  210.     close(s);
  211.     errorWindow("SIOCADDRT: %s");
  212.     return 1;
  213.     }
  214.  
  215.     return 0;
  216. }
  217.  
  218. static int configureNetDevice(struct netInterface * intf) {
  219.     struct ifreq req;
  220.     struct rtentry route;
  221.     int s;
  222.     struct sockaddr_in addr;
  223.     struct in_addr ia;
  224.     char ip[20], nm[20], nw[20], bc[20];
  225.  
  226.     addr.sin_family = AF_INET;
  227.     addr.sin_port = 0;
  228.  
  229.     memcpy(&ia, &intf->ip, sizeof(intf->ip));
  230.     strcpy(ip, inet_ntoa(ia));
  231.  
  232.     memcpy(&ia, &intf->netmask, sizeof(intf->netmask));
  233.     strcpy(nm, inet_ntoa(ia));
  234.  
  235.     memcpy(&ia, &intf->broadcast, sizeof(intf->broadcast));
  236.     strcpy(bc, inet_ntoa(ia));
  237.  
  238.     memcpy(&ia, &intf->network, sizeof(intf->network));
  239.     strcpy(nw, inet_ntoa(ia));
  240.  
  241.     logMessage("configuring %s ip: %s nm: %s nw: %s bc: %s", intf->dev,
  242.         ip, nm, nw, bc);
  243.  
  244.     if (testing) return 0;
  245.     
  246.     strcpy(req.ifr_name, intf->dev);
  247.     addr.sin_family = AF_INET;
  248.     addr.sin_port = 0;
  249.     memcpy(&addr.sin_addr, &intf->ip, sizeof(intf->ip));
  250.  
  251.     s = socket(AF_INET, SOCK_DGRAM, 0);
  252.     if (s < 0) {
  253.     errorWindow("socket: %s");
  254.     return 1;
  255.     }
  256.  
  257.     memcpy(&req.ifr_addr, &addr, sizeof(addr));
  258.     if (ioctl(s, SIOCSIFADDR, &req)) {
  259.     close(s);
  260.     errorWindow("SIOCSIFADDR: %s");
  261.     return 1;
  262.     }
  263.  
  264.     memcpy(&addr.sin_addr, &intf->broadcast, sizeof(intf->broadcast));
  265.     memcpy(&req.ifr_broadaddr, &addr, sizeof(addr));
  266.     if (ioctl(s, SIOCSIFBRDADDR, &req)) {
  267.     close(s);
  268.     errorWindow("SIOCSIFNETMASK: %s");
  269.     return 1;
  270.     }
  271.  
  272.     memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask));
  273.     memcpy(&req.ifr_netmask, &addr, sizeof(addr));
  274.     if (ioctl(s, SIOCSIFNETMASK, &req)) {
  275.     close(s);
  276.     errorWindow("SIOCSIFNETMASK: %s");
  277.     return 1;
  278.     }
  279.  
  280.     if (intf->isPtp)
  281.     req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_NOARP;
  282.     else
  283.     req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST;
  284.  
  285.     if (ioctl(s, SIOCSIFFLAGS, &req)) {
  286.     close(s);
  287.     errorWindow("SIOCSIFFLAGS: %s");
  288.     return 1;
  289.     }
  290.  
  291.     memset(&route, 0, sizeof(route));
  292.     route.rt_dev = intf->dev;
  293.     route.rt_flags = RTF_UP;
  294.  
  295.     memcpy(&addr.sin_addr, &intf->network, sizeof(intf->netmask));
  296.     memcpy(&route.rt_dst, &addr, sizeof(addr));
  297.  
  298.     memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask));
  299.     memcpy(&route.rt_genmask, &addr, sizeof(addr));
  300.  
  301.     if (ioctl(s, SIOCADDRT, &route)) {
  302.     close(s);
  303.     errorWindow("SIOCADDRT: %s");
  304.     return 1;
  305.     }
  306.  
  307.     intf->isUp = 1;
  308.  
  309.     return 0;
  310. }
  311.  
  312. int netDeviceAvailable(char * device) {
  313.     struct ifreq req;
  314.     int s;
  315.     
  316.     s = socket(AF_INET, SOCK_DGRAM, 0);
  317.     if (s < 0) {
  318.     close(s);
  319.     errorWindow("socket: %s");
  320.     return 1;
  321.     }
  322.  
  323.     strcpy(req.ifr_name, device);
  324.  
  325.     if (ioctl(s, SIOCGIFFLAGS, &req)) {
  326.     /* if we can't get the flags, the networking device isn't available */
  327.     close(s);
  328.     return 0;
  329.     }
  330.   
  331.     return 1;
  332. }
  333.  
  334. static void interfaceConfigToggle(newtComponent co, void * arg) {
  335.     struct intfconfig_s * info = arg;
  336.     int sense = NEWT_FLAGS_SET;
  337.  
  338.     if (*info->bootpState == ' ') 
  339.     sense = NEWT_FLAGS_RESET;
  340.  
  341.     newtEntrySetFlags(info->ipEntry, NEWT_ENTRY_DISABLED, sense);
  342.     newtEntrySetFlags(info->nmEntry, NEWT_ENTRY_DISABLED, sense);
  343.     newtEntrySetFlags(info->gwEntry, NEWT_ENTRY_DISABLED, sense);
  344.     newtEntrySetFlags(info->nsEntry, NEWT_ENTRY_DISABLED, sense);
  345.  
  346.     newtRefresh();
  347. }
  348.  
  349. static char * findAvailableNetDevice(void) {
  350.     char * devices[] = { "eth0", "tr0", "plip0", "plip1", "plip2", 
  351.              "fddi0", NULL };
  352.     char * device = NULL;
  353.     char ** deviceptr;
  354.  
  355.     /* I should probably ask which device to use if multiple ones are
  356.        available -- oh well :-( */
  357.     for (deviceptr = devices; *deviceptr; deviceptr++) {
  358.     if (netDeviceAvailable(*deviceptr)) {
  359.         device = *deviceptr;
  360.         logMessage("%s is available -- using it for networking", device);
  361.         break;
  362.     }
  363.     }
  364.  
  365.     return device;
  366. }
  367.  
  368. static int setupNetworkInterface(struct netInterface * intf,
  369.                  struct netConfig * netc,
  370.                      struct driversLoaded ** dl, int justConfig) {
  371.     newtComponent okay, cancel, bootp, f, answer;
  372.     int top = 4;
  373.     struct intfconfig_s c;
  374.     struct in_addr addr;
  375.     int32 ptpNetmask;
  376.     int rc;
  377.     int done = 0;
  378.     char useBootp;
  379.     char * device;
  380.     struct driversLoaded * adriver;
  381.  
  382.     device = findAvailableNetDevice();
  383.  
  384.     if (!device) {
  385.     if ((rc = loadDeviceDriver(DRIVER_NET, dl, 0)))
  386.         return rc;
  387.  
  388.     for (adriver = *dl; adriver && adriver->type != DRIVER_NET; 
  389.         adriver = adriver->next);
  390.     if (!adriver) {
  391.         logMessage("ack! loadDriveDriver() worked but didn't load a "
  392.             "DRIVE_NET!!");
  393.         return INST_ERROR;
  394.     }
  395.  
  396.     switch (adriver->minor) {
  397.       case DRIVER_MINOR_ETHERNET:    device = "eth0"; break;
  398.       case DRIVER_MINOR_TR:        device = "tr0"; break;
  399.       case DRIVER_MINOR_PLIP:    device = getPlipDeviceName(); break;
  400.       default:            exit(1); /* ack! */
  401.     }
  402.     }
  403.  
  404.     newtCenteredWindow(50, 15, "Configure TCP/IP");
  405.  
  406.     c.ipLabel = newtLabel(1, top + 2, "IP address:");
  407.     c.nmLabel = newtLabel(1, top + 3, "Netmask:");
  408.     c.gwLabel = newtLabel(1, top + 4, "Default gateway (IP):");
  409.     c.nsLabel = newtLabel(1, top + 5, "Primary nameserver:");
  410.    
  411.     if (!intf->ip){
  412.     c.ipEntry = newtEntry(25, top + 2, "", 16, &c.ip, 0);
  413.     } else {
  414.     memcpy(&addr, &intf->ip, sizeof(intf->ip));
  415.     c.ipEntry = newtEntry(25, top + 2, inet_ntoa(addr), 16, &c.ip, 0);
  416.     }
  417.  
  418.     if (!intf->netmask){
  419.     c.nmEntry = newtEntry(25, top + 3, "", 16, &c.nm, 0);
  420.     } else {
  421.     memcpy(&addr, &intf->netmask, sizeof(intf->netmask));
  422.     c.nmEntry = newtEntry(25, top + 3, inet_ntoa(addr), 16, &c.nm, 0);
  423.     }
  424.  
  425.     if (!netc->defaultGateway) 
  426.     c.gwEntry = newtEntry(25, top + 4, "", 16, &c.gw, 0);
  427.     else
  428.     c.gwEntry = newtEntry(25, top + 4, netc->defaultGateway, 16, &c.gw, 0);
  429.  
  430.  
  431.     if (!netc->nameserver[0]) 
  432.     c.nsEntry = newtEntry(25, top + 5, "", 16, &c.ns, 0);
  433.     else
  434.     c.nsEntry = newtEntry(25, top + 5, netc->nameserver[0], 16, &c.ns, 0);
  435.     
  436.     c.bootpState = &useBootp;
  437.    
  438.     f = newtForm(NULL, NULL, 0);
  439.  
  440.     bootp = newtCheckbox(1, top, "Configure device with bootp", 
  441.              (intf->isConfigured && intf->useBootp) ? '*' : ' ', 
  442.              NULL, &useBootp);
  443.  
  444.     newtComponentAddCallback(bootp, interfaceConfigToggle, &c);
  445.  
  446.     newtFormAddComponents(f, bootp, c.ipLabel, c.nmLabel, c.gwLabel, c.nsLabel, 
  447.                  c.ipEntry, c.nmEntry, c.gwEntry, c.nsEntry, NULL);
  448.  
  449.     if (c.bootpState)
  450.     newtFormSetCurrent(f, c.ipEntry);
  451.  
  452.     newtComponentAddCallback(c.ipEntry, ipCallback, &c);
  453.     newtComponentAddCallback(c.nmEntry, ipCallback, &c);
  454.  
  455.     okay = newtButton(8, top + 7, "Ok");
  456.     cancel = newtButton(28, top + 7, "Cancel");
  457.  
  458.     newtFormAddComponents(f, okay, cancel, NULL);
  459.  
  460.     do {
  461.     answer = newtRunForm(f);
  462.  
  463.     if (answer == cancel) {
  464.         newtFormDestroy(f);
  465.         newtPopWindow();
  466.  
  467.         return INST_CANCEL;
  468.     }
  469.  
  470.     if (useBootp != ' ') {
  471.         logMessage("Configuring device %s via bootp", device);
  472.         if (justConfig) {
  473.         done = 1;
  474.         intf->useBootp = 1;
  475.         intf->isConfigured = 1;
  476.         } else if (!doBootp(device, intf, netc)) {
  477.         done = 1;
  478.         }
  479.     } else {
  480.         strcpy(intf->dev, device);
  481.         inet_aton(c.ip, (struct in_addr *) &intf->ip);
  482.         inet_aton(c.nm, (struct in_addr *) &intf->netmask);
  483.         intf->broadcast = (intf->ip & intf->netmask) | (~intf->netmask);
  484.  
  485.         inet_aton("255.255.255.255", (struct in_addr *) &ptpNetmask);
  486.  
  487.         if (ptpNetmask == intf->netmask) {
  488.         logMessage("configuring point to point device");
  489.         inet_aton(c.gw, (struct in_addr *) &intf->network);
  490.         intf->isPtp = 1;
  491.         } else {
  492.         intf->network = intf->ip & intf->netmask;
  493.         intf->isPtp = 0;
  494.         }
  495.  
  496.         intf->isConfigured = 1;
  497.         intf->useBootp = 0;
  498.  
  499.         strcpy(netc->defaultGateway, c.gw);
  500.  
  501.         if (netc->nameserver[0]) free(netc->nameserver[0]);
  502.  
  503.         if (strlen(c.ns))
  504.         netc->nameserver[0] = strdup(c.ns);
  505.         else
  506.         netc->nameserver[0] = NULL;
  507.         
  508.         netc->isConfigured = 1;
  509.  
  510.         done = 1;
  511.     }
  512.     } while (!done);
  513.  
  514.     newtFormDestroy(f);
  515.     newtPopWindow();
  516.  
  517.     if (!justConfig) {
  518.     if (configureNetDevice(intf)) return INST_ERROR;
  519.     if (addDefaultRoute(*netc)) return INST_ERROR;
  520.     }
  521.  
  522.     return 0;
  523.  
  524. static void hnCallback(newtComponent co, void * dptr) {
  525.     char * buf;
  526.     struct netconfig_s * data = dptr;
  527.  
  528.     if (strlen(data->hn)) return;
  529.     if (!strlen(data->dn)) return;
  530.  
  531.     buf = alloca(strlen(data->dn) + 5);
  532.     strcpy(buf, ".");
  533.     strcat(buf, data->dn);
  534.     
  535.     newtEntrySet(data->hnEntry, buf, 0);
  536. }
  537.  
  538. static void ipCallback(newtComponent co, void * dptr) {
  539.     struct intfconfig_s * data = dptr;
  540.     struct in_addr ipaddr, nmaddr, addr;
  541.     char * ascii;
  542.     int32 broadcast, network;
  543.  
  544.     if (co == data->ipEntry) {
  545.     if (strlen(data->ip) && !strlen(data->nm)) {
  546.         if (inet_aton(data->ip, &ipaddr)) {
  547.         ipaddr.s_addr = ntohl(ipaddr.s_addr);
  548.         if (((ipaddr.s_addr & 0xFF000000) >> 24) <= 127)
  549.             ascii = "255.0.0.0";
  550.         else if (((ipaddr.s_addr & 0xFF000000) >> 24) <= 191)
  551.             ascii = "255.255.0.0";
  552.         else 
  553.             ascii = "255.255.255.0";
  554.         newtEntrySet(data->nmEntry, ascii, 1);
  555.         }
  556.     }
  557.     } else if (co == data->nmEntry) {
  558.     if (!strlen(data->ip) || !strlen(data->nm)) return;
  559.     if (!inet_aton(data->ip, &ipaddr)) return;
  560.     if (!inet_aton(data->nm, &nmaddr)) return;
  561.  
  562.         network = ipaddr.s_addr & nmaddr.s_addr;
  563.     broadcast = (ipaddr.s_addr & nmaddr.s_addr) | (~nmaddr.s_addr);
  564.  
  565.     addr.s_addr = htonl(ntohl(broadcast) - 1);
  566.     newtEntrySet(data->gwEntry, inet_ntoa(addr), 1);
  567.  
  568.     /* I'm such a lazy bastard */
  569.     if ((ntohl(network) & 0xFFFFFF00) == 0xc7b71800) {
  570.         newtEntrySet(data->nsEntry, "199.183.24.1", 1);
  571.     } else {
  572.         addr.s_addr = htonl(ntohl(network) + 1);
  573.         newtEntrySet(data->nsEntry, inet_ntoa(addr), 1);
  574.     }
  575.     }
  576. }
  577.  
  578. int writeNetConfig(char * prefix, struct netConfig * netc, 
  579.            struct netInterface * gwdev, int verbose) {
  580.     char filename[100];
  581.     FILE * f;
  582.  
  583.     if (testing) return 0;
  584.  
  585.     sprintf(filename, "%s/network", prefix);
  586.  
  587.     f = fopen(filename, "w");
  588.     if (!f) {
  589.     errorWindow("cannot create network config file: %s");
  590.     return INST_ERROR;
  591.     }
  592.  
  593.     fprintf(f, "NETWORKING=yes\n");
  594.     fprintf(f, "FORWARD_IPV4=false\n");
  595.  
  596.     logMessage("writing network information to %s", filename);
  597.  
  598.     if (netc->hostname && strlen(netc->hostname)) {
  599.     logMessage("\tnetwork is configured, writing complete information");
  600.  
  601.     fprintf(f, "HOSTNAME=%s\n", netc->hostname);
  602.     fprintf(f, "DOMAINNAME=%s\n", netc->domainname);
  603.  
  604.     if (gwdev && strlen(netc->defaultGateway)) {
  605.         fprintf(f, "GATEWAY=%s\n", netc->defaultGateway);
  606.         fprintf(f, "GATEWAYDEV=%s\n", gwdev->dev);
  607.     }
  608.  
  609.     if (verbose) {
  610.         if (netc->nameserver[0])
  611.         fprintf(f, "NS1=%s\n", netc->nameserver[0]);
  612.         
  613.         if (netc->nameserver[1])
  614.         fprintf(f, "NS2=%s\n", netc->nameserver[1]);
  615.         
  616.         if (netc->nameserver[2])
  617.         fprintf(f, "NS3=%s\n", netc->nameserver[2]);
  618.     }
  619.     } else {
  620.     logMessage("\tnetwork is not configured");
  621.     fprintf(f, "HOSTNAME=localhost.localdomain\n");
  622.     }
  623.  
  624.     fclose(f);
  625.  
  626.     return 0;
  627. }
  628.  
  629. int writeHosts(char * prefix, struct netConfig * netc, 
  630.            struct netInterface * intf) {
  631.     char filename[100];
  632.     FILE * f;
  633.     struct in_addr * addrptr;
  634.     char * nickname;
  635.     int i;
  636.  
  637.     if (testing) return 1;
  638.  
  639.     sprintf(filename, "%s/hosts", prefix);
  640.  
  641.     /* if /etc/hosts already exists, don't bother creating one */
  642.     if (!access(filename, R_OK)) {
  643.     logMessage("%s already exists -- won't crunch it", filename);
  644.     return 0;
  645.     }
  646.     logMessage("%s doesn not exist -- creating", filename);
  647.  
  648.     f = fopen(filename, "w");
  649.     if (!f) {
  650.     errorWindow("cannot create /etc/hosts: %s");
  651.     return INST_ERROR;
  652.     }
  653.  
  654.     logMessage("writing host information to %s", filename);
  655.  
  656.     fprintf(f, "127.0.0.1\t\tlocalhost localhost.localdomain\n");
  657.     if (netc->hostname && strlen(netc->hostname)) {
  658.     addrptr = (struct in_addr *) &intf->ip;
  659.     i = strlen(netc->hostname) - strlen(netc->domainname);
  660.     if (i > 1 && !strcmp(netc->hostname + i, netc->domainname)
  661.         && netc->hostname[i - 1] == '.') {
  662.         nickname = strdup(netc->hostname);
  663.         nickname[i - 1] = '\0';
  664.         fprintf(f, "%s\t\t%s %s\n", inet_ntoa(*addrptr),
  665.             netc->hostname, nickname);
  666.         free(nickname);
  667.     } else {
  668.         fprintf(f, "%s\t\t%s\n", inet_ntoa(*addrptr),
  669.             netc->hostname);
  670.     }
  671.  
  672.     sethostname(netc->hostname, strlen(netc->hostname));
  673.     }
  674.  
  675.     fclose(f);
  676.  
  677.     res_init();        /* reinit the resolver so DNS changes take affect */
  678.  
  679.     return 0;
  680. }
  681.  
  682. int writeResolvConf(char * prefix, struct netConfig * netc) {
  683.     char filename[100];
  684.     FILE * f;
  685.  
  686.     if (testing) return 1;
  687.  
  688.     if (!netc->domainname && !netc->nameserver[0]) {
  689.     logMessage("networking is not configured - not writing resolv.conf");
  690.     return 0;
  691.     }
  692.  
  693.     sprintf(filename, "%s/resolv.conf", prefix);
  694.  
  695.     f = fopen(filename, "w");
  696.     if (!f) {
  697.     errorWindow("cannot create resolv.conf: %s");
  698.     return INST_ERROR;
  699.     }
  700.  
  701.     logMessage("writing nameservices information to %s", filename);
  702.  
  703.     if (netc->domainname)
  704.     fprintf(f, "search %s\n", netc->domainname);
  705.  
  706.     if (netc->nameserver[0])
  707.     fprintf(f, "nameserver %s\n", netc->nameserver[0]);
  708.     
  709.     if (netc->nameserver[1])
  710.     fprintf(f, "nameserver %s\n", netc->nameserver[1]);
  711.     
  712.     if (netc->nameserver[2])
  713.     fprintf(f, "nameserver %s\n", netc->nameserver[2]);
  714.  
  715.     fclose(f);
  716.  
  717.     res_init();        /* reinit the resolver so DNS changes take affect */
  718.  
  719.     return 0;
  720. }
  721.  
  722. int writeNetInterfaceConfig(char * prefix, struct netInterface * intf) {
  723.     char filename[100];
  724.     FILE * f;
  725.     struct in_addr * addrptr;
  726.  
  727.     if (testing) return 0;
  728.  
  729.     if (!intf->isConfigured) {
  730.     logMessage("network interface is not configured - not creating "
  731.            "ifcfg-*");
  732.     return(0);
  733.     }
  734.  
  735.     sprintf(filename, "%s/ifcfg-%s", prefix, intf->dev);
  736.  
  737.     f = fopen(filename, "w");
  738.     if (!f) {
  739.     errorWindow("cannot create network device config file: %s");
  740.     return INST_ERROR;
  741.     }
  742.  
  743.     logMessage("writing network information to %s", filename);
  744.     
  745.     fprintf(f, "DEVICE=%s\n", intf->dev);
  746.  
  747.     if (intf->useBootp) 
  748.     fprintf(f, "BOOTPROTO=bootp\n");
  749.  
  750.     if (!strcmp(prefix, "/tmp") || !intf->useBootp) {
  751.     addrptr = (struct in_addr *) &intf->ip;
  752.     fprintf(f, "IPADDR=%s\n", inet_ntoa(*addrptr));
  753.  
  754.     addrptr = (struct in_addr *) &intf->netmask;
  755.     fprintf(f, "NETMASK=%s\n", inet_ntoa(*addrptr));
  756.  
  757.     addrptr = (struct in_addr *) &intf->network;
  758.     fprintf(f, "NETWORK=%s\n", inet_ntoa(*addrptr));
  759.  
  760.     addrptr = (struct in_addr *) &intf->broadcast;
  761.     fprintf(f, "BROADCAST=%s\n", inet_ntoa(*addrptr));
  762.     }
  763.  
  764.     fprintf(f, "ONBOOT=yes\n");
  765.  
  766.     fclose(f);
  767.  
  768.     return 0;
  769. }
  770.  
  771. int readNetInterfaceConfig(char * prefix, char * device, 
  772.                 struct netInterface * intf) {
  773.     FILE * f;
  774.     char * start, * end;
  775.     char buf[250];
  776.     int line = 0;
  777.  
  778.     intf->isConfigured = 0;
  779.  
  780.     if (testing) {
  781.     return 0;
  782.     }
  783.  
  784.     sprintf(buf, "%s/ifcfg-%s", prefix, device);
  785.  
  786.     f = fopen(buf, "r");
  787.     if (!f) {
  788.     if (errno != ENOENT) {
  789.         errorWindow("cannot open file: %s");
  790.         return INST_ERROR;
  791.     } else {
  792.         intf->ip = 0;
  793.         return 0;
  794.     }
  795.     }
  796.  
  797.     while (fgets(buf, sizeof(buf) - 1, f)) {
  798.     line++;
  799.  
  800.     start = buf;
  801.  
  802.     /* skipping leading spaces */
  803.     while (*start && isspace(*start)) start++;
  804.     if (!*start) continue;
  805.  
  806.     /* skip comments */
  807.     if (*start == '#') continue;
  808.  
  809.     /* cut off trailing spaces and \n */
  810.     end = start + strlen(start) - 2;
  811.     while (isspace(*end)) end--;
  812.     end++;
  813.     *end = '\0';    
  814.     end--;
  815.     
  816.     if (!strncmp("IPADDR=", start, 7)) {
  817.         start += 7;
  818.         inet_aton(start, (struct in_addr *) &intf->ip);
  819.     } else if (!strncmp("DEVICE=", start, 7)) {
  820.         start += 7;
  821.         strcpy(intf->dev, start);
  822.     } else if (!strncmp("BOOTPROTO=bootp", start, 15)) {
  823.         intf->useBootp = 1;
  824.     } else if (!strncmp("NETMASK=", start, 8)) {
  825.         start += 8;
  826.         inet_aton(start, (struct in_addr *) &intf->netmask);
  827.     } else if (!strncmp("NETWORK=", start, 8)) {
  828.         start += 8;
  829.         inet_aton(start, (struct in_addr *) &intf->network);
  830.         if (!strcmp(start, "255.255.255.255"))
  831.         intf->isPtp = 1;
  832.     } else if (!strncmp("BROADCAST=", start, 10)) {
  833.         start += 10;
  834.         inet_aton(start, (struct in_addr *) &intf->broadcast);
  835.     }
  836.     }
  837.  
  838.     fclose(f);
  839.  
  840.     intf->isConfigured = 1;
  841.  
  842.     return 0;
  843. }
  844.  
  845. int configureNetwork(struct netConfig * netc, 
  846.              struct netInterface * intf) {
  847.     struct netconfig_s n;
  848.     int top = 3;
  849.     newtComponent f, okay, cancel, answer;
  850.     int i;
  851.  
  852.     n.dnLabel = newtLabel(1, top    , "Domain name:");
  853.     n.hnLabel = newtLabel(1, top + 1, "Host name:");
  854.     n.nsLabels[1] = newtLabel(1, top + 2, "Secondary nameserver (IP):");
  855.     n.nsLabels[2] = newtLabel(1, top + 3, "Tertiary nameserver (IP):");
  856.  
  857.     n.dnEntry = newtEntry(28, top    , "", 20, &n.dn, NEWT_ENTRY_SCROLL);
  858.     n.hnEntry = newtEntry(28, top + 1, "", 20, &n.hn, NEWT_ENTRY_SCROLL);
  859.     n.nsEntrys[1] = newtEntry(28, top + 2, "", 20, &n.ns[1], NEWT_ENTRY_SCROLL);
  860.     n.nsEntrys[2] = newtEntry(28, top + 3, "", 20, &n.ns[2], NEWT_ENTRY_SCROLL);
  861.  
  862.     if (!strlen(netc->hostname) && !strlen(netc->domainname) && 
  863.         (testing || intf->isUp) && netc->nameserver[0]) {
  864.     guessHostname(intf, netc);
  865.  
  866.     if (netc->hostname[0] && netc->domainname[0] && !expert) {
  867.         logMessage("reverse name lookup worked; skipping hostname config");
  868.         return 0;
  869.     }
  870.     } 
  871.  
  872.     newtCenteredWindow(50, 15, "Configure Network");
  873.  
  874.     if (netc->hostname)
  875.     newtEntrySet(n.hnEntry, netc->hostname, 0);
  876.  
  877.     if (netc->domainname)
  878.     newtEntrySet(n.dnEntry, netc->domainname, 0);
  879.  
  880.     if (netc->nameserver[1])
  881.     newtEntrySet(n.nsEntrys[1], netc->nameserver[1], 0);
  882.     if (netc->nameserver[2])
  883.     newtEntrySet(n.nsEntrys[2], netc->nameserver[2], 0);
  884.  
  885.     newtComponentAddCallback(n.dnEntry, hnCallback, &n);
  886.  
  887.     f = newtForm(NULL, NULL, 0);
  888.     newtFormAddComponents(f, n.dnLabel, n.hnLabel, n.nsLabels[1], 
  889.               n.nsLabels[2], NULL);
  890.     newtFormAddComponents(f, n.dnEntry, n.hnEntry, n.nsEntrys[1], 
  891.               n.nsEntrys[2], NULL);
  892.  
  893.     okay = newtButton(11, 11, "Ok");
  894.     cancel = newtButton(30, 11, "Cancel");
  895.  
  896.     newtFormAddComponents(f, okay, cancel, NULL);
  897.  
  898.     answer = newtRunForm(f);
  899.  
  900.     strcpy(netc->hostname, n.hn);
  901.     strcpy(netc->domainname, n.dn);
  902.  
  903.     for (i = 1; i < 3; i++) {
  904.     if (netc->nameserver[i]) 
  905.         free(netc->nameserver[i]);
  906.     netc->nameserver[i] = *n.ns[i] ? strdup(n.ns[i]) : NULL;
  907.     }
  908.  
  909.     newtFormDestroy(f);
  910.     newtPopWindow();
  911.  
  912.     if (answer == cancel) return INST_CANCEL;
  913.  
  914.     netc->isConfigured = 1;
  915.  
  916.     return 0;
  917. }
  918.  
  919. int readNetConfig(char * prefix, struct netConfig * netc) {
  920.     FILE * f;
  921.     char * start, * end;
  922.     char buf[250];
  923.     int line = 0;
  924.  
  925.     if (testing) {
  926.     return 0;
  927.     }
  928.  
  929.     sprintf(buf, "%s/network", prefix);
  930.  
  931.     f = fopen(buf, "r");
  932.     if (!f) {
  933.     if (errno != ENOENT) {
  934.         errorWindow("cannot open file: %s");
  935.         return INST_ERROR;
  936.     } else {
  937.         netc->hostname[0] = '\0';
  938.         return 0;
  939.     }
  940.     }
  941.  
  942.     memset(netc, 0, sizeof(*netc));
  943.  
  944.     while (fgets(buf, sizeof(buf) - 1, f)) {
  945.     line++;
  946.  
  947.     start = buf;
  948.  
  949.     /* skipping leading spaces */
  950.     while (*start && isspace(*start)) start++;
  951.     if (!*start) continue;
  952.  
  953.     /* skip comments */
  954.     if (*start == '#') continue;
  955.  
  956.     /* cut off trailing spaces and \n */
  957.     end = start + strlen(start) - 2;
  958.     while (isspace(*end)) end--;
  959.     end++;
  960.     *end = '\0';    
  961.     end--;
  962.     
  963.     if (!strncmp("HOSTNAME=", start, 9)) {
  964.         start += 9;
  965.         strcpy(netc->hostname, start);
  966.     } else if (!strncmp("DOMAINNAME=", start, 11)) {
  967.         start += 11;
  968.         strcpy(netc->domainname, start);
  969.     } else if (!strncmp("GATEWAY=", start, 8)) {
  970.         start += 8;
  971.         strcpy(netc->defaultGateway, start);
  972.     } else if (!strncmp("NS1=", start, 4)) {
  973.         start += 4;
  974.         netc->nameserver[0] = strdup(start);
  975.     } else if (!strncmp("NS2=", start, 4)) {
  976.         start += 4;
  977.         netc->nameserver[1] = strdup(start);
  978.     } else if (!strncmp("NS3=", start, 4)) {
  979.         start += 4;
  980.         netc->nameserver[2] = strdup(start);
  981.     }
  982.     }
  983.  
  984.     fclose(f);
  985.  
  986.     netc->isConfigured = 1;
  987.  
  988.     return 0;
  989. }
  990.  
  991.  
  992. int bringUpNetworking(struct netInterface * intf, struct netConfig * netc,
  993.               struct driversLoaded ** dl) {
  994.     return doBringUpNetworking(intf, netc, dl, 0);
  995. }
  996.  
  997. #define BRINGUP_NET     1
  998. #define BRINGUP_CONF    2
  999. #define BRINGUP_ROUTE    3
  1000. #define BRINGUP_DONE    4
  1001.  
  1002. static int doBringUpNetworking(struct netInterface * intf, 
  1003.                    struct netConfig * netc,
  1004.                    struct driversLoaded ** dl, int justConfig) {
  1005.     int where = BRINGUP_NET;
  1006.     int rc;
  1007.     char * device;
  1008.  
  1009.     if (kickstart) {
  1010.     if (intf->isConfigured && netc->isConfigured) return 0;
  1011.  
  1012.     /* justConfig must be zero, we have to actually do something for this
  1013.        to happen automatically */
  1014.  
  1015.     device = findAvailableNetDevice();
  1016.  
  1017.     if (!device) {
  1018.         if ((rc = loadDeviceDriver(DRIVER_NET, dl, 1))) { 
  1019.         newtWinMessage("Ethernet Probe", "Ok", 
  1020.             "The Ethernet probe failed "
  1021.             "to find a card on your system. Press <Enter> to manually "
  1022.             "configure one.");
  1023.  
  1024.         while (setupNetworkInterface(intf, netc, dl, 0)) ;
  1025.         }
  1026.  
  1027.         if (!(device = findAvailableNetDevice()))  {
  1028.         newtWinMessage("Network Failed", "Hang", "No networking "
  1029.                 "devices are available. You should never "
  1030.                 "have gotten this far.");
  1031.         }
  1032.     }
  1033.  
  1034.     while (doBootp(device, intf, netc)) {
  1035.         newtWinMessage("Bootp Failed", "Retry", "Bootp failed to find an "
  1036.         "IP address. Press <Enter> to retry.");
  1037.     }
  1038.  
  1039.     configureNetDevice(intf);
  1040.     addDefaultRoute(*netc);
  1041.  
  1042.     while (guessHostname(intf, netc)) {
  1043.         newtWinMessage("Hostname Lookup", "Retry", 
  1044.         "I cannot find by hostname via DNS. Press <Enter> to retry.");
  1045.      }
  1046.  
  1047.     return addDefaultRoute(*netc);
  1048.     }
  1049.  
  1050.     while (where != BRINGUP_DONE) {
  1051.     switch (where) {
  1052.       case BRINGUP_NET:
  1053.         rc = setupNetworkInterface(intf, netc, dl, justConfig);
  1054.         if (rc) return rc;
  1055.         where = BRINGUP_CONF;
  1056.         break;
  1057.  
  1058.       case BRINGUP_CONF:
  1059.         rc = configureNetwork(netc, intf);
  1060.         if (rc == INST_CANCEL)
  1061.         where = BRINGUP_NET;
  1062.         else if (rc)
  1063.         return INST_ERROR;
  1064.         else
  1065.         where = BRINGUP_ROUTE;
  1066.         break;
  1067.  
  1068.       case BRINGUP_ROUTE:
  1069.         if (justConfig)
  1070.         rc = 0;
  1071.         else
  1072.         rc = addDefaultRoute(*netc);
  1073.  
  1074.         if (rc) return rc;
  1075.         where = BRINGUP_DONE;
  1076.         break;
  1077.     }
  1078.     }
  1079.  
  1080.     /* write out the /etc/resolv.conf, as we'll need that to use name services
  1081.        properly */
  1082.     writeResolvConf("/etc", netc);
  1083.  
  1084.     return 0;
  1085. }
  1086.  
  1087. #define CHECKNET_CONFIG        1
  1088. #define CHECKNET_KEEP        2
  1089. #define CHECKNET_NONE        3
  1090. #define CHECKNET_NOBOOTP    4
  1091.  
  1092. static int checkNetConfigPanel(int isConfigured, int useBootp, int * choice) {
  1093.     newtComponent text, okay, cancel;
  1094.     newtComponent f, answer, yes, no, listbox;
  1095.     int which;
  1096.  
  1097.     if (isConfigured && kickstart) {
  1098.     *choice = CHECKNET_KEEP;
  1099.     return 0;
  1100.     } else if (isConfigured) {
  1101.     newtCenteredWindow(42, 13, "Network Configuration");
  1102.     text = newtTextbox(1, 1, 40, 2, NEWT_TEXTBOX_WRAP);
  1103.     newtTextboxSetText(text,
  1104.         "LAN networking has already been configured. Do you "
  1105.         "want to:");
  1106.  
  1107.     listbox = newtListbox(8, 4, 0, NEWT_LISTBOX_RETURNEXIT);
  1108.  
  1109.     if (useBootp) {
  1110.         newtListboxAddEntry(listbox, "Use bootp at startup", (void *) 1);
  1111.         newtListboxAddEntry(listbox, "Use the current IP information", 
  1112.                       (void *) 4);
  1113.         newtListboxAddEntry(listbox, "Reconfigure network now",
  1114.                       (void *) 2);
  1115.         newtListboxAddEntry(listbox, "Don't setup networking", (void *) 3);
  1116.     } else {
  1117.         newtListboxAddEntry(listbox, "Keep this setup", (void *) 1);
  1118.         newtListboxAddEntry(listbox, "Reconfigure network now",
  1119.                       (void *) 2);
  1120.         newtListboxAddEntry(listbox, "Don't setup networking", (void *) 3);
  1121.     }
  1122.  
  1123.     okay = newtButton(6, 9, "Ok");
  1124.     cancel = newtButton(23, 9, "Cancel");
  1125.  
  1126.     f = newtForm(NULL, NULL, 0);
  1127.  
  1128.     newtFormAddComponents(f, text, listbox, okay, cancel, NULL);
  1129.  
  1130.     answer = newtRunForm(f);
  1131.     if (answer == cancel) {
  1132.         newtPopWindow();
  1133.         newtFormDestroy(f);
  1134.  
  1135.         return INST_CANCEL;
  1136.     }
  1137.  
  1138.     which = (int) newtListboxGetCurrent(listbox);
  1139.  
  1140.     newtPopWindow();
  1141.     newtFormDestroy(f);
  1142.  
  1143.     if (which == 1)
  1144.         *choice = CHECKNET_KEEP;
  1145.     else if (which == 3)
  1146.         *choice = CHECKNET_NONE;
  1147.     else if (which == 4)
  1148.         *choice = CHECKNET_NOBOOTP;
  1149.     else
  1150.         *choice = CHECKNET_CONFIG;
  1151.     } else if (kickstart) {
  1152.     /* XXX this ought to be configurable */
  1153.     *choice = CHECKNET_NONE;
  1154.     } else {
  1155.     newtCenteredWindow(42, 10, "Network Configuration");
  1156.  
  1157.     text = newtTextbox(1, 1, 40, 3, NEWT_TEXTBOX_WRAP);
  1158.     newtTextboxSetText(text,
  1159.         "Do you want to configure LAN (not dialup) networking "
  1160.         "for your installed system?");
  1161.  
  1162.     yes = newtButton(3, 6, " Yes ");
  1163.     no = newtButton(16, 6, "  No  ");
  1164.     cancel = newtButton(29, 6, "Cancel");
  1165.  
  1166.     f = newtForm(NULL, NULL, 0);
  1167.     newtFormAddComponents(f, text, yes, no, cancel, NULL);
  1168.  
  1169.     answer = newtRunForm(f);
  1170.     if (answer == f) 
  1171.         answer = newtFormGetCurrent(f);
  1172.  
  1173.     newtPopWindow();
  1174.     newtFormDestroy(f);
  1175.  
  1176.     if (answer == yes) {
  1177.         *choice = CHECKNET_CONFIG;
  1178.     } else if (answer == cancel) {
  1179.         return INST_CANCEL;
  1180.     } else {
  1181.         *choice = CHECKNET_NONE;
  1182.     }
  1183.     }
  1184.  
  1185.     return 0;
  1186. }
  1187.  
  1188. int checkNetConfig(struct netInterface * intf, struct netConfig * netc,
  1189.            struct driversLoaded ** dl) {
  1190.     int choice, rc;
  1191.  
  1192.     /* this doesn't handle cancel very well as the dl makes it difficult :-( */
  1193.  
  1194.     do {
  1195.     rc = checkNetConfigPanel(netc->isConfigured && intf->isConfigured,
  1196.                  intf->useBootp, &choice);
  1197.     if (rc) return rc;
  1198.  
  1199.     switch (choice) {
  1200.       case CHECKNET_NOBOOTP:
  1201.         intf->useBootp = 0;
  1202.         rc = 0;
  1203.         break;
  1204.  
  1205.       case CHECKNET_CONFIG:
  1206.         rc = doBringUpNetworking(intf, netc, dl, 1);
  1207.         if (rc == INST_ERROR) return rc;
  1208.         break;
  1209.  
  1210.       case CHECKNET_NONE:
  1211.         intf->isConfigured = netc->isConfigured = 0;
  1212.         rc = 0;
  1213.         break;
  1214.     }
  1215.     } while (rc);
  1216.  
  1217.     return 0;
  1218. }
  1219.