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

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