X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=util-linux%2Fmkswap.c;h=11c411b6ac14043f3ce2f0bfcb83b740c235638d;hb=d93179fd5b6811cf5446a31146099c66c85db359;hp=f797d1395bef45a86a571efc369c1f0eb5a33067;hpb=cc8ed39b240180b58810784f844e253263594ac3;p=oweals%2Fbusybox.git diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c index f797d1395..11c411b6a 100644 --- a/util-linux/mkswap.c +++ b/util-linux/mkswap.c @@ -1,253 +1,129 @@ -#include "internal.h" -/* - * mkswap.c - set up a linux swap device - * - * (C) 1991 Linus Torvalds. This file may be redistributed as per - * the Linux copyright. - */ - -/* - * 20.12.91 - time began. Got VM working yesterday by doing this by hand. - * - * Usage: mkswap [-c] device [size-in-blocks] - * - * -c for readablility checking (use it unless you are SURE!) +/* vi: set sw=4 ts=4: */ +/* mkswap.c - format swap device (Linux v1 only) * - * 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 :-). + * Copyright 2006 Rob Landley * - * 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. + * Licensed under GPL version 2, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifndef __linux__ -# define volatile -#endif - -#define TEST_BUFFER_PAGES 8 - -const char mkswap_usage[] = "mkswap [-c] partition [block-count]\n" -"\n" -"\tPrepare a disk partition to be used as a swap partition.\n" -"\tThe default block count is the size of the entire partition.\n" -"\n" -"\t-c:\tCheck for read-ability.\n" -"\tblock-count\tUse only this many blocks.\n"; - -static const char * program_name = "mkswap"; -static const char * device_name = NULL; -static int DEV = -1; -static long PAGES = 0; -static int do_check = 0; -static int badpages = 0; +#include "libbb.h" - -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) +#if ENABLE_SELINUX +static void mkswap_selinux_setcontext(int fd, const char *path) { - 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; + struct stat stbuf; + + if (!is_selinux_enabled()) + return; + + if (fstat(fd, &stbuf) < 0) + bb_perror_msg_and_die("fstat failed"); + if (S_ISREG(stbuf.st_mode)) { + security_context_t newcon; + security_context_t oldcon = NULL; + context_t context; + + if (fgetfilecon(fd, &oldcon) < 0) { + if (errno != ENODATA) + goto error; + if (matchpathcon(path, stbuf.st_mode, &oldcon) < 0) + goto error; + } + context = context_new(oldcon); + if (!context || context_type_set(context, "swapfile_t")) + goto error; + newcon = context_str(context); + if (!newcon) + goto error; + /* fsetfilecon_raw is hidden */ + if (strcmp(oldcon, newcon) != 0 && fsetfilecon(fd, newcon) < 0) + goto error; + if (ENABLE_FEATURE_CLEAN_UP) { + context_free(context); + freecon(oldcon); + } + } + return; + error: + bb_perror_msg_and_die("SELinux relabeling failed"); } +#else +#define mkswap_selinux_setcontext(fd, path) ((void)0) +#endif +#if 0 /* from Linux 2.6.23 */ /* - * Volatile to let gcc know that this doesn't return. When trying - * to compile this under minix, volatile gives a warning, as - * exit() isn't defined as volatile under minix. + * Magic header for a swap area. The first part of the union is + * what the swap magic looks like for the old (limited to 128MB) + * swap area format, the second part of the union adds - in the + * old reserved area - some extra information. Note that the first + * kilobyte is reserved for boot loader or disk label stuff... */ -volatile void fatal_error(const char * fmt_string) -{ - fprintf(stderr,fmt_string,program_name,device_name); - exit(1); -} +union swap_header { + struct { + char reserved[PAGE_SIZE - 10]; + char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */ + } magic; + struct { + char bootbits[1024]; /* Space for disklabel etc. */ + __u32 version; /* second kbyte, word 0 */ + __u32 last_page; /* 1 */ + __u32 nr_badpages; /* 2 */ + unsigned char sws_uuid[16]; /* 3,4,5,6 */ + unsigned char sws_volume[16]; /* 7,8,9,10 */ + __u32 padding[117]; /* 11..127 */ + __u32 badpages[1]; /* 128, total 129 32-bit words */ + } info; +}; +#endif -#define die(str) fatal_error("%s: " str "\n") +#define NWORDS 129 +#define hdr ((uint32_t*)(&bb_common_bufsiz1)) -static void check_blocks(int * signature_page) -{ - unsigned int current_page; - int do_seek = 1; - char buffer[PAGE_SIZE]; - - current_page = 0; - while (current_page < PAGES) { - if (!do_check) { - bit_test_and_set(signature_page,current_page++); - continue; - } else { - printf("\r%d", current_page); - } - if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != - current_page*PAGE_SIZE) - die("seek failed in check_blocks"); - 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 (do_check) - printf("\n"); - if (badpages) - printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); -} +struct BUG_bufsiz1_is_too_small { + char BUG_bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1]; +}; + +/* Stored without terminating NUL */ +static const char SWAPSPACE2[sizeof("SWAPSPACE2")-1] ALIGN1 = "SWAPSPACE2"; -static long valid_offset (int fd, int offset) +int mkswap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mkswap_main(int argc, char **argv) { - char ch; + int fd, pagesize; + off_t len; - if (lseek (fd, offset, 0) < 0) - return 0; - if (read (fd, &ch, 1) < 1) - return 0; - return 1; -} + // No options supported. -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); -} + if (argc != 2) bb_show_usage(); -static int get_size(const char *file) -{ - int fd; - int size; + // Figure out how big the device is and announce our intentions. - fd = open(file, O_RDWR); - if (fd < 0) { - perror(file); - exit(1); - } - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - close(fd); - return (size * 512); - } - - size = count_blocks(fd); - close(fd); - return size; -} + fd = xopen(argv[1], O_RDWR); + /* fdlength was reported to be unreliable - use seek */ + len = xlseek(fd, 0, SEEK_END); +#if ENABLE_SELINUX + xlseek(fd, 0, SEEK_SET); +#endif + pagesize = getpagesize(); + printf("Setting up swapspace version 1, size = %"OFF_FMT"u bytes\n", + len - pagesize); + mkswap_selinux_setcontext(fd, argv[1]); -int -mkswap(char *device_name, int pages, int check) - { - struct stat statbuf; - int goodpages; - int signature_page[PAGE_SIZE/sizeof(int)]; + // Make a header. hdr is zero-filled so far... + hdr[0] = 1; + hdr[1] = (len / pagesize) - 1; - PAGES = pages; - do_check = check; + // Write the header. Sync to disk because some kernel versions check + // signature on disk (not in cache) during swapon. - memset(signature_page,0,PAGE_SIZE); + xlseek(fd, 1024, SEEK_SET); + xwrite(fd, hdr, NWORDS * 4); + xlseek(fd, pagesize - 10, SEEK_SET); + xwrite(fd, SWAPSPACE2, 10); + fsync(fd); - if (device_name && !PAGES) { - PAGES = get_size(device_name) / PAGE_SIZE; - } - if (!device_name || PAGES<10) { - fprintf(stderr, - "%s: error: swap area needs to be at least %ldkB\n", - program_name, 10 * PAGE_SIZE / 1024); - /* usage(mkswap_usage); */ - exit(1); - } - if (PAGES > 8 * (PAGE_SIZE - 10)) { - PAGES = 8 * (PAGE_SIZE - 10); - fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n", - program_name, PAGES * PAGE_SIZE / 1024); - } - DEV = open(device_name,O_RDWR); - if (DEV < 0 || fstat(DEV, &statbuf) < 0) { - perror(device_name); - exit(1); - } - if (!S_ISBLK(statbuf.st_mode)) - do_check=0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - die("Will not try to make swapdevice on '%s'"); - check_blocks(signature_page); - if (!bit_test_and_clear(signature_page,0)) - die("fatal: first page unreadable"); - goodpages = PAGES - badpages - 1; - if (goodpages <= 0) - die("Unable to set up swap-space: unreadable"); - printf("Setting up swapspace, size = %ld bytes\n",goodpages*PAGE_SIZE); - strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); - if (lseek(DEV, 0, SEEK_SET)) - die("unable to rewind swap-device"); - if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) - die("unable to write signature page"); - - close(DEV); - return 0; -} + if (ENABLE_FEATURE_CLEAN_UP) close(fd); -int mkswap_main(struct FileInfo * unnecessary, int argc, char ** argv) -{ - char * tmp; - long int pages=0; - int check=0; - - if (argc && *argv) - program_name = *argv; - while (argc > 1) { - argv++; - argc--; - if (argv[0][0] != '-') - if (device_name) { - pages = strtol(argv[0],&tmp,0)>>(PAGE_SHIFT-10); - if (*tmp) { - usage(mkswap_usage); - exit(1); - } - } else - device_name = argv[0]; - else while (*++argv[0]) - switch (argv[0][0]) { - case 'c': check=1; break; - default: usage(mkswap_usage); - exit(1); - } - } - return mkswap(device_name, pages, check); + return 0; }