home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / mkswap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-11  |  10.8 KB  |  474 lines

  1. /*
  2.  * mkswap.c - set up a linux swap device
  3.  *
  4.  * (C) 1991 Linus Torvalds. This file may be redistributed as per
  5.  * the Linux copyright.
  6.  *
  7.  * (C) 1996 Red Hat Software - Modified by Erik Troan for Red Hat Software 
  8.  *     still GPLed, of course
  9.  */
  10.  
  11. /*
  12.  * 20.12.91  -    time began. Got VM working yesterday by doing this by hand.
  13.  *
  14.  * Usuage: mkswap [-c] device [size-in-blocks]
  15.  *
  16.  *    -c for readablility checking (use it unless you are SURE!)
  17.  *
  18.  * The device may be a block device or a image of one, but this isn't
  19.  * enforced (but it's not much fun on a character device :-).
  20.  *
  21.  * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
  22.  * size-in-blocks parameter optional added Wed Feb  8 10:33:43 1995.
  23.  */
  24.  
  25. #include <errno.h>
  26. #include <fcntl.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/stat.h>
  32. #include <sys/swap.h>
  33. #include <unistd.h>
  34.  
  35. #include <asm/page.h>
  36.  
  37. #define BLKGETSIZE 0x1260
  38.  
  39. #include "devices.h"
  40. #include "install.h"
  41. #include "intl.h"
  42. #include "log.h"
  43. #include "mkswap.h"
  44. #include "newt.h"
  45. #include "windows.h"
  46.  
  47. #ifndef __linux__
  48. # define volatile
  49. #endif
  50.  
  51. #define TEST_BUFFER_PAGES 8
  52.  
  53. static int DEV = -1;
  54. static long PAGES = 0;
  55. static int check = 0;
  56. static int badpages = 0;
  57.  
  58. int canEnableSwap = 1;
  59.  
  60. static long bit_test_and_set (unsigned int *addr, unsigned int nr)
  61. {
  62.     unsigned int r, m;
  63.  
  64.     addr += nr / (8 * sizeof(int));
  65.     r = *addr;
  66.     m = 1 << (nr & (8 * sizeof(int) - 1));
  67.     *addr = r | m;
  68.     return (r & m) != 0;
  69. }
  70.  
  71. static int bit_test_and_clear (unsigned int *addr, unsigned int nr)
  72. {
  73.     unsigned int r, m;
  74.  
  75.     addr += nr / (8 * sizeof(int));
  76.     r = *addr;
  77.     m = 1 << (nr & (8 * sizeof(int) - 1));
  78.     *addr = r & ~m;
  79.     return (r & m) != 0;
  80. }
  81.  
  82. static int check_blocks(int * signature_page, char * file)
  83. {
  84.     unsigned int current_page;
  85.     int do_seek = 1;
  86.     static char buffer[PAGE_SIZE];
  87.     newtComponent form = NULL, scale = NULL;
  88.     newtGrid grid;
  89.  
  90.     if (check) {
  91.         form = newtForm(NULL, NULL, 0);
  92.  
  93.         sprintf(buffer, _("Formatting swap space on device %s..."), 
  94.             file);
  95.         scale = newtScale(-1, -1, 58, PAGES);
  96.  
  97.         grid = newtCreateGrid(1, 2);
  98.         newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT,
  99.                      newtLabel(-1, -1, buffer),
  100.                  0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  101.         newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, scale,
  102.                  0, 1, 0, 0, 0, 0);
  103.         newtGridAddComponentsToForm(grid, form, 1);
  104.  
  105.         newtGridWrappedWindow(grid, _("Formatting"));
  106.         
  107.         newtDrawForm(form);
  108.         newtRefresh();
  109.     }
  110.  
  111.     current_page = 0;
  112.     while (current_page < PAGES) {
  113.         if (!check) {
  114.             bit_test_and_set(signature_page,current_page++);
  115.             continue;
  116.         }
  117.  
  118.         newtScaleSet(scale, current_page);
  119.         newtRefresh();
  120.  
  121.         if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) !=
  122.         current_page*PAGE_SIZE) {
  123.             logMessage("mkswap: seek failed in check_blocks");
  124.             return INST_ERROR;
  125.         }
  126.         if ((do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE)))) {
  127.             bit_test_and_clear(signature_page,current_page++);
  128.             badpages++;
  129.             continue;
  130.         }
  131.         bit_test_and_set(signature_page,current_page++);
  132.     }
  133.     if (badpages)
  134.         logMessage("\t%d bad page%s\n",badpages,(badpages>1)?"s":"");
  135.  
  136.     if (check) {
  137.         newtPopWindow();
  138.         newtFormDestroy(form);
  139.     }
  140.  
  141.     return 0;
  142. }
  143.  
  144. static long valid_offset (int fd, int offset)
  145. {
  146.     char ch;
  147.  
  148.     if (lseek (fd, offset, 0) < 0)
  149.         return 0;
  150.     if (read (fd, &ch, 1) < 1)
  151.         return 0;
  152.     return 1;
  153. }
  154.  
  155. static int count_blocks (int fd)
  156. {
  157.     int high, low;
  158.  
  159.     low = 0;
  160.     for (high = 1; valid_offset (fd, high); high *= 2)
  161.         low = high;
  162.     while (low < high - 1)
  163.     {
  164.         const int mid = (low + high) / 2;
  165.  
  166.         if (valid_offset (fd, mid))
  167.             low = mid;
  168.         else
  169.             high = mid;
  170.     }
  171.     valid_offset (fd, 0);
  172.     return (low + 1);
  173. }
  174.  
  175. static int get_size(const char  *file, long int * sizeptr)
  176. {
  177.     int    fd;
  178.     int    size;
  179.  
  180.     fd = open(file, O_RDWR);
  181.     if (fd < 0) {
  182.         logMessage("mkswap: failed to get size of device %s", file);
  183.         return INST_ERROR;
  184.     }
  185.     if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
  186.         close(fd);
  187.         *sizeptr = size * 512;
  188.         return 0;
  189.     }
  190.         
  191.     *sizeptr = count_blocks(fd);
  192.     close(fd);
  193.  
  194.     return 0;;
  195. }
  196.  
  197. int enableswap(char * device_name, int size, int checkBlocks) {
  198.     struct stat statbuf;
  199.     int goodpages;
  200.     int signature_page[PAGE_SIZE/sizeof(int)];
  201.     char devicefile[100];
  202.  
  203.     check = checkBlocks;
  204.  
  205.     if (testing) {
  206.         return 0;
  207.     }
  208.  
  209.     memset(signature_page,0,PAGE_SIZE);
  210.  
  211.     if (*device_name == '/') {
  212.         strcpy(devicefile, device_name);
  213.     } else {
  214.         sprintf(devicefile, "/tmp/%s", device_name);
  215.         if (devMakeInode(device_name, devicefile)) {
  216.         return INST_ERROR;
  217.         }
  218.     }
  219.  
  220.     if (size)
  221.         PAGES = size;
  222.     else {
  223.         if (get_size(devicefile, &PAGES)) {
  224.             unlink(devicefile);
  225.             return INST_ERROR;
  226.         }
  227.  
  228.         PAGES = PAGES / PAGE_SIZE;
  229.     }
  230.  
  231.     if (PAGES<10) {
  232.         logMessage("mkswap: error: swap area needs to be at least "
  233.                 "%ldkB", 10 * PAGE_SIZE / 1024);
  234.         unlink(devicefile);
  235.         return INST_ERROR;
  236.     }
  237.  
  238.     if (PAGES > 8 * (PAGE_SIZE - 10)) {
  239.             PAGES = 8 * (PAGE_SIZE - 10);
  240.         logMessage("mkswap: warning: truncating %s swap to %ldkB",
  241.             device_name, PAGES * PAGE_SIZE / 1024);
  242.     }
  243.  
  244.     DEV = open(devicefile,O_RDWR);
  245.     if (DEV < 0 || fstat(DEV, &statbuf) < 0) {
  246.         logMessage("mkswap: failed to open device: %s\n", device_name);
  247.         unlink(devicefile);
  248.         return INST_ERROR;
  249.     }
  250.     if (!S_ISBLK(statbuf.st_mode))
  251.         check=0;
  252.     else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) {
  253.         logMessage("mkswap: will not try to make swapdevice on '%s'");
  254.         close(DEV);
  255.         unlink(devicefile);
  256.         return INST_ERROR;
  257.     }
  258.  
  259.     if (check_blocks(signature_page, device_name)) {
  260.         close(DEV);
  261.         unlink(devicefile);
  262.         newtPopWindow();
  263.         return INST_ERROR;
  264.     }
  265.  
  266.     if (!bit_test_and_clear(signature_page,0)) {
  267.         logMessage("mkswap: first page unreadable");
  268.         close(DEV);
  269.         unlink(devicefile);
  270.         newtPopWindow();
  271.         return INST_ERROR;
  272.     }
  273.  
  274.     goodpages = PAGES - badpages - 1;
  275.     if (goodpages <= 0) {
  276.         logMessage("mkswap: unable to set up swap-space: unreadable");
  277.         close(DEV);
  278.         unlink(devicefile);
  279.         newtPopWindow();
  280.         return INST_ERROR;
  281.     }
  282.  
  283.     logMessage("setting up swapspace, device = %s, size = %d bytes",
  284.         device_name, goodpages*PAGE_SIZE);
  285.     strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10);
  286.     if (lseek(DEV, 0, SEEK_SET)) {
  287.         logMessage("mkswap: unable to rewind swap-device");
  288.         close(DEV);
  289.         unlink(devicefile);
  290.         newtPopWindow();
  291.         return INST_ERROR;
  292.     }
  293.  
  294.     if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) {
  295.         logMessage("mkswap: unable to write signature page");
  296.         close(DEV);
  297.         unlink(devicefile);
  298.         newtPopWindow();
  299.         return INST_ERROR;
  300.     }
  301.  
  302.     close(DEV);
  303.  
  304.     if (swapon(devicefile, 0)) {
  305.         logMessage("mkswap: swapon() failed: %s\n", strerror(errno));
  306.     }
  307.  
  308.     if (*device_name != '/') 
  309.         unlink(devicefile);
  310.  
  311.     return 0;
  312. }
  313.  
  314. int activeSwapSpace(struct partitionTable * table, struct fstab * finalFstab,
  315.             int forceFormat) {
  316.     newtComponent form, checkList, okay, cancel, sb, text, answer, label;
  317.     newtComponent check, checkbox, blank;
  318.     newtGrid grid, subgrid, buttons, checkgrid;
  319.     char * states;
  320.     char buf[80];
  321.     int i, j, rc, row;
  322.     struct fstabEntry entry;
  323.     struct fstabEntry ** entries;
  324.     struct fstab fstab;
  325.     static int chkBadBlocks = 0;
  326.     char doCheck = ' ';
  327.  
  328.     if (!canEnableSwap) return INST_NOP;
  329.  
  330.     fstab = copyFstab(finalFstab);    
  331.  
  332.     form = newtForm(NULL, NULL, 0);
  333.  
  334.     for (i = j = 0; i < table->count; i++)
  335.     if (table->parts[i].type == PART_SWAP)
  336.         j++;
  337.  
  338.     if (!j) {
  339.     rc = newtWinChoice(_("No Swap Space"), _("Repartition"), _("Continue"),
  340.                _("You don't have any swap space defined. Would "
  341.                 "you like to continue, or repartition your disk?"));
  342.     if (rc != 2)
  343.        return INST_CANCEL;
  344.     
  345.     return 0;
  346.     }
  347.  
  348.     if (!forceFormat) {
  349.     if (j > 3) {
  350.         sb = newtVerticalScrollbar(47, 7, 3, 9, 10);
  351.     } else
  352.         sb = NULL;
  353.  
  354.     checkList = newtForm(sb, NULL, 0);
  355.     if (sb) newtFormSetHeight(checkList, j > 3);
  356.  
  357.     text = newtTextboxReflowed(-1, -1, _("What partitions would you like "
  358.                "to use for swap space? This will destroy any "
  359.                "information already on the partition."),
  360.                 52, 0, 15, 0);
  361.  
  362.     label = newtLabel(-1, -1, 
  363.             "    Device       Size (k)");
  364.  
  365.     states = alloca(sizeof(char) * table->count);
  366.     entries = alloca(sizeof(*entries) * table->count);
  367.  
  368.     for (i = 0, row = 0; i < table->count; i++) {
  369.         if (table->parts[i].type != PART_SWAP) continue;
  370.  
  371.         for (j = 0; j < fstab.numEntries; j++) 
  372.         if (!strcmp(table->parts[i].device, fstab.entries[j].device))
  373.             break;
  374.  
  375.         if ((j < fstab.numEntries && fstab.entries[j].mntpoint) || 
  376.         !testing)
  377.         states[i] = '*';
  378.         else
  379.         states[i] = ' ';
  380.  
  381.         if (j < fstab.numEntries) 
  382.         entries[i] = fstab.entries + j;
  383.         else
  384.         entries[i] = NULL;
  385.  
  386.         sprintf(buf, "/dev/%-5s  %9d", table->parts[i].device, 
  387.             table->parts[i].size);
  388.         check = newtCheckbox(-1, row++, buf, states[i], NULL, 
  389.                      &states[i]);
  390.         newtFormAddComponent(checkList, check);
  391.     }
  392.  
  393.     if (row > 3) {
  394.         blank = newtForm(NULL, NULL, 0);
  395.         newtFormSetWidth(blank, 2);
  396.         newtFormSetHeight(blank, 3);
  397.         newtFormSetBackground(blank, NEWT_COLORSET_CHECKBOX);
  398.         checkgrid = newtGridHCloseStacked(
  399.                 NEWT_GRID_COMPONENT, checkList,
  400.                 NEWT_GRID_COMPONENT, blank,
  401.                 NEWT_GRID_COMPONENT, sb, NULL);
  402.     } else {
  403.         checkgrid = newtGridHCloseStacked(NEWT_GRID_COMPONENT, checkList,
  404.                           NULL);
  405.     }
  406.  
  407.     checkbox = newtCheckbox(-1, -1, _("Check for bad blocks during format"),
  408.                     chkBadBlocks ? '*' : ' ', NULL, &doCheck);
  409.  
  410.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  411.     subgrid = newtCreateGrid(1, 3);
  412.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT, label,
  413.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  414.     newtGridSetField(subgrid, 0, 1, NEWT_GRID_SUBGRID, checkgrid,
  415.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  416.     newtGridSetField(subgrid, 0, 2, NEWT_GRID_COMPONENT, checkbox,
  417.              0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
  418.      grid = newtGridBasicWindow(text, subgrid, buttons);
  419.     newtGridAddComponentsToForm(grid, form, 1);
  420.     newtGridWrappedWindow(grid, _("Active Swap Space"));
  421.     newtGridFree(grid, 1);
  422.  
  423.     answer = newtRunForm(form);
  424.  
  425.     newtFormDestroy(form);
  426.     newtPopWindow();
  427.  
  428.     chkBadBlocks = (doCheck != ' ');
  429.  
  430.     if (answer == cancel) {
  431.         freeFstab(fstab);
  432.         return INST_CANCEL;
  433.     }
  434.     }
  435.  
  436.     for (i = 0; i < table->count; i++) {
  437.     if (table->parts[i].type != PART_SWAP) continue;
  438.  
  439.         if (forceFormat || states[i] != ' ') {
  440.         if (!forceFormat && entries[i])
  441.         entries[i]->mntpoint = strdup("swap");
  442.         else {
  443.         initFstabEntry(&entry);
  444.         entry.device = strdup(table->parts[i].device);
  445.         entry.size = table->parts[i].size;
  446.         entry.type = table->parts[i].type;
  447.         entry.tagName = table->parts[i].tagName;
  448.         entry.mntpoint = strdup("swap");
  449.  
  450.         addFstabEntry(&fstab, entry);
  451.         }
  452.     } else if (entries[i]) {
  453.         free(entries[i]->mntpoint);
  454.         entries[i]->mntpoint = NULL;
  455.     }
  456.     }
  457.  
  458.     if (canEnableSwap) {
  459.     for (i = 0; i < fstab.numEntries; i++) {
  460.         if (fstab.entries[i].type == PART_SWAP &&
  461.         fstab.entries[i].mntpoint) {
  462.         enableswap(fstab.entries[i].device, 0, chkBadBlocks);
  463.         canEnableSwap = 0;
  464.         }
  465.     }
  466.     }
  467.  
  468.     freeFstab(*finalFstab);
  469.     *finalFstab = copyFstab(&fstab);
  470.     freeFstab(fstab);
  471.  
  472.     return 0;
  473. }
  474.