home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / install / earlymethods.c < prev    next >
C/C++ Source or Header  |  1997-11-05  |  16KB  |  607 lines

  1. #include <ctype.h>
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <newt.h>
  5. #include <popt.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/mount.h>
  10. #include <unistd.h>
  11.  
  12. #include "dns.h"
  13. #include "hd.h"
  14. #include "fs.h"
  15. #include "install.h"
  16. #include "kickstart.h"
  17. #include "log.h"
  18. #include "methods.h"
  19. #include "net.h"
  20. #include "windows.h"
  21.  
  22. /* disable the smb install as smbfs seems hosed in 2.0.31 */
  23. #define SMB_INSTALL 0
  24.  
  25. /* This was split into two pieces to keep the initial install program small */
  26.  
  27. static int nfsPrepare(struct installMethod * method, struct netConfig * netc,
  28.                struct netInterface * intf, struct driversLoaded ** dl);
  29. static int cdromPrepare(struct installMethod * method, struct netConfig * netc,
  30.                struct netInterface * intf, struct driversLoaded ** dl);
  31. static int nfsGetSetup(char ** hostptr, char ** dirptr);
  32. int floppyRoot(struct installMethod * method, struct netConfig * netc,
  33.                struct netInterface * intf, struct driversLoaded ** dl);
  34.  
  35. #if SMB_INSTALL
  36. static int smbGetSetup(char ** hostptr, char ** dirptr, char ** acctptr,
  37.             char ** pwptr);
  38. #endif
  39. static int totalMemory(void);            /* in K */
  40.  
  41. #define CDROM_METHOD_NUM 0
  42. #define NFS_METHOD_NUM 1
  43. static struct installMethod methods[] = {
  44.     { "Local CDROM",         "cdrom", 0, cdromPrepare, NULL, NULL,
  45.         NULL, NULL, NULL },
  46.     { "NFS image",         "nfs", 0, nfsPrepare, NULL, NULL,
  47.         NULL, NULL, NULL },
  48.     { "hard drive",        "hd", 0, floppyRoot, NULL, NULL,
  49.         NULL, NULL, NULL },
  50.     { "FTP",             "ftp", 0, floppyRoot, NULL, NULL,
  51.         NULL, NULL, NULL },
  52. #if SMB_INSTALL
  53.     { "SMB image",         "smb", 0, floppyRoot, NULL, NULL,
  54.         NULL, NULL, NULL },
  55. #endif
  56. #if 0
  57.     { "SCSI Tape Install",     "tape", 0, floppyRoot, NULL, NULL,
  58.         NULL, NULL, NULL },
  59. #endif
  60. } ;
  61. static int numMethods = sizeof(methods) / sizeof(struct installMethod);
  62.  
  63. #define LOAD_BLOCK_COUNT 16
  64. static int loadRamdisk(char * todev, char * fromdev, int blocks,
  65.             char * label) {
  66.     newtComponent form, scale;
  67.     char * topath, * frompath;
  68.     char buf[LOAD_BLOCK_COUNT * 1024];
  69.     int rc = 0;
  70.     int i;
  71.     int to, from;
  72.  
  73.     if (blocks % LOAD_BLOCK_COUNT) {
  74.     logMessage("internal error: blocks in loadRamdisk() must be "
  75.         "divisible by %d!!", LOAD_BLOCK_COUNT);
  76.     return 1;
  77.     }
  78.  
  79.     topath = alloca(strlen(todev) + 8);
  80.     sprintf(topath, "/tmp/%s", todev);
  81.  
  82.     frompath = alloca(strlen(fromdev) + 8);
  83.     sprintf(frompath, "/tmp/%s", fromdev);
  84.  
  85.     if (devMakeInode(todev, topath)) return 1;
  86.     if (devMakeInode(fromdev, frompath)) {
  87.     unlink(topath);
  88.     return 1;
  89.     }
  90.  
  91.     to = open(topath, O_WRONLY);
  92.     if (to < 0) {
  93.     logMessage("failed to open %s: %s", topath, strerror(errno));
  94.     unlink(topath);
  95.     unlink(frompath);
  96.     return 1;
  97.     }
  98.  
  99.     from = open(frompath, O_RDONLY);
  100.     if (from < 0) {
  101.     logMessage("failed to open %s: %s", frompath, strerror(errno));
  102.     unlink(topath);
  103.     unlink(frompath);
  104.     return 1;
  105.     }
  106.  
  107.     unlink(frompath);
  108.     unlink(topath);
  109.  
  110.     logMessage("copying %d blocks from %s to %s", blocks, fromdev, todev);
  111.  
  112.     newtCenteredWindow(60, 5, "Loading");
  113.     
  114.     form = newtForm(NULL, NULL, 0);
  115.     
  116.     newtFormAddComponent(form, newtLabel(1, 1, label));
  117.     scale = newtScale(1, 3, 58, blocks / LOAD_BLOCK_COUNT);
  118.     newtFormAddComponent(form, scale);
  119.     newtDrawForm(form);
  120.     newtRefresh();
  121.  
  122.     for (i = 0; i < (blocks / LOAD_BLOCK_COUNT) && !rc; i++) {
  123.     newtScaleSet(scale, i);
  124.     newtRefresh();
  125.  
  126.     if (read(from, buf, sizeof(buf)) != sizeof(buf)) {
  127.         logMessage("error reading from device: %s", strerror(errno));
  128.         rc = 1;
  129.     } else {
  130.         if (write(to, buf, sizeof(buf)) != sizeof(buf)) {
  131.         logMessage("error writing to device: %s", strerror(errno));
  132.         rc = 1;
  133.         }
  134.     }
  135.     }
  136.  
  137.     newtPopWindow();
  138.     newtFormDestroy(form);
  139.     
  140.     close(from);
  141.     close(to);
  142.  
  143.     return rc;
  144. }
  145.  
  146. static int totalMemory(void) {
  147.     int fd;
  148.     int bytesRead;
  149.     char buf[4096];
  150.     char * chptr, * start;
  151.     int total = 0;
  152.  
  153.     fd = open("/proc/meminfo", O_RDONLY);
  154.     if (fd < 0) {
  155.     logMessage("failed to open /proc/meminfo: %s", strerror(errno));
  156.     return 0;
  157.     }
  158.  
  159.     bytesRead = read(fd, buf, sizeof(buf) - 1);
  160.     if (bytesRead < 0) {
  161.     logMessage("failed to read from /proc/meminfo: %s", strerror(errno));
  162.     close(fd);
  163.     return 0;
  164.     }
  165.  
  166.     close(fd);
  167.     buf[bytesRead] = '\0';
  168.  
  169.     chptr = buf;
  170.     while (*chptr && !total) {
  171.     if (*chptr != '\n' || strncmp(chptr + 1, "MemTotal:", 9)) {
  172.         chptr++;
  173.         continue;
  174.     }
  175.  
  176.     start = ++chptr ;
  177.     while (*chptr && *chptr != '\n') chptr++;
  178.  
  179.     *chptr = '\0';
  180.  
  181.     logMessage("found total memory tag: \"%s\"", start);
  182.     
  183.     while (!isdigit(*start) && *start) start++;
  184.     if (!*start) {
  185.         logMessage("no number appears after MemTotal tag");
  186.         return 0;
  187.     }
  188.  
  189.     chptr = start;
  190.     while (*chptr && isdigit(*chptr)) {
  191.         total = (total * 10) + (*chptr - '0');
  192.         chptr++;
  193.     }
  194.     }
  195.  
  196.     logMessage("%d kB are available", total);
  197.  
  198.     return total;
  199. }
  200.  
  201. static int installMethodWindow(struct installMethod ** method) {
  202.     newtComponent form, listbox, okay, text;
  203.     struct installMethod * newMethod;
  204.     newtGrid grid;
  205.     char * reflowedText;
  206.     int i, width, height;
  207.  
  208.     form = newtForm(NULL, NULL, 0);
  209.  
  210.     reflowedText = newtReflowText("What type of media contains the packages "
  211.             "to be installed?", 30, 5, 5, &width, &height);
  212.  
  213.     text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
  214.     newtTextboxSetText(text, reflowedText);
  215.  
  216.     free(reflowedText);
  217.  
  218.     listbox = newtListbox(-1, -1, 0, NEWT_LISTBOX_RETURNEXIT);
  219.  
  220.     for (i = 0; i < numMethods; i++) {
  221.     newtListboxAddEntry(listbox, methods[i].name, methods + i);
  222.     }
  223.  
  224.     okay = newtButton(14, 11, "Ok");
  225.  
  226.     grid = newtCreateGrid(1, 3);
  227.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
  228.             0, 0, 0, 0, 0, 0);
  229.     newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox,
  230.             0, 1, 0, 0, 0, 0);
  231.     newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, okay,
  232.             0, 1, 0, 0, 0, 0);
  233.  
  234.     newtGridWrappedWindow(grid, "Installation Method");
  235.  
  236.     newtFormAddComponents(form, text, listbox, okay, NULL);
  237.  
  238.     newtRunForm(form);
  239.  
  240.     newMethod = newtListboxGetCurrent(listbox);
  241.  
  242.     newtFormDestroy(form);
  243.     newtPopWindow();
  244.  
  245.     *method = newMethod;
  246.  
  247.     return 0;
  248. }
  249.  
  250. int chooseInstallMethod(struct installMethod ** method, struct netConfig * netc,
  251.                struct netInterface * intf, struct driversLoaded ** dl) {
  252.     int rc;
  253.  
  254.     if (kickstart) {
  255.     if (!ksGetCommand(KS_CMD_NFS, NULL, NULL, NULL)) {
  256.         *method = methods + NFS_METHOD_NUM;
  257.         return (*method)->prepareImage((*method), netc, intf, dl);
  258.     } else if (!ksGetCommand(KS_CMD_CDROM, NULL, NULL, NULL)) {
  259.         *method = methods + CDROM_METHOD_NUM;
  260.         return (*method)->prepareImage((*method), netc, intf, dl);
  261.     } else {
  262.         logMessage("No kickstart method was specified.");
  263.         kickstart = 0;
  264.     }
  265.     }
  266.  
  267.     do {
  268.     rc = installMethodWindow(method);
  269.     if (rc) return rc;
  270.  
  271.     if ((*method)->prepareImage) {
  272.         rc = (*method)->prepareImage((*method), netc, intf, dl);
  273.         if (rc == INST_ERROR) return rc;
  274.     }
  275.     } while (rc);
  276.  
  277.     return 0;
  278. }
  279.  
  280. static int nfsGetSetup(char ** hostptr, char ** dirptr) {
  281.     newtComponent form, okay, cancel, answer, text;
  282.     newtComponent siteLabel, dirLabel;
  283.     newtGrid buttons, entryArea, grid;
  284.     struct nfsMountCallbackInfo cbInfo;
  285.     char * message = "Please enter the following information:\n"
  286.              "\n"
  287.              "    o the name or IP number of your NFS server\n"
  288.              "    o the directory on that server containing\n"
  289.              "      Red Hat Linux for your architecture";
  290.  
  291.     if (*hostptr) {
  292.     cbInfo.serverVal = *hostptr;
  293.     cbInfo.netpathVal = *dirptr;
  294.     } else {
  295.     cbInfo.serverVal = "";
  296.     cbInfo.netpathVal = "";
  297.     }
  298.  
  299.     form = newtForm(NULL, NULL, 0);
  300.     buttons = newtButtonBar("Ok", &okay, "Cancel", &cancel, NULL);
  301.  
  302.     text = newtTextbox(-1, -1, 47, 5, NEWT_TEXTBOX_WRAP);
  303.     newtTextboxSetText(text, message);
  304.  
  305.     entryArea = newtCreateGrid(2, 2);
  306.     siteLabel = newtLabel(-1, -1, "NFS server name  :");
  307.     newtGridSetField(entryArea, 0, 0, NEWT_GRID_COMPONENT, siteLabel, 
  308.             0, 0, 0, 0, 0, 0);
  309.     dirLabel = newtLabel(-1, -1, "Red Hat directory:");
  310.     newtGridSetField(entryArea, 0, 1, NEWT_GRID_COMPONENT, dirLabel, 
  311.             0, 0, 0, 0, 0, 0);
  312.  
  313.     cbInfo.server = newtEntry(-1, -1, cbInfo.serverVal, 24, &cbInfo.serverVal, 
  314.                 NEWT_ENTRY_SCROLL);
  315.     newtComponentAddCallback(cbInfo.server, nfsMountCallback, &cbInfo);
  316.     cbInfo.netpath = newtEntry(-1, -1, cbInfo.netpathVal, 24, 
  317.                 &cbInfo.netpathVal, NEWT_ENTRY_SCROLL);
  318.     cbInfo.mntpoint = NULL;
  319.  
  320.     newtGridSetField(entryArea, 1, 0, NEWT_GRID_COMPONENT, cbInfo.server, 
  321.             1, 0, 0, 0, 0, 0);
  322.     newtGridSetField(entryArea, 1, 1, NEWT_GRID_COMPONENT, cbInfo.netpath, 
  323.             1, 0, 0, 0, 0, 0);
  324.  
  325.     grid = newtCreateGrid(1, 3);
  326.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
  327.             0, 0, 0, 0, 0, 0);
  328.     newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, entryArea,
  329.             0, 1, 0, 1, 0, 0);
  330.     newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
  331.             0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  332.  
  333.     newtGridWrappedWindow(grid, "NFS Setup");
  334.  
  335.     newtFormAddComponents(form, text, cbInfo.server, cbInfo.netpath, okay, 
  336.               cancel, dirLabel, siteLabel, NULL);
  337.  
  338.     answer = newtRunForm(form);
  339.     if (answer == cancel) {
  340.     newtFormDestroy(form);
  341.     newtPopWindow();
  342.     
  343.     return INST_CANCEL;
  344.     }
  345.  
  346.     if (*hostptr) free(*hostptr);
  347.     if (*dirptr) free(*dirptr);
  348.     *hostptr = strdup(cbInfo.serverVal);
  349.     *dirptr = strdup(cbInfo.netpathVal);
  350.  
  351.     newtFormDestroy(form);
  352.     newtPopWindow();
  353.  
  354.     return 0;
  355. }
  356.  
  357. static int cdromPrepare(struct installMethod * method, struct netConfig * netc,
  358.                struct netInterface * intf, struct driversLoaded ** dl) {
  359.     char * cddev;
  360.     int rc;
  361.  
  362.     if (!kickstart)
  363.     newtWinMessage("Note", "Ok", 
  364.                 "Insert your Red Hat CD into your CD drive now");
  365.  
  366.     while (1) {
  367.     /* this autoprobes already, so we don't need to do anything special
  368.        for the kickstart :-) */
  369.     rc = setupCDdevice(&cddev, dl);
  370.     if (rc) return rc;
  371.  
  372.     if ((rc = loadFilesystem("iso9660", dl))) return rc;
  373.  
  374.     rc = doMount(cddev, "/tmp/rhimage", "iso9660", 1, 0);
  375.     if (rc) {
  376.         removeCDmodule(dl);
  377.         newtWinMessage("Error", "Ok", 
  378.             "I could not mount a CD on device /dev/%s", cddev);
  379.         continue;
  380.     }
  381.  
  382.     if (access("/tmp/rhimage/RedHat", R_OK)) {
  383.         umount("/tmp/rhimage");
  384.         removeCDmodule(dl);
  385.         newtWinMessage("Error", "Ok", "That CDROM device does not seem "
  386.               "to contain a Red Hat CDROM.");
  387.         continue;
  388.     }
  389.  
  390.     break;
  391.     }
  392.  
  393.     if (!access("/tmp/rhimage/RedHat/instimage/lib", X_OK)) {
  394.     unlink("/tmp/rhimage/RedHat/instimage/lib");
  395.     symlink("/tmp/rhimage/RedHat/instimage/lib", "/lib");
  396.     }
  397.  
  398.     if (!access("/tmp/rhimage/RedHat/instimage/usr/bin", X_OK)) {
  399.         unlink("/tmp/rhimage/RedHat/instimage/usr/bin");
  400.     symlink("/tmp/rhimage/RedHat/instimage/usr/bin", "/usr/bin");
  401.     }
  402.  
  403.     return 0;
  404. }
  405.  
  406. static int nfsPrepare(struct installMethod * method, struct netConfig * netc,
  407.                struct netInterface * intf, struct driversLoaded ** dl) {
  408.     char * host = NULL, * dir = NULL;
  409.     char * buf;
  410.     enum { NFS_STEP_NET, NFS_STEP_INFO, NFS_STEP_MOUNT, NFS_STEP_DONE }
  411.         step = NFS_STEP_NET;
  412.     int rc;
  413.     int ksArgc;
  414.     char ** ksArgv;
  415.     poptContext optCon;
  416.     struct poptOption ksNfsOptions[] = {
  417.         { "server", '\0', POPT_ARG_STRING, &host, 0 },
  418.         { "dir", '\0', POPT_ARG_STRING, &dir, 0 },
  419.         { 0, 0, 0, 0, 0 }
  420.     };
  421.  
  422.  
  423.     if (kickstart) {
  424.     if (!intf->isConfigured || !netc->isConfigured) 
  425.         if (bringUpNetworking(intf, netc, dl)) return INST_ERROR;
  426.  
  427.     ksGetCommand(KS_CMD_NFS, NULL, &ksArgc, &ksArgv);
  428.  
  429.     optCon = poptGetContext(NULL, ksArgc, ksArgv, ksNfsOptions, 0);
  430.  
  431.     if ((rc = poptGetNextOpt(optCon)) < -1) {
  432.         newtWinMessage("nfs command",  "Ok",
  433.                "bad argument to kickstart nfs command %s: %s",
  434.                poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
  435.                poptStrerror(rc));
  436.     }
  437.  
  438.     if (!host || !dir) {
  439.         newtWinMessage("nfs command",  "Ok",
  440.                "nfs command incomplete");
  441.     } else {
  442.         step = NFS_STEP_MOUNT;
  443.     }
  444.     }
  445.  
  446.     while (step != NFS_STEP_DONE) {
  447.     switch (step) {
  448.       case NFS_STEP_NET:
  449.         rc = bringUpNetworking(intf, netc, dl);
  450.         if (rc) return rc;
  451.         step = NFS_STEP_INFO;
  452.         break;
  453.  
  454.       case NFS_STEP_INFO:
  455.         if (!host && getenv("BOOTP_SERVER"))
  456.         host = mygethostbyaddr(getenv("BOOTP_SERVER"));
  457.         if (!dir && getenv("BOOTP_BOOTFILE"))
  458.         dir = strdup(getenv("BOOTP_BOOTFILE"));
  459.  
  460.         rc = nfsGetSetup(&host, &dir);
  461.         if (rc == INST_CANCEL)
  462.         step = NFS_STEP_NET;
  463.         else if (rc == INST_ERROR)
  464.         return INST_ERROR;
  465.         else
  466.         step = NFS_STEP_MOUNT;
  467.         break;
  468.  
  469.       case NFS_STEP_MOUNT:
  470.         if (!strlen(host) || !strlen(dir))
  471.         rc = INST_ERROR;
  472.         else {
  473.         buf = malloc(strlen(host) + strlen(dir) + 10);
  474.         strcpy(buf, host);
  475.         strcat(buf, ":");
  476.         strcat(buf, dir);
  477.  
  478.         if ((rc = loadFilesystem("nfs", dl))) return rc;
  479.  
  480.         rc = doMount(buf, "/tmp/rhimage", "nfs", 1, 0);
  481.         free(buf);
  482.         }
  483.  
  484.         if (rc) {
  485.         step = NFS_STEP_INFO;
  486.         newtWinMessage("Error", "Ok", 
  487.             "I could not mount that directory from the server");
  488.         } else {
  489.             if (access("/tmp/rhimage/RedHat", R_OK)) {
  490.             step = NFS_STEP_INFO;
  491.             newtWinMessage("Error", "Ok", 
  492.                    "That directory does not seem "
  493.                   "to contain a Red Hat installation tree.");
  494.             umount("/tmp/rhimage");
  495.         } else
  496.             step = NFS_STEP_DONE;
  497.         }
  498.  
  499.         break;
  500.  
  501.       case NFS_STEP_DONE:
  502.         break;
  503.     }
  504.     }
  505.  
  506.     if (!kickstart) {
  507.     free(host);
  508.     free(dir);
  509.     }
  510.  
  511.     if (!access("/tmp/rhimage/RedHat/instimage/lib", X_OK)) {
  512.     unlink("/tmp/rhimage/RedHat/instimage/lib");
  513.     symlink("/tmp/rhimage/RedHat/instimage/lib", "/lib");
  514.     }
  515.  
  516.     if (!access("/tmp/rhimage/RedHat/instimage/usr/bin", X_OK)) {
  517.         unlink("/tmp/rhimage/RedHat/instimage/usr/bin");
  518.     symlink("/tmp/rhimage/RedHat/instimage/usr/bin", "/usr/bin");
  519.     }
  520.  
  521.     return 0;
  522. }
  523.  
  524. int floppyRoot(struct installMethod * method, struct netConfig * netc,
  525.                struct netInterface * intf, struct driversLoaded ** dl) { 
  526.     return loadFloppyRoot(method,
  527.         "This install method requires a second disk. Please remove "
  528.         "the boot disk currently in your drive and replace it with "
  529.         "the Red Hat Supplementary Install disk.");
  530. }
  531.  
  532. int loadFloppyRoot(struct installMethod * method, char * message) { 
  533.     newtComponent form, text, okay, cancel, answer;
  534.     static int isMounted = 0;
  535.  
  536.     if (isMounted) return 0;
  537.  
  538.     if (access("/usr/bin/runinstall2", R_OK)) {
  539.     newtCenteredWindow(40, 15, "Second Floppy");
  540.  
  541.     text = newtTextbox(1, 1, 38, 5, NEWT_TEXTBOX_WRAP);
  542.     newtTextboxSetText(text, message);
  543.  
  544.     okay = newtButton(6, 10, "Ok");
  545.     cancel = newtButton(24, 10, "Cancel");
  546.  
  547.     form = newtForm(NULL, NULL, 0);
  548.     newtFormAddComponents(form, text, okay, cancel, NULL);
  549.       
  550.     answer = newtRunForm(form);
  551.  
  552.     newtFormDestroy(form);
  553.     newtPopWindow();
  554.  
  555.     if (answer == cancel) return INST_CANCEL;
  556.  
  557.     if (testing) return 0;
  558.  
  559.     while (doMount("fd0", "/tmp/image", "ext2", 1, 0) ||
  560.            access("/tmp/image/usr/bin/runinstall2", R_OK)) {
  561.         /* in case the mount succeeded */
  562.         umount("/tmp/image");
  563.  
  564.         newtCenteredWindow(40, 15, "Second Floppy");
  565.         text = newtTextbox(1, 1, 38, 5, NEWT_TEXTBOX_WRAP);
  566.  
  567.         newtTextboxSetText(text, 
  568.         "I failed to mount the floppy. Please insert the "
  569.         "Red Hat Supplementary Install disk, or choose "
  570.         "Cancel to pick a different installation process.");
  571.  
  572.         okay = newtButton(6, 10, "Ok");
  573.         cancel = newtButton(24, 10, "Cancel");
  574.  
  575.         form = newtForm(NULL, NULL, 0);
  576.         newtFormAddComponents(form, text, okay, cancel);
  577.       
  578.         answer = newtRunForm(form);
  579.         
  580.         newtFormDestroy(form);
  581.         newtPopWindow();
  582.  
  583.         if (answer == cancel) return INST_CANCEL;
  584.     }
  585.  
  586.     if (totalMemory() > 8000) {
  587.         umount("/tmp/image");
  588.         loadRamdisk("ram2", "fd0", 1440, "Loading supplemental disk...");
  589.         if (doMount("ram2", "/tmp/image", "ext2", 1, 0)) {
  590.         errorWindow("Error mounting ramdisk. This shouldn't "
  591.                 "happen, and I'm rebooting your system now.");
  592.         exit(1);
  593.         }
  594.     }
  595.  
  596.  
  597.     symlink("/tmp/image/lib", "/lib");
  598.     symlink("/tmp/image/etc", "/etc");
  599.     symlink("/tmp/image/usr/bin", "/usr/bin");
  600.     }
  601.  
  602.     isMounted = 1;
  603.  
  604.     return 0;
  605. }
  606.  
  607.