/* * mkswap.c - set up a linux swap device * * (C) 1991 Linus Torvalds. This file may be redistributed as per * the Linux copyright. * * (C) 1996 Red Hat Software - Modified by Erik Troan for Red Hat Software * still GPLed, of course */ /* * 20.12.91 - time began. Got VM working yesterday by doing this by hand. * * Usuage: mkswap [-c] device [size-in-blocks] * * -c for readablility checking (use it unless you are SURE!) * * The device may be a block device or a image of one, but this isn't * enforced (but it's not much fun on a character device :-). * * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. */ #include #include #include #include #include #include #include #include #include #include #define BLKGETSIZE 0x1260 #include "devices.h" #include "install.h" #include "intl.h" #include "log.h" #include "mkswap.h" #include "newt.h" #include "windows.h" #ifndef __linux__ # define volatile #endif #define TEST_BUFFER_PAGES 8 static int DEV = -1; static long PAGES = 0; static int check = 0; static int badpages = 0; int canEnableSwap = 1; static long bit_test_and_set (unsigned int *addr, unsigned int nr) { unsigned int r, m; addr += nr / (8 * sizeof(int)); r = *addr; m = 1 << (nr & (8 * sizeof(int) - 1)); *addr = r | m; return (r & m) != 0; } static int bit_test_and_clear (unsigned int *addr, unsigned int nr) { unsigned int r, m; addr += nr / (8 * sizeof(int)); r = *addr; m = 1 << (nr & (8 * sizeof(int) - 1)); *addr = r & ~m; return (r & m) != 0; } static int check_blocks(int * signature_page, char * file) { unsigned int current_page; int do_seek = 1; static char buffer[PAGE_SIZE]; newtComponent form = NULL, scale = NULL; newtGrid grid; if (check) { form = newtForm(NULL, NULL, 0); sprintf(buffer, _("Formatting swap space on device %s..."), file); scale = newtScale(-1, -1, 58, PAGES); grid = newtCreateGrid(1, 2); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, newtLabel(-1, -1, buffer), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, scale, 0, 1, 0, 0, 0, 0); newtGridAddComponentsToForm(grid, form, 1); newtGridWrappedWindow(grid, _("Formatting")); newtDrawForm(form); newtRefresh(); } current_page = 0; while (current_page < PAGES) { if (!check) { bit_test_and_set(signature_page,current_page++); continue; } newtScaleSet(scale, current_page); newtRefresh(); if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != current_page*PAGE_SIZE) { logMessage("mkswap: seek failed in check_blocks"); return INST_ERROR; } if ((do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE)))) { bit_test_and_clear(signature_page,current_page++); badpages++; continue; } bit_test_and_set(signature_page,current_page++); } if (badpages) logMessage("\t%d bad page%s\n",badpages,(badpages>1)?"s":""); if (check) { newtPopWindow(); newtFormDestroy(form); } return 0; } static long valid_offset (int fd, int offset) { char ch; if (lseek (fd, offset, 0) < 0) return 0; if (read (fd, &ch, 1) < 1) return 0; return 1; } static int count_blocks (int fd) { int high, low; low = 0; for (high = 1; valid_offset (fd, high); high *= 2) low = high; while (low < high - 1) { const int mid = (low + high) / 2; if (valid_offset (fd, mid)) low = mid; else high = mid; } valid_offset (fd, 0); return (low + 1); } static int get_size(const char *file, long int * sizeptr) { int fd; int size; fd = open(file, O_RDWR); if (fd < 0) { logMessage("mkswap: failed to get size of device %s", file); return INST_ERROR; } if (ioctl(fd, BLKGETSIZE, &size) >= 0) { close(fd); *sizeptr = size * 512; return 0; } *sizeptr = count_blocks(fd); close(fd); return 0;; } int enableswap(char * device_name, int size, int checkBlocks) { struct stat statbuf; int goodpages; int signature_page[PAGE_SIZE/sizeof(int)]; char devicefile[100]; check = checkBlocks; if (testing) { return 0; } memset(signature_page,0,PAGE_SIZE); if (*device_name == '/') { strcpy(devicefile, device_name); } else { sprintf(devicefile, "/tmp/%s", device_name); if (devMakeInode(device_name, devicefile)) { return INST_ERROR; } } if (size) PAGES = size; else { if (get_size(devicefile, &PAGES)) { unlink(devicefile); return INST_ERROR; } PAGES = PAGES / PAGE_SIZE; } if (PAGES<10) { logMessage("mkswap: error: swap area needs to be at least " "%ldkB", 10 * PAGE_SIZE / 1024); unlink(devicefile); return INST_ERROR; } if (PAGES > 8 * (PAGE_SIZE - 10)) { PAGES = 8 * (PAGE_SIZE - 10); logMessage("mkswap: warning: truncating %s swap to %ldkB", device_name, PAGES * PAGE_SIZE / 1024); } DEV = open(devicefile,O_RDWR); if (DEV < 0 || fstat(DEV, &statbuf) < 0) { logMessage("mkswap: failed to open device: %s\n", device_name); unlink(devicefile); return INST_ERROR; } if (!S_ISBLK(statbuf.st_mode)) check=0; else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) { logMessage("mkswap: will not try to make swapdevice on '%s'"); close(DEV); unlink(devicefile); return INST_ERROR; } if (check_blocks(signature_page, device_name)) { close(DEV); unlink(devicefile); newtPopWindow(); return INST_ERROR; } if (!bit_test_and_clear(signature_page,0)) { logMessage("mkswap: first page unreadable"); close(DEV); unlink(devicefile); newtPopWindow(); return INST_ERROR; } goodpages = PAGES - badpages - 1; if (goodpages <= 0) { logMessage("mkswap: unable to set up swap-space: unreadable"); close(DEV); unlink(devicefile); newtPopWindow(); return INST_ERROR; } logMessage("setting up swapspace, device = %s, size = %d bytes", device_name, goodpages*PAGE_SIZE); strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); if (lseek(DEV, 0, SEEK_SET)) { logMessage("mkswap: unable to rewind swap-device"); close(DEV); unlink(devicefile); newtPopWindow(); return INST_ERROR; } if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) { logMessage("mkswap: unable to write signature page"); close(DEV); unlink(devicefile); newtPopWindow(); return INST_ERROR; } close(DEV); if (swapon(devicefile, 0)) { logMessage("mkswap: swapon() failed: %s\n", strerror(errno)); } if (*device_name != '/') unlink(devicefile); return 0; } int activeSwapSpace(struct partitionTable * table, struct fstab * finalFstab) { newtComponent form, checkList, okay, cancel, sb, text, answer, label; newtComponent check, checkbox, blank; newtGrid grid, subgrid, buttons, checkgrid; char * states; char buf[80]; int i, j, rc, row; struct fstabEntry entry; struct fstabEntry ** entries; struct fstab fstab; static int chkBadBlocks = 1; char doCheck = ' '; if (!canEnableSwap) return INST_NOP; fstab = copyFstab(finalFstab); form = newtForm(NULL, NULL, 0); for (i = j = 0; i < table->count; i++) if (table->parts[i].type == PART_SWAP) j++; if (!j) { rc = newtWinChoice(_("No Swap Space"), _("Repartition"), _("Continue"), _("You don't have any swap space defined. Would " "you like to continue, or repartition your disk?")); if (rc != 2) return INST_CANCEL; return 0; } if (!kickstart) { if (j > 3) { sb = newtVerticalScrollbar(47, 7, 3, 9, 10); } else sb = NULL; checkList = newtForm(sb, NULL, 0); if (sb) newtFormSetHeight(checkList, j > 3); text = newtTextboxReflowed(-1, -1, _("What partitions would you like " "to use for swap space? This will destroy any " "information already on the partition."), 52, 0, 15, 0); label = newtLabel(-1, -1, " Device Begin End Size (k)"); states = alloca(sizeof(char) * table->count); entries = alloca(sizeof(*entries) * table->count); for (i = 0, row = 0; i < table->count; i++) { if (table->parts[i].type != PART_SWAP) continue; for (j = 0; j < fstab.numEntries; j++) if (!strcmp(table->parts[i].device, fstab.entries[j].device)) break; if ((j < fstab.numEntries && fstab.entries[j].mntpoint) || !testing) states[i] = '*'; else states[i] = ' '; if (j < fstab.numEntries) entries[i] = fstab.entries + j; else entries[i] = NULL; sprintf(buf, "/dev/%-5s %9d %9d %9d", table->parts[i].device, table->parts[i].begin, table->parts[i].end, table->parts[i].size); check = newtCheckbox(-1, row++, buf, states[i], NULL, &states[i]); newtFormAddComponent(checkList, check); } if (row > 3) { blank = newtForm(NULL, NULL, 0); newtFormSetWidth(blank, 2); newtFormSetHeight(blank, 3); newtFormSetBackground(blank, NEWT_COLORSET_CHECKBOX); checkgrid = newtGridHCloseStacked( NEWT_GRID_COMPONENT, checkList, NEWT_GRID_COMPONENT, blank, NEWT_GRID_COMPONENT, sb, NULL); } else { checkgrid = newtGridHCloseStacked(NEWT_GRID_COMPONENT, checkList, NULL); } checkbox = newtCheckbox(-1, -1, _("Check for bad blocks during format"), chkBadBlocks ? '*' : ' ', NULL, &doCheck); buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL); subgrid = newtCreateGrid(1, 3); newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT, label, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 1, NEWT_GRID_SUBGRID, checkgrid, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 2, NEWT_GRID_COMPONENT, checkbox, 0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0); grid = newtGridBasicWindow(text, subgrid, buttons); newtGridAddComponentsToForm(grid, form, 1); newtGridWrappedWindow(grid, _("Active Swap Space")); newtGridFree(grid, 1); answer = newtRunForm(form); newtFormDestroy(form); newtPopWindow(); chkBadBlocks = (doCheck != ' '); if (answer == cancel) { freeFstab(fstab); return INST_CANCEL; } } for (i = 0; i < table->count; i++) { if (table->parts[i].type != PART_SWAP) continue; if (kickstart || states[i] != ' ') { if (!kickstart && entries[i]) entries[i]->mntpoint = strdup("swap"); else { initFstabEntry(&entry); entry.device = strdup(table->parts[i].device); entry.size = table->parts[i].size; entry.type = table->parts[i].type; entry.tagName = table->parts[i].tagName; entry.mntpoint = strdup("swap"); addFstabEntry(&fstab, entry); } } else if (entries[i]) { free(entries[i]->mntpoint); entries[i]->mntpoint = NULL; } } if (canEnableSwap) { for (i = 0; i < fstab.numEntries; i++) { if (fstab.entries[i].type == PART_SWAP && fstab.entries[i].mntpoint) { enableswap(fstab.entries[i].device, 0, chkBadBlocks); canEnableSwap = 0; } } } freeFstab(*finalFstab); *finalFstab = copyFstab(&fstab); freeFstab(fstab); return 0; }