home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 December / CHIPNET Aralık 1997.iso / linux / redhat / misc / src / install / hd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-11  |  13.6 KB  |  532 lines

  1. #include <ctype.h>
  2. #include <fcntl.h>
  3. #include <linux/hdreg.h>
  4. #include <linux/fs.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/stat.h>
  10. #include <sys/sysmacros.h>
  11. #include <sys/wait.h>
  12. #include <unistd.h>
  13.  
  14. #include "hd.h"
  15. #include "install.h"
  16. #include "log.h"
  17. #include "newt.h"
  18. #include "run.h"
  19. #include "scsi.h"
  20. #include "windows.h"
  21.  
  22. extern int testing;
  23.  
  24. struct fdiskTag {
  25.     int tag;
  26.     int type;
  27. } ;
  28.  
  29. #if defined(__sparc__)
  30. const struct fdiskTag fdiskTags[] =  {
  31.     { 0x05,    PART_IGNORE },
  32.     { 0x82,    PART_SWAP },
  33.     { 0x83,    PART_EXT2 },
  34.     { 0, 0 },
  35. };
  36. #else
  37. const struct fdiskTag fdiskTags[] =  {
  38.     { 0x01,    PART_DOS },
  39.     { 0x04,    PART_DOS },
  40.     { 0x05,    PART_IGNORE },
  41.     { 0x06,    PART_DOS },
  42.     { 0x07,    PART_HPFS },
  43.     { 0x82,    PART_SWAP },
  44.     { 0x83,    PART_EXT2 },
  45.     { 0, 0 },
  46. };
  47. #endif
  48.  
  49. struct hd {
  50.     char * device;
  51.     int major, minor;
  52. };
  53.  
  54. struct hd static possibleDrives[] = {
  55. #ifndef __sparc__
  56.     { "hda",    3,    0 },
  57.     { "hdb",    3,    64 },
  58.     { "hdc",    22,    0 },
  59.     { "hdd",    22,    64 },
  60.     { "hde",    33,    0 },
  61.     { "hdf",    33,    64 },
  62.     { "hdg",    34,    0 },
  63.     { "hdh",    34,    64 },
  64. #endif
  65.     { "sda",    8,    0 },
  66.     { "sdb",    8,    16 },
  67.     { "sdc",    8,    32 },
  68.     { "sdd",    8,    48 },
  69.     { "sde",    8,    64 },
  70.     { "sdf",    8,    80 },
  71.     { "sdg",    8,    96 },
  72.     { "sdh",    8,    112 },
  73.  
  74. }; 
  75.  
  76. static void parseLabelLine(char * device, char * start, int * numPartitions, 
  77.                struct partition partitions[15]) {
  78.     char * str = start;
  79.     char * chptr;
  80.     char devbuf[2];
  81.  
  82.     if (*str++ != ' ') return;
  83.     if (*str++ != ' ') return;
  84.  
  85.     if (*str < 'a' || *str > 'h') return;
  86.     if (*(str + 1) != ':') return;
  87.  
  88.     strcpy(partitions[*numPartitions].device, device);
  89.     devbuf[0] = *str - 'a' + '1';
  90.     devbuf[1] = '\0';
  91.     strcat(partitions[*numPartitions].device, devbuf);
  92.     str += 2;
  93.  
  94.     while (*str && isspace(*str)) str++;
  95.     if (!*str) return;
  96.  
  97.     partitions[*numPartitions].size = strtol(str, &chptr, 10);
  98.     partitions[*numPartitions].size /= 2;    /* we want 1k blocks */
  99.     if (!chptr || !isspace(*chptr)) return;
  100.     str = chptr;
  101.  
  102.     while (isspace(*str)) str++;
  103.     if (!*str) return;
  104.  
  105.     partitions[*numPartitions].begin = strtol(str, &chptr, 10);
  106.     if (!chptr || !isspace(*chptr)) return;
  107.     str = chptr;
  108.  
  109.     partitions[*numPartitions].end = partitions[*numPartitions].size * 2 +
  110.                     partitions[*numPartitions].begin;
  111.  
  112.     while (isspace(*str)) str++;
  113.     if (!*str) return;
  114.  
  115.     if (!strncmp(str, "ext2", 4)) {
  116.     partitions[*numPartitions].type = PART_EXT2;
  117.     strcpy(partitions[*numPartitions].tagName, "Linux native");
  118.     } else if (!strncmp(str, "swap", 4)) {
  119.     partitions[*numPartitions].type = PART_SWAP;
  120.     strcpy(partitions[*numPartitions].tagName, "Linux swap");
  121.     } else {
  122.     partitions[*numPartitions].type = PART_OTHER;
  123.     strcpy(partitions[*numPartitions].tagName, "Other");
  124.     }
  125.     
  126.     partitions[*numPartitions].bootLabel = NULL;
  127.  
  128.     logMessage("found partition %s", partitions[*numPartitions].device);
  129.  
  130.     (*numPartitions)++;
  131. }
  132.  
  133. static void parseFdiskLine(char * device, char * start, int * numPartitions, 
  134.                struct partition partitions[15]) {
  135.     int tag, i;
  136.     char * str = start;
  137.     char * chptr;
  138.  
  139.     if (*str != '/') return;
  140.  
  141.     if (strlen(str) < 60) return;
  142.  
  143.     /* grab the partition number */
  144.     str += 8;
  145.     chptr = str;
  146.     
  147.     if (!isdigit(*chptr)) return;
  148.     while (*chptr && isdigit(*chptr)) chptr++;
  149.     if (!*chptr) return;
  150.  
  151.     *chptr = '\0';
  152.     strcpy(partitions[*numPartitions].device, device);
  153.     strcat(partitions[*numPartitions].device, str);
  154.     str = chptr + 1;
  155.  
  156.     /* go to the "Begin" field, skipping the '*' which marks a bootable
  157.        partition and the 'u|r' fields which can occur on a Sun disklabel */
  158.     while (*str && (isspace(*str) || *str == '*' || *str == 'u' ||
  159.         *str == 'r')) str++;
  160.     if (!*str) return;
  161.  
  162.     /* skip the Begin: field (but make sure it's a number */
  163.     if (!isdigit(*str)) return;
  164.     while (isdigit(*str)) str++;
  165.     if (!*str || !isspace(*str)) return;
  166.  
  167.     /* go to the first digit in the "Start" field */
  168.     while (isspace(*str)) str++;
  169.     if (!*str) return;
  170.  
  171.     partitions[*numPartitions].begin = strtol(str, &chptr, 10);
  172.     if (!chptr || !isspace(*chptr)) return;
  173.     str = chptr;
  174.  
  175.     /* go to the first digit in the "End" field */
  176.     while (isspace(*str)) str++;
  177.     if (!*str) return;
  178.  
  179.     partitions[*numPartitions].end = strtol(str, &chptr, 10);
  180.     if (!chptr || !isspace(*chptr)) return;
  181.     str = chptr;
  182.  
  183.     /* go to the first digit in the "Size" field */
  184.     while (isspace(*str)) str++;
  185.     if (!*str) return;
  186.  
  187.     partitions[*numPartitions].size = strtol(str, &chptr, 10);
  188.     if (!chptr || (*chptr != '-' && *chptr != '+' && !isspace(*chptr)))
  189.     return;
  190.  
  191.     str = chptr + 1;
  192.  
  193.     /* go to the first digit in the "Tag" field */
  194.     while (isspace(*str)) str++;
  195.     if (!*str) return;
  196.     tag = strtol(str, &chptr, 16);
  197.  
  198.     partitions[*numPartitions].type = PART_OTHER;
  199.     for (i = 0; fdiskTags[i].tag; i++) {
  200.     if (fdiskTags[i].tag == tag) {
  201.         partitions[*numPartitions].type = fdiskTags[i].type;
  202.         break;
  203.     }
  204.     }
  205.     
  206.     str = chptr;
  207.     while (isspace(*str)) str++;
  208.     if (!*str) return;
  209.  
  210.     strcpy(partitions[*numPartitions].tagName, str);
  211.     partitions[*numPartitions].bootLabel = NULL;
  212.  
  213.     logMessage("found partition %s", partitions[*numPartitions].device);
  214.  
  215.     (*numPartitions)++;
  216. }
  217.  
  218. static int findPartitions(struct hd hd, int * numPartitions, 
  219.               struct partition partitions[15]) {
  220.     char devBuf[20];
  221.     int fd;
  222.     char * fdiskOutput;
  223.     char * fdiskArgs[] = { NULL, NULL, NULL };
  224.     char * start, * end;
  225.     int oldTesting;
  226.     int len;
  227.     char * cmd;
  228.     struct hd_geometry geo;
  229.     int labelMode = 0;
  230.     #if defined(__alpha__)
  231.     unsigned short magic;
  232.     unsigned int fdiskMagic = 0xAA55;
  233.     #endif
  234.  
  235.     if (testing)
  236.     cmd = "/sbin/fdisk";
  237.     else
  238.     cmd = "/usr/bin/fdisk";
  239.  
  240.     fdiskArgs[0] = cmd;
  241.  
  242.     *numPartitions = 0;
  243.  
  244.     /* don't bother with any of this if the main device doesn't exist 
  245.        or doesn't look like a hard drive */
  246.     sprintf(devBuf, "/tmp/%s", hd.device);
  247.     mknod(devBuf, S_IFBLK | 0600, makedev(hd.major, hd.minor));
  248.     fd = open(devBuf, O_RDONLY);
  249.     if (fd < 0) {
  250.     unlink(devBuf);
  251.     return 0;
  252.     }
  253.  
  254.     /* make sure this isn't an IDE CD or tape drive */
  255.     if (ioctl(fd, HDIO_GETGEO, &geo)) {
  256.     logMessage("/dev/%s doesn't look like a hard drive", hd.device);
  257.     unlink(devBuf);
  258.     close(fd);
  259.     return 0;
  260.     }
  261.  
  262.     #if defined(__alpha__)
  263.     /* is this a labeled disk? */
  264.     /* This test used to just look for the disklabel magic, but that 
  265.        got left around on fdisks drives much of the time. This check
  266.        seems more reliable */
  267.     lseek(fd, 510, SEEK_SET);
  268.     if (read(fd, &magic, sizeof(magic)) == sizeof(magic))
  269.         labelMode = (magic != fdiskMagic);
  270.  
  271.     if (labelMode) 
  272.         logMessage("/dev/%s is disklabeled", hd.device);
  273.     else
  274.         logMessage("/dev/%s is fdisked", hd.device);
  275.     #endif
  276.  
  277.     close(fd);
  278.  
  279.     oldTesting = testing;
  280.     testing = 0;
  281.     fdiskArgs[1] = devBuf;
  282.     if (labelMode)
  283.     runProgramIO(RUN_NOLOG, cmd, fdiskArgs, "b\np\nq\n", &fdiskOutput);
  284.     else
  285.     runProgramIO(RUN_NOLOG, cmd, fdiskArgs, "p\nq\n", &fdiskOutput);
  286.     unlink(devBuf);
  287.     testing = oldTesting;
  288.  
  289.     start = fdiskOutput;
  290.     len = strlen(start);
  291.     while (((start - fdiskOutput) < len) && (end = strchr(start, '\n'))) {
  292.     *end = '\0';
  293.     if (labelMode)
  294.         parseLabelLine(hd.device, start, numPartitions, partitions);
  295.     else
  296.         parseFdiskLine(hd.device, start, numPartitions, partitions);
  297.     
  298.     start = end + 1;
  299.     }
  300.     free(fdiskOutput);
  301.  
  302.     return 0;
  303. }
  304.  
  305. int findAllPartitions(struct partitionTable * table) {
  306.     int numPartitions;
  307.     int i;
  308.     struct partition parts[16];
  309.     struct partition * allParts = NULL;
  310.     int numAllParts = 0;
  311.  
  312.     winStatus(30, 3, "Hard Drives", "Scanning hard drives...");
  313.  
  314.     for (i = 0; i < (sizeof(possibleDrives) / sizeof(*possibleDrives)); i++) {
  315.     findPartitions(possibleDrives[i], &numPartitions, parts);
  316.     if (!numPartitions) continue;
  317.     
  318.     if (!numAllParts) {
  319.         numAllParts = numPartitions;
  320.         allParts = malloc(sizeof(*allParts) * numAllParts);
  321.         memcpy(allParts, parts, sizeof(*allParts) * numAllParts);
  322.     } else {
  323.         allParts = realloc(allParts, sizeof(*allParts) * 
  324.                 (numAllParts + numPartitions));
  325.         memcpy(allParts + numAllParts, parts, 
  326.            sizeof(*allParts) * numPartitions);
  327.         numAllParts += numPartitions;
  328.     }
  329.     }
  330.  
  331.     table->count = numAllParts;
  332.     table->parts = allParts;
  333.  
  334.     newtPopWindow();
  335.  
  336.     return 0;
  337. }
  338.  
  339. int partitionDrives(void) {
  340.     int drivesPresent[sizeof(possibleDrives) / sizeof(*possibleDrives)];
  341.     int numDrivesPresent = 0;
  342.     int childpid;
  343.     int i, fd, rc;
  344.     int haveEdited = 0;
  345.     char devBuf[100], idBuf[3];
  346.     newtComponent cancel, done, edit, text, listbox, f, answer, okay, form;
  347.     struct hd_geometry geo;
  348.     struct hd * currhd;
  349.     char * cmd;
  350.     int status;
  351.     struct scsiDeviceInfo * sdi, * thissd;
  352.     int reboot = 0;
  353.     struct hd_driveid ideids[sizeof(possibleDrives) / sizeof(*possibleDrives)];
  354.  
  355.     if (testing)
  356.     cmd = "/sbin/fdisk";
  357.     else
  358.     cmd = "/usr/bin/fdisk";
  359.  
  360.     for (i = 0; i < sizeof(possibleDrives) / sizeof(*possibleDrives); i++) {
  361.     sprintf(devBuf, "/tmp/%s", possibleDrives[i].device);
  362.     mknod(devBuf, S_IFBLK | 0600, 
  363.             makedev(possibleDrives[i].major, possibleDrives[i].minor));
  364.     fd = open(devBuf, O_RDONLY);
  365.     unlink(devBuf);
  366.     if (fd < 0) {
  367.         continue;
  368.     }
  369.  
  370.     logMessage("successfully opened: %s", devBuf);
  371.  
  372.     if (possibleDrives[i].device[0] == 'h') {
  373.         /* make sure this isn't an IDE CD or tape drive */
  374.         if (ioctl(fd, HDIO_GETGEO, &geo)) {
  375.         logMessage("\tHDIO_GETGEO ioctl failed - probably cd or tape");
  376.         close(fd);
  377.         continue;
  378.         } else {
  379.         if (ioctl(fd, HDIO_GET_IDENTITY, &ideids[numDrivesPresent])) {
  380.             ideids[numDrivesPresent].model[0] = '\0';
  381.         }
  382.         }
  383.     }
  384.  
  385.     close(fd);
  386.  
  387.     drivesPresent[numDrivesPresent++] = i;
  388.     }
  389.  
  390.     if (!numDrivesPresent) {
  391.     newtOpenWindow(18, 6, 44, 11, "Setup Swap");
  392.     text = newtTextbox(1, 1, 42, 4, NEWT_TEXTBOX_WRAP);
  393.     newtTextboxSetText(text, "You don't have any hard drives available! "
  394.                  "You probably forgot to configure a SCSI "
  395.                  "controller.");
  396.     
  397.     okay = newtButton(17, 7, "Ok");
  398.  
  399.     form = newtForm(NULL, NULL, 0);
  400.     newtFormAddComponents(form, text, okay, NULL);
  401.     
  402.     newtRunForm(form);
  403.     newtFormDestroy(form);
  404.     newtPopWindow();
  405.  
  406.     return INST_ERROR;
  407.     }
  408.  
  409.     if (scsiDeviceAvailable()) {
  410.         if ((rc = scsiGetDevices(&sdi))) return rc;
  411.     } else {
  412.     sdi = NULL;
  413.     }
  414.  
  415.     newtOpenWindow(10, 3, 60, 17, "Partition Disks");
  416.     text = newtTextbox(1, 1, 56, 5, NEWT_TEXTBOX_WRAP);
  417. #ifdef __i386__
  418.     newtTextboxSetText(text, 
  419.             "To install Red Hat Linux, you must have at least "
  420.             "one parition of 50 MB dedicated to Linux. We suggest "
  421.             "placing that partition on one of the first two hard "
  422.             "drives in your system so you can boot into Linux "
  423.             "with LILO.");
  424. #else
  425.     newtTextboxSetText(text, 
  426.             "To install Red Hat Linux, you must have at least "
  427.             "one parition of 50 MB dedicated to Linux.");
  428. #endif
  429.     
  430.     listbox = newtListbox(10, 7, numDrivesPresent < 5 ? numDrivesPresent : 5,
  431.               (numDrivesPresent <= 5 ? NEWT_FLAG_NOSCROLL : 0) |
  432.                   NEWT_LISTBOX_RETURNEXIT);
  433.     
  434.     for (i = 0; i < numDrivesPresent; i++) {
  435.     sprintf(devBuf, "/dev/%s", possibleDrives[drivesPresent[i]].device);
  436.  
  437.     if (sdi && !strncmp(possibleDrives[drivesPresent[i]].device, "sd", 2))
  438.     {
  439.         thissd = sdi;
  440.         while (thissd->info &&
  441.            strcmp(thissd->deviceName, 
  442.               possibleDrives[drivesPresent[i]].device)) thissd++;
  443.         if (thissd->info) {
  444.         sprintf(idBuf, "%d", thissd->id);
  445.         strcat(devBuf, " - SCSI ID ");
  446.         strcat(devBuf, idBuf);
  447.         strcat(devBuf, " ");
  448.         strcat(devBuf, thissd->info);
  449.         } 
  450.     } else if (ideids[i].model[0]) {
  451.         strcat(devBuf, " - Model ");
  452.         strcat(devBuf, ideids[i].model);
  453.     }
  454.  
  455.     newtListboxAddEntry(listbox, devBuf, possibleDrives + drivesPresent[i]);
  456.     }
  457.  
  458.     done = newtButton(7, 13, "Done");
  459.     edit = newtButton(24, 13, "Edit");
  460.     cancel = newtButton(41, 13, "Cancel");
  461.  
  462.     f = newtForm(NULL, NULL, 0);
  463.     newtFormAddComponents(f, text, listbox, done, edit, cancel, NULL);
  464.     newtFormSetCurrent(f, done);
  465.   
  466.     do {
  467.     answer = newtRunForm(f);
  468.     
  469.     if (answer == edit || answer == listbox) {
  470.         haveEdited = 1;
  471.         currhd = newtListboxGetCurrent(listbox);
  472.  
  473.         sprintf(devBuf, "/tmp/%s", currhd->device);
  474.         mknod(devBuf, S_IFBLK | 0600, 
  475.             makedev(currhd->major, currhd->minor));
  476.  
  477.         newtPopWindow();
  478.         newtSuspend();
  479.         for (i = 0; i < 25; i++) puts("");
  480.         printf("This is the fdisk program for partitioning your drive. It "
  481.            "is running\non /dev/%s.\n\n", currhd->device);
  482.  
  483.         logMessage("running fdisk on %s", devBuf);
  484.         
  485.         if (!(childpid = fork())) {
  486.         execl(cmd, cmd, devBuf, NULL);
  487.          return -1;
  488.         }
  489.  
  490.         waitpid(childpid, &status, 0);
  491.  
  492.         newtResume();
  493.         newtOpenWindow(10, 3, 60, 17, "Partition Disks");
  494.     }
  495.     } while (answer != done && answer != cancel && answer != f);
  496.  
  497.     newtFormDestroy(f);
  498.     newtPopWindow();
  499.  
  500.     if (haveEdited) {
  501.     for (i = 0; i < numDrivesPresent; i++) {
  502.         sprintf(devBuf, "/tmp/%s", possibleDrives[drivesPresent[i]].device);
  503.         mknod(devBuf, S_IFBLK | 0600, 
  504.             makedev(possibleDrives[drivesPresent[i]].major, 
  505.                 possibleDrives[drivesPresent[i]].minor)); 
  506.         fd = open(devBuf, O_RDONLY);
  507.         unlink(devBuf);
  508.         if (fd < 0) reboot = 1;
  509.  
  510.         if (ioctl(fd, BLKRRPART, 0)) reboot = 1;
  511.         close(fd);
  512.     }
  513.     }
  514.  
  515.     if (reboot) {
  516.     winMessage(14, 6, 52, 12, "Reboot Needed",
  517.             "The kernel is unable to read your new partitioning "
  518.             "information, probably because you modified extended "
  519.             "partitions. While this is not critical, you must "
  520.             "reboot your machine before proceeding. Insert the "
  521.             "Red Hat boot disk now and press Return to reboot "
  522.             "your system.");
  523.     newtFinished();
  524.     exit(0);
  525.     }
  526.  
  527.     if (answer == cancel)
  528.     return INST_CANCEL;
  529.  
  530.     return 0;
  531. }
  532.