int main(void) { int p, s, r; struct rusage rr; long long tms = 0; fprintf(stderr, "t6: checking millisecond time limits\n"); if ((linux_version = get_linux_version()) < 0) return 1; if (!linux_version) { fprintf(stderr, "failed: not Linux or unknown linux version\n"); return 1; } fprintf(stderr, "t6: linux version %d\n", linux_version); if (linux_version >= 3000000) { fprintf(stderr, "t6: patch for linux >= 3.0.0 does not support millisecond time limits\n"); return 0; } if ((p = fork()) < 0) { fprintf(stderr, "failed: unexpected fork() error: %s\n", strerror(errno)); return 1; } if (!p) do_son(); sleep(5); r = wait4(-1, &s, WNOHANG, &rr); if (!r) { fprintf(stderr, "failed: child did not terminate in 5 seconds\n"); kill(p, SIGKILL); wait(0); return 1; } if (WIFEXITED(s) && WEXITSTATUS(s) == 111) { fprintf(stderr, "failed: child failed to setup limitations\n"); return 1; } if (WIFEXITED(s)) { fprintf(stderr, "info: child exited: %d\n", WEXITSTATUS(s)); } else if (WIFSIGNALED(s)) { fprintf(stderr, "info: child signaled: %d\n", WTERMSIG(s)); } tms = 0; tms += rr.ru_utime.tv_sec * 1000; tms += rr.ru_stime.tv_sec * 1000; tms += rr.ru_utime.tv_usec / 1000; tms += rr.ru_stime.tv_usec / 1000; fprintf(stderr, "info: child user+sys ms: %lld\n", tms); if (tms > 900) { fprintf(stderr, "failed: millisecond timelimit does not work\n"); return 1; } fprintf(stderr, "ok\n"); return 0; }
static int system_supports_ext4_ext2(void) { #ifdef __linux__ return get_linux_version() >= EXT4_SUPPORTS_EXT2; #else return 0; #endif }
/* * Check if the kernel supports partitioned loop devices. * * Notes: * - kernels < 3.2 support partitioned loop devices and PT scanning * only if max_part= module paremeter is non-zero * * - kernels >= 3.2 always support partitioned loop devices * * - kernels >= 3.2 always support BLKPG_{ADD,DEL}_PARTITION ioctls * * - kernels >= 3.2 enable PT scanner only if max_part= is non-zero or if the * LO_FLAGS_PARTSCAN flag is set for the device. The PT scanner is disabled * by default. * * See kernel commit e03c8dd14915fabc101aa495828d58598dc5af98. */ int loopmod_supports_partscan(void) { int rc, ret = 0; FILE *f; if (get_linux_version() >= KERNEL_VERSION(3,2,0)) return 1; f = fopen("/sys/module/loop/parameters/max_part", "r"); if (!f) return 0; rc = fscanf(f, "%d", &ret); fclose(f); return rc == 1 ? ret : 0; }
int main(int argc, char **argv) { int p, s, d = 0; snprintf(progname, sizeof(progname), "%s_helper", argv[0]); fprintf(stderr, "t5: checking memory limit error for program size\n"); if ((linux_version = get_linux_version()) < 0) return 1; if (!linux_version) { fprintf(stderr, "failed: not Linux or unknown linux version\n"); return 1; } fprintf(stderr, "t5: linux version %d\n", linux_version); if ((p = fork()) < 0) { fprintf(stderr, "failed: unexpected fork() error: %s\n", strerror(errno)); return 1; } if (!p) do_son(); wait(&s); if ((s & 0x10000)) { fprintf(stderr, "info: 0x10000 detected\n"); s &= 0xffff; d = 1; } if (WIFEXITED(s) && WEXITSTATUS(s) == 111) { fprintf(stderr, "failed: child failed to setup limitations\n"); return 1; } if (WIFEXITED(s)) { fprintf(stderr, "info: child exited: %d\n", WEXITSTATUS(s)); } else if (WIFSIGNALED(s)) { fprintf(stderr, "info: child signaled: %d\n", WTERMSIG(s)); } if (!d) { fprintf(stderr, "failed: memory limit error not detected\n"); return 1; } fprintf(stderr, "ok\n"); return 0; }
int main(void) { int p, s, d = 0; fprintf(stderr, "t3: checking memory limit error for stack\n"); if ((linux_version = get_linux_version()) < 0) return 1; if (!linux_version) { fprintf(stderr, "failed: not Linux or unknown linux version\n"); return 1; } fprintf(stderr, "t3: linux version %d\n", linux_version); if ((p = fork()) < 0) { fprintf(stderr, "failed: unexpected fork() error: %s\n", strerror(errno)); return 1; } if (!p) do_son(); wait(&s); if ((s & 0x10000)) { fprintf(stderr, "\ninfo: 0x10000 detected\n"); s &= 0xffff; d = 1; } if (WIFEXITED(s) && WEXITSTATUS(s) == 111) { fprintf(stderr, "failed: child failed to setup limitations\n"); return 1; } if (WIFEXITED(s)) { fprintf(stderr, "info: child exited: %d\n", WEXITSTATUS(s)); } else if (WIFSIGNALED(s)) { fprintf(stderr, "info: child signaled: %d\n", WTERMSIG(s)); } if (!d) { fprintf(stderr, "failed: memory limit error not detected\n"); return 1; } fprintf(stderr, "ok\n"); return 0; }
void _initialize_arm_linux_nat (void) { struct target_ops *t; os_version = get_linux_version (&os_major, &os_minor, &os_release); /* Fill in the generic GNU/Linux methods. */ t = linux_target (); /* Add our register access methods. */ t->to_fetch_registers = arm_linux_fetch_inferior_registers; t->to_store_registers = arm_linux_store_inferior_registers; t->to_read_description = arm_linux_read_description; /* Register the target. */ linux_nat_add_target (t); }
/* * @lc: context * @flags: LOOPDEV_FL_* flags * * Initilize loop handler. * * We have two sets of the flags: * * * LOOPDEV_FL_* flags control loopcxt_* API behavior * * * LO_FLAGS_* are kernel flags used for LOOP_{SET,GET}_STAT64 ioctls * * Note about LOOPDEV_FL_{RDONLY,RDWR} flags. These flags are used for open(2) * syscall to open loop device. By default is the device open read-only. * * The expection is loopcxt_setup_device(), where the device is open read-write * if LO_FLAGS_READ_ONLY flags is not set (see loopcxt_set_flags()). * * Returns: <0 on error, 0 on success. */ int loopcxt_init(struct loopdev_cxt *lc, int flags) { struct stat st; if (!lc) return -EINVAL; memset(lc, 0, sizeof(*lc)); lc->flags = flags; loopcxt_set_device(lc, NULL); if (!(lc->flags & LOOPDEV_FL_NOSYSFS) && get_linux_version() >= KERNEL_VERSION(2,6,37)) /* * Use only sysfs for basic information about loop devices */ lc->flags |= LOOPDEV_FL_NOIOCTL; if (!(lc->flags & LOOPDEV_FL_CONTROL) && !stat(_PATH_DEV_LOOPCTL, &st)) lc->flags |= LOOPDEV_FL_CONTROL; return 0; }
int mnt_context_setup_loopdev(struct libmnt_context *cxt) { const char *backing_file, *optstr, *loopdev = NULL; char *val = NULL, *loopval = NULL; size_t len; struct loopdev_cxt lc; int rc = 0, lo_flags = 0; uint64_t offset = 0, sizelimit = 0; assert(cxt); assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); backing_file = mnt_fs_get_srcpath(cxt->fs); if (!backing_file) return -EINVAL; DBG(LOOP, ul_debugobj(cxt, "trying to setup device for %s", backing_file)); if (cxt->mountflags & MS_RDONLY) { DBG(LOOP, ul_debugobj(cxt, "enabling READ-ONLY flag")); lo_flags |= LO_FLAGS_READ_ONLY; } optstr = mnt_fs_get_user_options(cxt->fs); /* * loop= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_LOOP) && mnt_optstr_get_option(optstr, "loop", &val, &len) == 0 && val) { loopval = strndup(val, len); rc = loopval ? 0 : -ENOMEM; } /* * offset= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_OFFSET) && mnt_optstr_get_option(optstr, "offset", &val, &len) == 0) { rc = mnt_parse_offset(val, len, &offset); if (rc) { DBG(LOOP, ul_debugobj(cxt, "failed to parse offset=")); rc = -MNT_ERR_MOUNTOPT; } } /* * sizelimit= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_SIZELIMIT) && mnt_optstr_get_option(optstr, "sizelimit", &val, &len) == 0) { rc = mnt_parse_offset(val, len, &sizelimit); if (rc) { DBG(LOOP, ul_debugobj(cxt, "failed to parse sizelimit=")); rc = -MNT_ERR_MOUNTOPT; } } /* * encryption= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_ENCRYPTION) && mnt_optstr_get_option(optstr, "encryption", &val, &len) == 0) { DBG(LOOP, ul_debugobj(cxt, "encryption no longer supported")); rc = -MNT_ERR_MOUNTOPT; } if (rc == 0 && is_mounted_same_loopfile(cxt, mnt_context_get_target(cxt), backing_file, offset)) rc = -EBUSY; if (rc) goto done_no_deinit; /* It is possible to mount the same file more times. If we set more * than one loop device referring to the same file, kernel has no * mechanism to detect it. To prevent data corruption, the same loop * device has to be recycled. */ if (backing_file) { rc = loopcxt_init(&lc, 0); if (rc) goto done_no_deinit; rc = loopcxt_find_overlap(&lc, backing_file, offset, sizelimit); switch (rc) { case 0: /* not found */ DBG(LOOP, ul_debugobj(cxt, "not found overlaping loopdev")); loopcxt_deinit(&lc); break; case 1: /* overlap */ DBG(LOOP, ul_debugobj(cxt, "overlaping %s detected", loopcxt_get_device(&lc))); rc = -MNT_ERR_LOOPOVERLAP; goto done; case 2: /* overlap -- full size and offset match (reuse) */ { uint32_t lc_encrypt_type; DBG(LOOP, ul_debugobj(cxt, "re-using existing loop device %s", loopcxt_get_device(&lc))); /* Once a loop is initialized RO, there is no * way to change its parameters. */ if (loopcxt_is_readonly(&lc) && !(lo_flags & LO_FLAGS_READ_ONLY)) { DBG(LOOP, ul_debugobj(cxt, "%s is read-only", loopcxt_get_device(&lc))); rc = -EROFS; goto done; } /* This is no more supported, but check to be safe. */ if (loopcxt_get_encrypt_type(&lc, &lc_encrypt_type) == 0 && lc_encrypt_type != LO_CRYPT_NONE) { DBG(LOOP, ul_debugobj(cxt, "encryption no longer supported for device %s", loopcxt_get_device(&lc))); rc = -MNT_ERR_LOOPOVERLAP; goto done; } rc = 0; goto success; } default: /* error */ goto done; } } DBG(LOOP, ul_debugobj(cxt, "not found; create a new loop device")); rc = loopcxt_init(&lc, 0); if (rc) goto done_no_deinit; if (loopval) { rc = loopcxt_set_device(&lc, loopval); if (rc == 0) loopdev = loopcxt_get_device(&lc); } if (rc) goto done; /* since 2.6.37 we don't have to store backing filename to mtab * because kernel provides the name in /sys. */ if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) || !mnt_context_mtab_writable(cxt)) { DBG(LOOP, ul_debugobj(cxt, "enabling AUTOCLEAR flag")); lo_flags |= LO_FLAGS_AUTOCLEAR; } do { /* found free device */ if (!loopdev) { rc = loopcxt_find_unused(&lc); if (rc) goto done; DBG(LOOP, ul_debugobj(cxt, "trying to use %s", loopcxt_get_device(&lc))); } /* set device attributes * -- note that loopcxt_find_unused() resets "lc" */ rc = loopcxt_set_backing_file(&lc, backing_file); if (!rc && offset) rc = loopcxt_set_offset(&lc, offset); if (!rc && sizelimit) rc = loopcxt_set_sizelimit(&lc, sizelimit); if (!rc) loopcxt_set_flags(&lc, lo_flags); if (rc) { DBG(LOOP, ul_debugobj(cxt, "failed to set loop attributes")); goto done; } /* setup the device */ rc = loopcxt_setup_device(&lc); if (!rc) break; /* success */ if (loopdev || rc != -EBUSY) { DBG(LOOP, ul_debugobj(cxt, "failed to setup device")); rc = -MNT_ERR_LOOPDEV; goto done; } DBG(LOOP, ul_debugobj(cxt, "device stolen...trying again")); } while (1); success: if (!rc) rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc)); if (!rc) { /* success */ cxt->flags |= MNT_FL_LOOPDEV_READY; if ((cxt->user_mountflags & MNT_MS_LOOP) && loopcxt_is_autoclear(&lc)) { /* * autoclear flag accepted by the kernel, don't store * the "loop=" option to mtab. */ DBG(LOOP, ul_debugobj(cxt, "removing unnecessary loop= from mtab")); cxt->user_mountflags &= ~MNT_MS_LOOP; mnt_optstr_remove_option(&cxt->fs->user_optstr, "loop"); } if (!(cxt->mountflags & MS_RDONLY) && loopcxt_is_readonly(&lc)) /* * mount planned read-write, but loopdev is read-only, * let's fix mount options... */ mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY); /* we have to keep the device open until mount(1), * otherwise it will be auto-cleared by kernel */ cxt->loopdev_fd = loopcxt_get_fd(&lc); if (cxt->loopdev_fd < 0) { DBG(LOOP, ul_debugobj(cxt, "failed to get loopdev FD")); rc = -errno; } else loopcxt_set_fd(&lc, -1, 0); } done: loopcxt_deinit(&lc); done_no_deinit: free(loopval); return rc; }
/* get size in bytes */ int blkdev_get_size(int fd, unsigned long long *bytes) { #ifdef DKIOCGETBLOCKCOUNT /* Apple Darwin */ if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) { *bytes <<= 9; return 0; } #endif #ifdef BLKGETSIZE64 { #ifdef __linux__ int ver = get_linux_version(); /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */ if (ver >= KERNEL_VERSION (2,6,0) || (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0))) #endif if (ioctl(fd, BLKGETSIZE64, bytes) >= 0) return 0; } #endif /* BLKGETSIZE64 */ #ifdef BLKGETSIZE { unsigned long size; if (ioctl(fd, BLKGETSIZE, &size) >= 0) { *bytes = ((unsigned long long)size << 9); return 0; } } #endif /* BLKGETSIZE */ #ifdef DIOCGMEDIASIZE /* FreeBSD */ if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0) return 0; #endif #ifdef FDGETPRM { struct floppy_struct this_floppy; if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { *bytes = ((unsigned long long) this_floppy.size) << 9; return 0; } } #endif /* FDGETPRM */ #ifdef HAVE_SYS_DISKLABEL_H { /* * This code works for FreeBSD 4.11 i386, except for the full device * (such as /dev/ad0). It doesn't work properly for newer FreeBSD * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE * above however. * * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw, * character) devices, so we need to check for S_ISCHR, too. */ int part = -1; struct disklabel lab; struct partition *pp; struct stat st; if ((fstat(fd, &st) >= 0) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) part = st.st_rdev & 7; if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { pp = &lab.d_partitions[part]; if (pp->p_size) { *bytes = pp->p_size << 9; return 0; } } } #endif /* HAVE_SYS_DISKLABEL_H */ { struct stat st; if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { *bytes = st.st_size; return 0; } if (!S_ISBLK(st.st_mode)) return -1; } *bytes = blkdev_find_size(fd); return 0; }
void _initialize_arm_linux_nat (void) { os_version = get_linux_version (&os_major, &os_minor, &os_release); }
int Manage_subdevs(char *devname, int fd, struct mddev_dev *devlist, int verbose, int test, char *update) { /* do something to each dev. * devmode can be * 'a' - add the device * try HOT_ADD_DISK * If that fails EINVAL, try ADD_NEW_DISK * 'r' - remove the device HOT_REMOVE_DISK * device can be 'faulty' or 'detached' in which case all * matching devices are removed. * 'f' - set the device faulty SET_DISK_FAULTY * device can be 'detached' in which case any device that * is inaccessible will be marked faulty. * For 'f' and 'r', the device can also be a kernel-internal * name such as 'sdb'. */ struct mddev_dev *add_devlist = NULL; mdu_array_info_t array; mdu_disk_info_t disc; unsigned long long array_size; struct mddev_dev *dv, *next = NULL; struct stat stb; int j, jnext = 0; int tfd = -1; struct supertype *st, *tst; char *subarray = NULL; int duuid[4]; int ouuid[4]; int lfd = -1; int sysfd = -1; int count = 0; /* number of actions taken */ if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": cannot get array info for %s\n", devname); return 1; } /* array.size is only 32 bit and may be truncated. * So read from sysfs if possible, and record number of sectors */ array_size = get_component_size(fd); if (array_size <= 0) array_size = array.size * 2; tst = super_by_fd(fd, &subarray); if (!tst) { fprintf(stderr, Name ": unsupport array - version %d.%d\n", array.major_version, array.minor_version); return 1; } stb.st_rdev = 0; for (dv = devlist, j=0 ; dv; dv = next, j = jnext) { unsigned long long ldsize; char dvname[20]; char *dnprintable = dv->devname; char *add_dev = dv->devname; int err; int re_add_failed = 0; next = dv->next; jnext = 0; if (strcmp(dv->devname, "failed")==0 || strcmp(dv->devname, "faulty")==0) { int remaining_disks = array.nr_disks; if (dv->disposition != 'r') { fprintf(stderr, Name ": %s only meaningful " "with -r, not -%c\n", dv->devname, dv->disposition); return 1; } for (; j < 1024 && remaining_disks > 0; j++) { unsigned dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; if (disc.major == 0 && disc.minor == 0) continue; remaining_disks --; if ((disc.state & 1) == 0) /* faulty */ continue; dev = makedev(disc.major, disc.minor); if (stb.st_rdev == dev) /* already did that one */ continue; stb.st_rdev = dev; next = dv; /* same slot again next time - things might * have reshuffled */ jnext = j; sprintf(dvname,"%d:%d", disc.major, disc.minor); dnprintable = dvname; break; } if (next != dv) continue; } else if (strcmp(dv->devname, "detached") == 0) { int remaining_disks = array.nr_disks; if (dv->disposition != 'r' && dv->disposition != 'f') { fprintf(stderr, Name ": %s only meaningful " "with -r of -f, not -%c\n", dv->devname, dv->disposition); return 1; } for (; j < 1024 && remaining_disks > 0; j++) { int sfd; unsigned dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; if (disc.major == 0 && disc.minor == 0) continue; remaining_disks --; sprintf(dvname,"%d:%d", disc.major, disc.minor); sfd = dev_open(dvname, O_RDONLY); if (sfd >= 0) { close(sfd); continue; } if (dv->disposition == 'f' && (disc.state & 1) == 1) /* already faulty */ continue; if (errno != ENXIO) continue; dev = makedev(disc.major, disc.minor); if (stb.st_rdev == dev) /* already did that one */ continue; stb.st_rdev = dev; next = dv; /* same slot again next time - things might * have reshuffled */ jnext = j; dnprintable = dvname; break; } if (next != dv) continue; } else if (strcmp(dv->devname, "missing") == 0) { if (dv->disposition != 'a' || dv->re_add == 0) { fprintf(stderr, Name ": 'missing' only meaningful " "with --re-add\n"); return 1; } if (add_devlist == NULL) add_devlist = conf_get_devs(); if (add_devlist == NULL) { fprintf(stderr, Name ": no devices to scan for missing members."); continue; } add_dev = add_devlist->devname; add_devlist = add_devlist->next; if (add_devlist != NULL) next = dv; if (stat(add_dev, &stb) < 0) continue; } else if (strchr(dv->devname, '/') == NULL && strchr(dv->devname, ':') == NULL && strlen(dv->devname) < 50) { /* Assume this is a kernel-internal name like 'sda1' */ int found = 0; char dname[55]; if (dv->disposition != 'r' && dv->disposition != 'f') { fprintf(stderr, Name ": %s only meaningful " "with -r or -f, not -%c\n", dv->devname, dv->disposition); return 1; } sprintf(dname, "dev-%s", dv->devname); sysfd = sysfs_open(fd2devnum(fd), dname, "block/dev"); if (sysfd >= 0) { char dn[20]; int mj,mn; if (sysfs_fd_get_str(sysfd, dn, 20) > 0 && sscanf(dn, "%d:%d", &mj,&mn) == 2) { stb.st_rdev = makedev(mj,mn); found = 1; } close(sysfd); sysfd = -1; } if (!found) { sysfd = sysfs_open(fd2devnum(fd), dname, "state"); if (sysfd < 0) { fprintf(stderr, Name ": %s does not appear " "to be a component of %s\n", dv->devname, devname); return 1; } } } else { j = 0; tfd = dev_open(dv->devname, O_RDONLY); if (tfd < 0 && dv->disposition == 'r' && lstat(dv->devname, &stb) == 0) /* Be happy, the lstat worked, that is * enough for --remove */ ; else { if (tfd < 0 || fstat(tfd, &stb) != 0) { fprintf(stderr, Name ": cannot find %s: %s\n", dv->devname, strerror(errno)); if (tfd >= 0) close(tfd); return 1; } close(tfd); tfd = -1; } if ((stb.st_mode & S_IFMT) != S_IFBLK) { fprintf(stderr, Name ": %s is not a " "block device.\n", dv->devname); return 1; } } switch(dv->disposition){ default: fprintf(stderr, Name ": internal error - devmode[%s]=%d\n", dv->devname, dv->disposition); return 1; case 'a': /* add the device */ if (subarray) { fprintf(stderr, Name ": Cannot add disks to a" " \'member\' array, perform this" " operation on the parent container\n"); return 1; } /* Make sure it isn't in use (in 2.6 or later) */ tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT); if (tfd < 0 && add_dev != dv->devname) continue; if (tfd < 0) { fprintf(stderr, Name ": Cannot open %s: %s\n", dv->devname, strerror(errno)); return 1; } st = dup_super(tst); if (array.not_persistent==0) st->ss->load_super(st, tfd, NULL); if (add_dev == dv->devname) { if (!get_dev_size(tfd, dv->devname, &ldsize)) { close(tfd); return 1; } } else if (!get_dev_size(tfd, NULL, &ldsize)) { close(tfd); tfd = -1; continue; } if (!tst->ss->external && array.major_version == 0 && md_get_version(fd)%100 < 2) { close(tfd); tfd = -1; if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) { if (verbose >= 0) fprintf(stderr, Name ": hot added %s\n", add_dev); continue; } fprintf(stderr, Name ": hot add failed for %s: %s\n", add_dev, strerror(errno)); return 1; } if (array.not_persistent == 0 || tst->ss->external) { /* need to find a sample superblock to copy, and * a spare slot to use. * For 'external' array (well, container based), * We can just load the metadata for the array. */ if (tst->sb) /* already loaded */; else if (tst->ss->external) { tst->ss->load_container(tst, fd, NULL); } else for (j = 0; j < tst->max_devs; j++) { char *dev; int dfd; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; if (disc.major==0 && disc.minor==0) continue; if ((disc.state & 4)==0) continue; /* sync */ /* Looks like a good device to try */ dev = map_dev(disc.major, disc.minor, 1); if (!dev) continue; dfd = dev_open(dev, O_RDONLY); if (dfd < 0) continue; if (tst->ss->load_super(tst, dfd, NULL)) { close(dfd); continue; } close(dfd); break; } /* FIXME this is a bad test to be using */ if (!tst->sb) { close(tfd); fprintf(stderr, Name ": cannot load array metadata from %s\n", devname); return 1; } /* Make sure device is large enough */ if (tst->ss->avail_size(tst, ldsize/512) < array_size) { close(tfd); tfd = -1; if (add_dev != dv->devname) continue; fprintf(stderr, Name ": %s not large enough to join array\n", dv->devname); return 1; } /* Possibly this device was recently part of the array * and was temporarily removed, and is now being re-added. * If so, we can simply re-add it. */ tst->ss->uuid_from_super(tst, duuid); if (st->sb) { struct mdinfo mdi; st->ss->getinfo_super(st, &mdi, NULL); st->ss->uuid_from_super(st, ouuid); if ((mdi.disk.state & (1<<MD_DISK_ACTIVE)) && !(mdi.disk.state & (1<<MD_DISK_FAULTY)) && memcmp(duuid, ouuid, sizeof(ouuid))==0) { /* look like it is worth a try. Need to * make sure kernel will accept it though. */ /* re-add doesn't work for version-1 superblocks * before 2.6.18 :-( */ if (array.major_version == 1 && get_linux_version() <= 2006018) goto skip_re_add; disc.number = mdi.disk.number; if (ioctl(fd, GET_DISK_INFO, &disc) != 0 || disc.major != 0 || disc.minor != 0 || !enough_fd(fd)) goto skip_re_add; disc.major = major(stb.st_rdev); disc.minor = minor(stb.st_rdev); disc.number = mdi.disk.number; disc.raid_disk = mdi.disk.raid_disk; disc.state = mdi.disk.state; if (dv->writemostly == 1) disc.state |= 1 << MD_DISK_WRITEMOSTLY; if (dv->writemostly == 2) disc.state &= ~(1 << MD_DISK_WRITEMOSTLY); remove_partitions(tfd); close(tfd); tfd = -1; if (update) { int rv = -1; tfd = dev_open(dv->devname, O_RDWR); if (tfd >= 0) rv = st->ss->update_super( st, NULL, update, devname, verbose, 0, NULL); if (rv == 0) rv = st->ss->store_super(st, tfd); close(tfd); tfd = -1; if (rv != 0) { fprintf(stderr, Name ": failed to update" " superblock during re-add\n"); return 1; } } /* don't even try if disk is marked as faulty */ errno = 0; if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) { if (verbose >= 0) fprintf(stderr, Name ": re-added %s\n", add_dev); count++; continue; } if (errno == ENOMEM || errno == EROFS) { fprintf(stderr, Name ": add new device failed for %s: %s\n", add_dev, strerror(errno)); if (add_dev != dv->devname) continue; return 1; } skip_re_add: re_add_failed = 1; } st->ss->free_super(st); } if (add_dev != dv->devname) { if (verbose > 0) fprintf(stderr, Name ": --re-add for %s to %s is not possible\n", add_dev, devname); if (tfd >= 0) { close(tfd); tfd = -1; } continue; } if (dv->re_add) { if (tfd >= 0) close(tfd); fprintf(stderr, Name ": --re-add for %s to %s is not possible\n", dv->devname, devname); return 1; } if (re_add_failed) { fprintf(stderr, Name ": %s reports being an active member for %s, but a --re-add fails.\n", dv->devname, devname); fprintf(stderr, Name ": not performing --add as that would convert %s in to a spare.\n", dv->devname); fprintf(stderr, Name ": To make this a spare, use \"mdadm --zero-superblock %s\" first.\n", dv->devname); if (tfd >= 0) close(tfd); return 1; } } else { /* non-persistent. Must ensure that new drive * is at least array.size big. */ if (ldsize/512 < array_size) { fprintf(stderr, Name ": %s not large enough to join array\n", dv->devname); if (tfd >= 0) close(tfd); return 1; } } /* committed to really trying this device now*/ if (tfd >= 0) { remove_partitions(tfd); close(tfd); tfd = -1; } /* in 2.6.17 and earlier, version-1 superblocks won't * use the number we write, but will choose a free number. * we must choose the same free number, which requires * starting at 'raid_disks' and counting up */ for (j = array.raid_disks; j< tst->max_devs; j++) { disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) break; if (disc.major==0 && disc.minor==0) break; if (disc.state & 8) /* removed */ break; } disc.major = major(stb.st_rdev); disc.minor = minor(stb.st_rdev); disc.number =j; disc.state = 0; if (array.not_persistent==0) { int dfd; if (dv->writemostly == 1) disc.state |= 1 << MD_DISK_WRITEMOSTLY; dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); if (tst->ss->add_to_super(tst, &disc, dfd, dv->devname)) { close(dfd); return 1; } if (tst->ss->write_init_super(tst)) { close(dfd); return 1; } } else if (dv->re_add) { /* this had better be raid1. * As we are "--re-add"ing we must find a spare slot * to fill. */ char *used = malloc(array.raid_disks); memset(used, 0, array.raid_disks); for (j=0; j< tst->max_devs; j++) { mdu_disk_info_t disc2; disc2.number = j; if (ioctl(fd, GET_DISK_INFO, &disc2)) continue; if (disc2.major==0 && disc2.minor==0) continue; if (disc2.state & 8) /* removed */ continue; if (disc2.raid_disk < 0) continue; if (disc2.raid_disk > array.raid_disks) continue; used[disc2.raid_disk] = 1; } for (j=0 ; j<array.raid_disks; j++) if (!used[j]) { disc.raid_disk = j; disc.state |= (1<<MD_DISK_SYNC); break; } free(used); } if (dv->writemostly == 1) disc.state |= (1 << MD_DISK_WRITEMOSTLY); if (tst->ss->external) { /* add a disk * to an external metadata container */ struct mdinfo new_mdi; struct mdinfo *sra; int container_fd; int devnum = fd2devnum(fd); int dfd; container_fd = open_dev_excl(devnum); if (container_fd < 0) { fprintf(stderr, Name ": add failed for %s:" " could not get exclusive access to container\n", dv->devname); tst->ss->free_super(tst); return 1; } dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); if (mdmon_running(tst->container_dev)) tst->update_tail = &tst->updates; if (tst->ss->add_to_super(tst, &disc, dfd, dv->devname)) { close(dfd); close(container_fd); return 1; } if (tst->update_tail) flush_metadata_updates(tst); else tst->ss->sync_metadata(tst); sra = sysfs_read(container_fd, -1, 0); if (!sra) { fprintf(stderr, Name ": add failed for %s: sysfs_read failed\n", dv->devname); close(container_fd); tst->ss->free_super(tst); return 1; } sra->array.level = LEVEL_CONTAINER; /* Need to set data_offset and component_size */ tst->ss->getinfo_super(tst, &new_mdi, NULL); new_mdi.disk.major = disc.major; new_mdi.disk.minor = disc.minor; new_mdi.recovery_start = 0; /* Make sure fds are closed as they are O_EXCL which * would block add_disk */ tst->ss->free_super(tst); if (sysfs_add_disk(sra, &new_mdi, 0) != 0) { fprintf(stderr, Name ": add new device to external metadata" " failed for %s\n", dv->devname); close(container_fd); sysfs_free(sra); return 1; } ping_monitor_by_id(devnum); sysfs_free(sra); close(container_fd); } else { tst->ss->free_super(tst); if (ioctl(fd, ADD_NEW_DISK, &disc)) { fprintf(stderr, Name ": add new device failed for %s as %d: %s\n", dv->devname, j, strerror(errno)); return 1; } } if (verbose >= 0) fprintf(stderr, Name ": added %s\n", dv->devname); break; case 'r': /* hot remove */ if (subarray) { fprintf(stderr, Name ": Cannot remove disks from a" " \'member\' array, perform this" " operation on the parent container\n"); if (sysfd >= 0) close(sysfd); return 1; } if (tst->ss->external) { /* To remove a device from a container, we must * check that it isn't in use in an array. * This involves looking in the 'holders' * directory - there must be just one entry, * the container. * To ensure that it doesn't get used as a * hold spare while we are checking, we * get an O_EXCL open on the container */ int dnum = fd2devnum(fd); lfd = open_dev_excl(dnum); if (lfd < 0) { fprintf(stderr, Name ": Cannot get exclusive access " " to container - odd\n"); if (sysfd >= 0) close(sysfd); return 1; } /* in the detached case it is not possible to * check if we are the unique holder, so just * rely on the 'detached' checks */ if (strcmp(dv->devname, "detached") == 0 || sysfd >= 0 || sysfs_unique_holder(dnum, stb.st_rdev)) /* pass */; else { fprintf(stderr, Name ": %s is %s, cannot remove.\n", dnprintable, errno == EEXIST ? "still in use": "not a member"); close(lfd); return 1; } } /* FIXME check that it is a current member */ if (sysfd >= 0) { /* device has been removed and we don't know * the major:minor number */ int n = write(sysfd, "remove", 6); if (n != 6) err = -1; else err = 0; close(sysfd); sysfd = -1; } else { err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev); if (err && errno == ENODEV) { /* Old kernels rejected this if no personality * registered */ struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS); struct mdinfo *dv = NULL; if (sra) dv = sra->devs; for ( ; dv ; dv=dv->next) if (dv->disk.major == (int)major(stb.st_rdev) && dv->disk.minor == (int)minor(stb.st_rdev)) break; if (dv) err = sysfs_set_str(sra, dv, "state", "remove"); else err = -1; if (sra) sysfs_free(sra); } } if (err) { fprintf(stderr, Name ": hot remove failed " "for %s: %s\n", dnprintable, strerror(errno)); if (lfd >= 0) close(lfd); return 1; } if (tst->ss->external) { /* * Before dropping our exclusive open we make an * attempt at preventing mdmon from seeing an * 'add' event before reconciling this 'remove' * event. */ char *name = devnum2devname(fd2devnum(fd)); if (!name) { fprintf(stderr, Name ": unable to get container name\n"); return 1; } ping_manager(name); free(name); } if (lfd >= 0) close(lfd); count++; if (verbose >= 0) fprintf(stderr, Name ": hot removed %s from %s\n", dnprintable, devname); break; case 'f': /* set faulty */ /* FIXME check current member */ if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) || (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev))) { fprintf(stderr, Name ": set device faulty failed for %s: %s\n", dnprintable, strerror(errno)); if (sysfd >= 0) close(sysfd); return 1; } if (sysfd >= 0) close(sysfd); sysfd = -1; count++; if (verbose >= 0) fprintf(stderr, Name ": set %s faulty in %s\n", dnprintable, devname); break; } } if (test && count == 0) return 2; return 0; }
int mnt_context_setup_loopdev(struct libmnt_context *cxt) { const char *backing_file, *optstr, *loopdev = NULL; char *val = NULL; size_t len; struct loopdev_cxt lc; int rc = 0, lo_flags = 0; uint64_t offset = 0, sizelimit = 0; assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!cxt) return -EINVAL; backing_file = mnt_fs_get_srcpath(cxt->fs); if (!backing_file) return -EINVAL; DBG(CXT, ul_debugobj(cxt, "trying to setup loopdev for %s", backing_file)); if (cxt->mountflags & MS_RDONLY) { DBG(CXT, ul_debugobj(cxt, "enabling READ-ONLY flag")); lo_flags |= LO_FLAGS_READ_ONLY; } rc = loopcxt_init(&lc, 0); if (rc) return rc; ON_DBG(CXT, loopcxt_enable_debug(&lc, 1)); optstr = mnt_fs_get_user_options(cxt->fs); /* * loop= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_LOOP) && mnt_optstr_get_option(optstr, "loop", &val, &len) == 0 && val) { val = strndup(val, len); rc = val ? loopcxt_set_device(&lc, val) : -ENOMEM; free(val); if (rc == 0) loopdev = loopcxt_get_device(&lc); } /* * offset= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_OFFSET) && mnt_optstr_get_option(optstr, "offset", &val, &len) == 0) { rc = mnt_parse_offset(val, len, &offset); if (rc) { DBG(CXT, ul_debugobj(cxt, "failed to parse offset=")); rc = -MNT_ERR_MOUNTOPT; } } /* * sizelimit= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_SIZELIMIT) && mnt_optstr_get_option(optstr, "sizelimit", &val, &len) == 0) { rc = mnt_parse_offset(val, len, &sizelimit); if (rc) { DBG(CXT, ul_debugobj(cxt, "failed to parse sizelimit=")); rc = -MNT_ERR_MOUNTOPT; } } /* * encryption= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_ENCRYPTION) && mnt_optstr_get_option(optstr, "encryption", &val, &len) == 0) { DBG(CXT, ul_debugobj(cxt, "encryption no longer supported")); rc = -MNT_ERR_MOUNTOPT; } if (rc == 0 && is_mounted_same_loopfile(cxt, mnt_context_get_target(cxt), backing_file, offset)) rc = -EBUSY; if (rc) goto done; /* since 2.6.37 we don't have to store backing filename to mtab * because kernel provides the name in /sys. */ if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) || !mnt_context_mtab_writable(cxt)) { DBG(CXT, ul_debugobj(cxt, "enabling AUTOCLEAR flag")); lo_flags |= LO_FLAGS_AUTOCLEAR; } do { /* found free device */ if (!loopdev) { rc = loopcxt_find_unused(&lc); if (rc) goto done; DBG(CXT, ul_debugobj(cxt, "trying to use %s", loopcxt_get_device(&lc))); } /* set device attributes * -- note that loopcxt_find_unused() resets "lc" */ rc = loopcxt_set_backing_file(&lc, backing_file); if (!rc && offset) rc = loopcxt_set_offset(&lc, offset); if (!rc && sizelimit) rc = loopcxt_set_sizelimit(&lc, sizelimit); if (!rc) loopcxt_set_flags(&lc, lo_flags); if (rc) { DBG(CXT, ul_debugobj(cxt, "failed to set loopdev attributes")); goto done; } /* setup the device */ rc = loopcxt_setup_device(&lc); if (!rc) break; /* success */ if (loopdev || rc != -EBUSY) { DBG(CXT, ul_debugobj(cxt, "failed to setup device")); rc = -MNT_ERR_LOOPDEV; goto done; } DBG(CXT, ul_debugobj(cxt, "loopdev stolen...trying again")); } while (1); if (!rc) rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc)); if (!rc) { /* success */ cxt->flags |= MNT_FL_LOOPDEV_READY; if ((cxt->user_mountflags & MNT_MS_LOOP) && loopcxt_is_autoclear(&lc)) { /* * autoclear flag accepted by the kernel, don't store * the "loop=" option to mtab. */ cxt->user_mountflags &= ~MNT_MS_LOOP; mnt_optstr_remove_option(&cxt->fs->user_optstr, "loop"); } if (!(cxt->mountflags & MS_RDONLY) && loopcxt_is_readonly(&lc)) /* * mount planned read-write, but loopdev is read-only, * let's fix mount options... */ mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY); /* we have to keep the device open until mount(1), * otherwise it will be auto-cleared by kernel */ cxt->loopdev_fd = loopcxt_get_fd(&lc); loopcxt_set_fd(&lc, -1, 0); } done: loopcxt_deinit(&lc); return rc; }
int Assemble(struct supertype *st, char *mddev, int mdfd, mddev_ident_t ident, char *conffile, mddev_dev_t devlist, int readonly, int runstop, char *update, int verbose, int force) { /* * The task of Assemble is to find a collection of * devices that should (according to their superblocks) * form an array, and to give this collection to the MD driver. * In Linux-2.4 and later, this involves submitting a * SET_ARRAY_INFO ioctl with no arg - to prepare * the array - and then submit a number of * ADD_NEW_DISK ioctls to add disks into * the array. Finally RUN_ARRAY might * be submitted to start the array. * * Much of the work of Assemble is in finding and/or * checking the disks to make sure they look right. * * If mddev is not set, then scan must be set and we * read through the config file for dev+uuid mapping * We recurse, setting mddev, for each device that * - isn't running * - has a valid uuid (or any uuid if !uuidset) * * If mddev is set, we try to determine state of md. * check version - must be at least 0.90.0 * check kernel version. must be at least 2.4. * If not, we can possibly fall back on START_ARRAY * Try to GET_ARRAY_INFO. * If possible, give up * If not, try to STOP_ARRAY just to make sure * * If !uuidset and scan, look in conf-file for uuid * If not found, give up * If !devlist and scan and uuidset, get list of devs from conf-file * * For each device: * Check superblock - discard if bad * Check uuid (set if we don't have one) - discard if no match * Check superblock similarity if we have a superblock - discard if different * Record events, devicenum * This should give us a list of devices for the array * We should collect the most recent event number * * Count disks with recent enough event count * While force && !enough disks * Choose newest rejected disks, update event count * mark clean and rewrite superblock * If recent kernel: * SET_ARRAY_INFO * foreach device with recent events : ADD_NEW_DISK * if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY * If old kernel: * Check the device numbers in superblock are right * update superblock if any changes * START_ARRAY * */ int old_linux = 0; int vers; void *first_super = NULL, *super = NULL; struct { char *devname; unsigned int major, minor; unsigned int oldmajor, oldminor; long long events; int uptodate; int state; int raid_disk; int disk_nr; } *devices; int *best = NULL; /* indexed by raid_disk */ unsigned int bestcnt = 0; int devcnt = 0; unsigned int okcnt, sparecnt; unsigned int req_cnt; unsigned int i; int most_recent = 0; int chosen_drive; int change = 0; int inargv = 0; int start_partial_ok = force || devlist==NULL; unsigned int num_devs; mddev_dev_t tmpdev; struct mdinfo info; struct mddev_ident_s ident2; char *avail; int nextspare = 0; vers = md_get_version(mdfd); if (vers <= 0) { fprintf(stderr, Name ": %s appears not to be an md device.\n", mddev); return 1; } if (vers < 9000) { fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n" " Upgrade your kernel or try --build\n"); return 1; } if (get_linux_version() < 2004000) old_linux = 1; if (ioctl(mdfd, GET_ARRAY_INFO, &info.array)>=0) { fprintf(stderr, Name ": device %s already active - cannot assemble it\n", mddev); return 1; } ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */ /* * If any subdevs are listed, then any that don't * match ident are discarded. Remainder must all match and * become the array. * If no subdevs, then we scan all devices in the config file, but * there must be something in the identity */ if (!devlist && ident->uuid_set == 0 && ident->super_minor < 0 && ident->devices == NULL) { fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n", mddev); return 1; } if (devlist == NULL) devlist = conf_get_devs(conffile); else inargv = 1; tmpdev = devlist; num_devs = 0; while (tmpdev) { num_devs++; tmpdev = tmpdev->next; } devices = malloc(num_devs * sizeof(*devices)); if (!st && ident->st) st = ident->st; if (verbose>0) fprintf(stderr, Name ": looking for devices for %s\n", mddev); while ( devlist) { char *devname; int dfd; struct stat stb; struct supertype *tst = st; devname = devlist->devname; devlist = devlist->next; if (ident->devices && !match_oneof(ident->devices, devname)) { if ((inargv && verbose>=0) || verbose > 0) fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices); continue; } if (super) { free(super); super = NULL; } dfd = dev_open(devname, O_RDONLY|O_EXCL); if (dfd < 0) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": cannot open device %s: %s\n", devname, strerror(errno)); } else if (fstat(dfd, &stb)< 0) { /* Impossible! */ fprintf(stderr, Name ": fstat failed for %s: %s\n", devname, strerror(errno)); } else if ((stb.st_mode & S_IFMT) != S_IFBLK) { fprintf(stderr, Name ": %s is not a block device.\n", devname); } else if (!tst && (tst = guess_super(dfd)) == NULL) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": no recogniseable superblock\n"); } else if (tst->ss->load_super(tst,dfd, &super, NULL)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf( stderr, Name ": no RAID superblock on %s\n", devname); } else { tst->ss->getinfo_super(&info, &ident2, super); } if (dfd >= 0) close(dfd); if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) && (!super || same_uuid(info.uuid, ident->uuid, tst->ss->swapuuid)==0)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong uuid.\n", devname); continue; } if (ident->name[0] && (!super || strncmp(ident2.name, ident->name, 32)!=0)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong name.\n", devname); continue; } if (ident->super_minor != UnSet && (!super || ident->super_minor != info.array.md_minor)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong super-minor.\n", devname); continue; } if (ident->level != UnSet && (!super|| ident->level != info.array.level)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong raid level.\n", devname); continue; } if (ident->raid_disks != UnSet && (!super || ident->raid_disks!= info.array.raid_disks)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s requires wrong number of drives.\n", devname); continue; } /* If we are this far, then we are commited to this device. * If the super_block doesn't exist, or doesn't match others, * then we cannot continue */ if (!super) { fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", devname); free(first_super); return 1; } st = tst; /* commit to this format, if haven't already */ if (st->ss->compare_super(&first_super, super)) { fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", devname); free(super); free(first_super); return 1; } /* looks like a good enough match to update the super block if needed */ if (update) { /* prepare useful information in info structures */ struct stat stb2; fstat(mdfd, &stb2); info.array.md_minor = minor(stb2.st_rdev); if (strcmp(update, "uuid")==0 && !ident->uuid_set) { int rfd; if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || read(rfd, ident->uuid, 16) != 16) { *(__u32*)(ident->uuid) = random(); *(__u32*)(ident->uuid+1) = random(); *(__u32*)(ident->uuid+2) = random(); *(__u32*)(ident->uuid+3) = random(); } if (rfd >= 0) close(rfd); ident->uuid_set = 1; } memcpy(info.uuid, ident->uuid, 16); st->ss->update_super(&info, super, update, devname, verbose); dfd = dev_open(devname, O_RDWR|O_EXCL); if (dfd < 0) fprintf(stderr, Name ": Cannot open %s for superblock update\n", devname); else if (st->ss->store_super(st, dfd, super)) fprintf(stderr, Name ": Could not re-write superblock on %s.\n", devname); if (dfd >= 0) close(dfd); } if (verbose > 0) fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", devname, mddev, info.disk.raid_disk); devices[devcnt].devname = devname; devices[devcnt].major = major(stb.st_rdev); devices[devcnt].minor = minor(stb.st_rdev); devices[devcnt].oldmajor = info.disk.major; devices[devcnt].oldminor = info.disk.minor; devices[devcnt].events = info.events; devices[devcnt].raid_disk = info.disk.raid_disk; devices[devcnt].disk_nr = info.disk.number; devices[devcnt].uptodate = 0; devices[devcnt].state = info.disk.state; if (most_recent < devcnt) { if (devices[devcnt].events > devices[most_recent].events) most_recent = devcnt; } if (info.array.level == -4) /* with multipath, the raid_disk from the superblock is meaningless */ i = devcnt; else i = devices[devcnt].raid_disk; if (i+1 == 0) { if (nextspare < info.array.raid_disks) nextspare = info.array.raid_disks; i = nextspare++; } if (i < 10000) { if (i >= bestcnt) { unsigned int newbestcnt = i+10; int *newbest = malloc(sizeof(int)*newbestcnt); unsigned int c; for (c=0; c < newbestcnt; c++) if (c < bestcnt) newbest[c] = best[c]; else newbest[c] = -1; if (best)free(best); best = newbest; bestcnt = newbestcnt; } if (best[i] == -1 || devices[best[i]].events < devices[devcnt].events) best[i] = devcnt; } devcnt++; } if (super) free(super); super = NULL; if (update && strcmp(update, "byteorder")==0) st->minor_version = 90; if (devcnt == 0) { fprintf(stderr, Name ": no devices found for %s\n", mddev); free(first_super); return 1; } st->ss->getinfo_super(&info, &ident2, first_super); /* now we have some devices that might be suitable. * I wonder how many */ avail = malloc(info.array.raid_disks); memset(avail, 0, info.array.raid_disks); okcnt = 0; sparecnt=0; for (i=0; i< bestcnt ;i++) { int j = best[i]; int event_margin = 1; /* always allow a difference of '1' * like the kernel does */ if (j < 0) continue; /* note: we ignore error flags in multipath arrays * as they don't make sense */ if (info.array.level != -4) if (!(devices[j].state & (1<<MD_DISK_SYNC))) { if (!(devices[j].state & (1<<MD_DISK_FAULTY))) sparecnt++; continue; } if (devices[j].events+event_margin >= devices[most_recent].events) { devices[j].uptodate = 1; if (i < info.array.raid_disks) { okcnt++; avail[i]=1; } else sparecnt++; } } while (force && !enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt)) { /* Choose the newest best drive which is * not up-to-date, update the superblock * and add it. */ int fd; chosen_drive = -1; for (i=0; i<info.array.raid_disks && i < bestcnt; i++) { int j = best[i]; if (j>=0 && !devices[j].uptodate && devices[j].events > 0 && (chosen_drive < 0 || devices[j].events > devices[chosen_drive].events)) chosen_drive = j; } if (chosen_drive < 0) break; if (verbose >= 0) fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n", devices[chosen_drive].devname, devices[chosen_drive].raid_disk, (int)(devices[chosen_drive].events), (int)(devices[most_recent].events)); fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); if (fd < 0) { fprintf(stderr, Name ": Couldn't open %s for write - not updating\n", devices[chosen_drive].devname); devices[chosen_drive].events = 0; continue; } if (st->ss->load_super(st,fd, &super, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", devices[chosen_drive].devname); devices[chosen_drive].events = 0; continue; } info.events = devices[most_recent].events; st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose); if (st->ss->store_super(st, fd, super)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); devices[chosen_drive].events = 0; free(super); continue; } close(fd); devices[chosen_drive].events = devices[most_recent].events; devices[chosen_drive].uptodate = 1; avail[chosen_drive] = 1; okcnt++; free(super); } /* Now we want to look at the superblock which the kernel will base things on * and compare the devices that we think are working with the devices that the * superblock thinks are working. * If there are differences and --force is given, then update this chosen * superblock. */ chosen_drive = -1; super = NULL; for (i=0; chosen_drive < 0 && i<bestcnt; i++) { int j = best[i]; int fd; if (j<0) continue; if (!devices[j].uptodate) continue; chosen_drive = j; if ((fd=dev_open(devices[j].devname, O_RDONLY|O_EXCL))< 0) { fprintf(stderr, Name ": Cannot open %s: %s\n", devices[j].devname, strerror(errno)); return 1; } if (st->ss->load_super(st,fd, &super, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", devices[j].devname); return 1; } close(fd); } if (super == NULL) { fprintf(stderr, Name ": No suitable drives found for %s\n", mddev); return 1; } st->ss->getinfo_super(&info, &ident2, super); for (i=0; i<bestcnt; i++) { int j = best[i]; unsigned int desired_state; if (i < info.array.raid_disks) desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC); else desired_state = 0; if (j<0) continue; if (!devices[j].uptodate) continue; info.disk.number = devices[j].disk_nr; info.disk.raid_disk = i; info.disk.state = desired_state; if (devices[j].uptodate && st->ss->update_super(&info, super, "assemble", NULL, verbose)) { if (force) { if (verbose >= 0) fprintf(stderr, Name ": " "clearing FAULTY flag for device %d in %s for %s\n", j, mddev, devices[j].devname); change = 1; } else { if (verbose >= -1) fprintf(stderr, Name ": " "device %d in %s has wrong state in superblock, but %s seems ok\n", i, mddev, devices[j].devname); } } #if 0 if (!devices[j].uptodate && !(super.disks[i].state & (1 << MD_DISK_FAULTY))) { fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n", i, mddev); } #endif } if (force && okcnt == info.array.raid_disks-1) { /* FIXME check event count */ change += st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose); } if (change) { int fd; fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); if (fd < 0) { fprintf(stderr, Name ": Could open %s for write - cannot Assemble array.\n", devices[chosen_drive].devname); return 1; } if (st->ss->store_super(st, fd, super)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); return 1; } close(fd); } /* count number of in-sync devices according to the superblock. * We must have this number to start the array without -s or -R */ req_cnt = info.array.working_disks; /* Almost ready to actually *do* something */ if (!old_linux) { int rv; if ((vers % 100) >= 1) { /* can use different versions */ mdu_array_info_t inf; memset(&inf, 0, sizeof(inf)); inf.major_version = st->ss->major; inf.minor_version = st->minor_version; rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); } else rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); if (rv) { fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", mddev, strerror(errno)); return 1; } if (ident->bitmap_fd >= 0) { if (ioctl(mdfd, SET_BITMAP_FILE, ident->bitmap_fd) != 0) { fprintf(stderr, Name ": SET_BITMAP_FILE failed.\n"); return 1; } } /* First, add the raid disks, but add the chosen one last */ for (i=0; i<= bestcnt; i++) { int j; if (i < bestcnt) { j = best[i]; if (j == chosen_drive) continue; } else j = chosen_drive; if (j >= 0 /* && devices[j].uptodate */) { mdu_disk_info_t disk; memset(&disk, 0, sizeof(disk)); disk.major = devices[j].major; disk.minor = devices[j].minor; if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) { fprintf(stderr, Name ": failed to add %s to %s: %s\n", devices[j].devname, mddev, strerror(errno)); if (i < info.array.raid_disks || i == bestcnt) okcnt--; else sparecnt--; } else if (verbose > 0) fprintf(stderr, Name ": added %s to %s as %d\n", devices[j].devname, mddev, devices[j].raid_disk); } else if (verbose > 0 && i < info.array.raid_disks) fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", i, mddev); } if (runstop == 1 || (runstop == 0 && ( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) && (okcnt >= req_cnt || start_partial_ok) ))) { if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { if (verbose >= 0) { fprintf(stderr, Name ": %s has been started with %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (okcnt < info.array.raid_disks) fprintf(stderr, " (out of %d)", info.array.raid_disks); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); fprintf(stderr, ".\n"); } return 0; } fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", mddev, strerror(errno)); return 1; } if (runstop == -1) { fprintf(stderr, Name ": %s assembled from %d drive%s, but not started.\n", mddev, okcnt, okcnt==1?"":"s"); return 0; } if (verbose >= 0) { fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); if (!enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt)) fprintf(stderr, " - not enough to start the array.\n"); else { if (req_cnt == info.array.raid_disks) fprintf(stderr, " - need all %d to start it", req_cnt); else fprintf(stderr, " - need %d of %d to start", req_cnt, info.array.raid_disks); fprintf(stderr, " (use --run to insist).\n"); } } return 1; } else { /* The "chosen_drive" is a good choice, and if necessary, the superblock has * been updated to point to the current locations of devices. * so we can just start the array */ unsigned long dev; dev = makedev(devices[chosen_drive].major, devices[chosen_drive].minor); if (ioctl(mdfd, START_ARRAY, dev)) { fprintf(stderr, Name ": Cannot start array: %s\n", strerror(errno)); } } return 0; }
int main(int argc, char ** argv) { struct stat statbuf; struct swap_header_v1_2 *hdr; int i; unsigned long long maxpages; unsigned long long goodpages; unsigned long long sz; off_t offset; int force = 0; int version = 1; char *block_count = 0; char *pp; char *opt_label = NULL; unsigned char *uuid = NULL; #ifdef HAVE_LIBUUID const char *opt_uuid = NULL; uuid_t uuid_dat; #endif program_name = (argc && *argv) ? argv[0] : "mkswap"; if ((pp = strrchr(program_name, '/')) != NULL) program_name = pp+1; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); if (argc == 2 && (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) { printf(_("%s (%s)\n"), program_name, PACKAGE_STRING); exit(0); } for (i=1; i<argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'c': check=1; break; case 'f': force=1; break; case 'p': pp = argv[i]+2; if (!*pp && i+1 < argc) pp = argv[++i]; if (isnzdigit(*pp)) user_pagesize = atoi(pp); else usage(); break; case 'L': pp = argv[i]+2; if (!*pp && i+1 < argc) pp = argv[++i]; opt_label = pp; break; case 'v': version = atoi(argv[i]+2); break; case 'U': #ifdef HAVE_LIBUUID opt_uuid = argv[i]+2; if (!*opt_uuid && i+1 < argc) opt_uuid = argv[++i]; #else fprintf(stderr, _("%1$s: warning: ignore -U (UUIDs are unsupported by %1$s)\n"), program_name); #endif break; default: usage(); } } else if (!device_name) { device_name = argv[i]; } else if (!block_count) { block_count = argv[i]; } else usage(); } if (version != 1) { fprintf(stderr, _("%s: does not support swapspace version %d.\n"), program_name, version); exit(EXIT_FAILURE); } #ifdef HAVE_LIBUUID if(opt_uuid) { if (uuid_parse(opt_uuid, uuid_dat) != 0) die(_("error: UUID parsing failed")); } else uuid_generate(uuid_dat); uuid = uuid_dat; #endif init_signature_page(); /* get pagesize */ atexit(deinit_signature_page); if (!device_name) { fprintf(stderr, _("%s: error: Nowhere to set up swap on?\n"), program_name); usage(); } if (block_count) { /* this silly user specified the number of blocks explicitly */ char *tmp = NULL; long long blks; errno = 0; blks = strtoll(block_count, &tmp, 0); if ((tmp == block_count) || (tmp && *tmp) || (errno != 0 && (blks == LLONG_MAX || blks == LLONG_MIN)) || blks < 0) usage(); PAGES = blks / (pagesize / 1024); } sz = get_size(device_name); if (!PAGES) { PAGES = sz; } else if (PAGES > sz && !force) { fprintf(stderr, _("%s: error: " "size %llu KiB is larger than device size %llu KiB\n"), program_name, PAGES*(pagesize/1024), sz*(pagesize/1024)); exit(1); } if (PAGES < MIN_GOODPAGES) { fprintf(stderr, _("%s: error: swap area needs to be at least %ld KiB\n"), program_name, (long)(MIN_GOODPAGES * pagesize/1024)); usage(); } #ifdef __linux__ if (get_linux_version() >= KERNEL_VERSION(2,3,4)) maxpages = UINT_MAX + 1ULL; else if (get_linux_version() >= KERNEL_VERSION(2,2,1)) maxpages = V1_MAX_PAGES; else #endif maxpages = V1_OLD_MAX_PAGES; if (PAGES > maxpages) { PAGES = maxpages; fprintf(stderr, _("%s: warning: truncating swap area to %llu KiB\n"), program_name, PAGES * pagesize / 1024); } if (stat(device_name, &statbuf) < 0) { perror(device_name); exit(EXIT_FAILURE); } if (S_ISBLK(statbuf.st_mode)) DEV = open(device_name, O_RDWR | O_EXCL); else DEV = open(device_name, O_RDWR); if (DEV < 0) { perror(device_name); exit(1); } /* Want a block device. Probably not /dev/hda or /dev/hdb. */ if (!S_ISBLK(statbuf.st_mode)) check=0; else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) { fprintf(stderr, _("%s: error: " "will not try to make swapdevice on '%s'\n"), program_name, device_name); exit(1); } else if (check_mount()) { fprintf(stderr, _("%s: error: " "%s is mounted; will not make swapspace.\n"), program_name, device_name); exit(1); } if (check) check_blocks(); zap_bootbits(DEV, device_name, force, S_ISBLK(statbuf.st_mode)); hdr = (struct swap_header_v1_2 *) signature_page; hdr->version = 1; hdr->last_page = PAGES - 1; hdr->nr_badpages = badpages; if (badpages > PAGES - MIN_GOODPAGES) die(_("Unable to set up swap-space: unreadable")); goodpages = PAGES - badpages - 1; printf(_("Setting up swapspace version 1, size = %llu KiB\n"), goodpages * pagesize / 1024); write_signature("SWAPSPACE2"); write_uuid_and_label(uuid, opt_label); offset = 1024; if (lseek(DEV, offset, SEEK_SET) != offset) die(_("unable to rewind swap-device")); if (write_all(DEV, (char *) signature_page + offset, pagesize - offset) == -1) { fprintf(stderr, _("%s: %s: unable to write signature page: %s"), program_name, device_name, strerror(errno)); exit(1); } /* * A subsequent swapon() will fail if the signature * is not actually on disk. (This is a kernel bug.) */ #ifdef HAVE_FSYNC if (fsync(DEV)) die(_("fsync failed")); #endif #ifdef HAVE_LIBSELINUX if (S_ISREG(statbuf.st_mode) && is_selinux_enabled() > 0) { security_context_t context_string; security_context_t oldcontext; context_t newcontext; if (fgetfilecon(DEV, &oldcontext) < 0) { if (errno != ENODATA) { fprintf(stderr, _("%s: %s: unable to obtain selinux file label: %s\n"), program_name, device_name, strerror(errno)); exit(1); } if (matchpathcon(device_name, statbuf.st_mode, &oldcontext)) die(_("unable to matchpathcon()")); } if (!(newcontext = context_new(oldcontext))) die(_("unable to create new selinux context")); if (context_type_set(newcontext, SELINUX_SWAPFILE_TYPE)) die(_("couldn't compute selinux context")); context_string = context_str(newcontext); if (strcmp(context_string, oldcontext)!=0) { if (fsetfilecon(DEV, context_string)) { fprintf(stderr, _("%s: unable to relabel %s to %s: %s\n"), program_name, device_name, context_string, strerror(errno)); exit(1); } } context_free(newcontext); freecon(oldcontext); } #endif return 0; }
int mnt_context_setup_loopdev(struct libmnt_context *cxt) { const char *backing_file; char *loopdev = NULL; size_t len; struct loopdev_cxt lc; int rc, lo_flags = 0; assert(cxt); assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); backing_file = mnt_fs_get_srcpath(cxt->fs); if (!backing_file) return -EINVAL; DBG(CXT, mnt_debug_h(cxt, "trying to setup loopdev for %s", backing_file)); if (cxt->mountflags & MS_RDONLY) { DBG(CXT, mnt_debug_h(cxt, "enabling READ-ONLY flag")); lo_flags |= LO_FLAGS_READ_ONLY; } loopcxt_init(&lc, 0); if ((cxt->user_mountflags & MNT_MS_LOOP) && mnt_fs_get_option(cxt->fs, "loop", &loopdev, &len) == 0 && loopdev) { char *tmp = strndup(loopdev, len); if (!tmp) rc = -ENOMEM; else { rc = loopcxt_set_device(&lc, tmp); free(tmp); } } /* since 2.6.37 we don't have to store backing filename to mtab * because kernel provides the name in /sys. */ if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) || !cxt->mtab_writable) { DBG(CXT, mnt_debug_h(cxt, "enabling AUTOCLEAR flag")); lo_flags |= LO_FLAGS_AUTOCLEAR; } do { /* found free device */ if (!loopdev) { rc = loopcxt_find_unused(&lc); if (rc) goto done; DBG(CXT, mnt_debug_h(cxt, "trying to use %s", loopcxt_get_device(&lc))); } /* set device attributes */ rc = loopcxt_set_backing_file(&lc, backing_file); if (rc) goto done; loopcxt_set_flags(&lc, lo_flags); /* setup the device */ rc = loopcxt_setup_device(&lc); if (!rc) break; /* success */ if (loopdev || rc != -EBUSY) { DBG(CXT, mnt_debug_h(cxt, "failed to setup device")); break; } DBG(CXT, mnt_debug_h(cxt, "loopdev stolen...trying again")); } while (1); if (!rc) rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc)); if (!rc) { /* success */ cxt->flags |= MNT_FL_LOOPDEV_READY; if ((cxt->user_mountflags & MNT_MS_LOOP) && loopcxt_is_autoclear(&lc)) /* * autoclear flag accepted by kernel, don't store * the "loop=" option to mtab. */ cxt->user_mountflags &= ~MNT_MS_LOOP; if (!(cxt->mountflags & MS_RDONLY) && loopcxt_is_readonly(&lc)) /* * mount planned read-write, but loopdev is read-only, * let's fix mount options... */ cxt->mountflags |= MS_RDONLY; /* we have to keep the device open until mount(1), * otherwise it will auto-cleared by kernel */ cxt->loopdev_fd = loopcxt_get_fd(&lc); loopcxt_set_fd(&lc, -1, 0); } done: loopcxt_deinit(&lc); return rc; }
/* * this has to be called after mnt_context_evaluate_permissions() */ static int fix_optstr(struct libmnt_context *cxt) { int rc = 0; char *next; char *name, *val; size_t namesz, valsz; struct libmnt_fs *fs; #ifdef HAVE_LIBSELINUX int se_fix = 0, se_rem = 0; #endif assert(cxt); assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!cxt) return -EINVAL; if (!cxt->fs || (cxt->flags & MNT_FL_MOUNTOPTS_FIXED)) return 0; DBG(CXT, mnt_debug_h(cxt, "mount: fixing optstr")); fs = cxt->fs; /* The propagation flags should not be used together with any other * flags (except MS_REC and MS_SILENT) */ if (cxt->mountflags & MS_PROPAGATION) cxt->mountflags &= (MS_PROPAGATION | MS_REC | MS_SILENT); if (!mnt_optstr_get_option(fs->user_optstr, "user", &val, &valsz)) { if (val) { cxt->orig_user = strndup(val, valsz); if (!cxt->orig_user) { rc = -ENOMEM; goto done; } } cxt->flags |= MNT_FL_SAVED_USER; } /* * Sync mount options with mount flags */ rc = mnt_optstr_apply_flags(&fs->vfs_optstr, cxt->mountflags, mnt_get_builtin_optmap(MNT_LINUX_MAP)); if (rc) goto done; rc = mnt_optstr_apply_flags(&fs->user_optstr, cxt->user_mountflags, mnt_get_builtin_optmap(MNT_USERSPACE_MAP)); if (rc) goto done; next = fs->fs_optstr; #ifdef HAVE_LIBSELINUX if (!is_selinux_enabled()) /* Always remove SELinux garbage if SELinux disabled */ se_rem = 1; else if (cxt->mountflags & MS_REMOUNT) /* * Linux kernel < 2.6.39 does not allow to remount with any * selinux specific mount options. * * Kernel 2.6.39 commits: ff36fe2c845cab2102e4826c1ffa0a6ebf487c65 * 026eb167ae77244458fa4b4b9fc171209c079ba7 * fix this odd behavior, so we don't have to care about it in * userspace. */ se_rem = get_linux_version() < KERNEL_VERSION(2, 6, 39); else /* For normal mount we have translate the contexts */ se_fix = 1; #endif while (!mnt_optstr_next_option(&next, &name, &namesz, &val, &valsz)) { if (namesz == 3 && !strncmp(name, "uid", 3)) rc = mnt_optstr_fix_uid(&fs->fs_optstr, val, valsz, &next); else if (namesz == 3 && !strncmp(name, "gid", 3)) rc = mnt_optstr_fix_gid(&fs->fs_optstr, val, valsz, &next); #ifdef HAVE_LIBSELINUX else if ((se_rem || se_fix) && namesz >= 7 && (!strncmp(name, "context", 7) || !strncmp(name, "fscontext", 9) || !strncmp(name, "defcontext", 10) || !strncmp(name, "rootcontext", 11) || !strncmp(name, "seclabel", 8))) { if (se_rem) { /* remove context= option */ next = name; rc = mnt_optstr_remove_option_at(&fs->fs_optstr, name, val ? val + valsz : name + namesz); } else if (se_fix && val && valsz) /* translate selinux contexts */ rc = mnt_optstr_fix_secontext(&fs->fs_optstr, val, valsz, &next); } #endif if (rc) goto done; } if (!rc && cxt->user_mountflags & MNT_MS_USER) rc = mnt_optstr_fix_user(&fs->user_optstr); /* refresh merged optstr */ free(fs->optstr); fs->optstr = NULL; fs->optstr = mnt_fs_strdup_options(fs); done: cxt->flags |= MNT_FL_MOUNTOPTS_FIXED; DBG(CXT, mnt_debug_h(cxt, "fixed options [rc=%d]: " "vfs: '%s' fs: '%s' user: '******', optstr: '%s'", rc, fs->vfs_optstr, fs->fs_optstr, fs->user_optstr, fs->optstr)); if (rc) rc = -MNT_ERR_MOUNTOPT; return rc; }
int main(int argc, char **argv) { struct stat statbuf; struct swap_header_v1_2 *hdr; int c; unsigned long long maxpages; unsigned long long goodpages; unsigned long long sz; off_t offset; int force = 0; int version = 1; char *block_count = 0; char *opt_label = NULL; unsigned char *uuid = NULL; #ifdef HAVE_LIBUUID const char *opt_uuid = NULL; uuid_t uuid_dat; #endif static const struct option longopts[] = { { "check", no_argument, 0, 'c' }, { "force", no_argument, 0, 'f' }, { "pagesize", required_argument, 0, 'p' }, { "label", required_argument, 0, 'L' }, { "swapversion", required_argument, 0, 'v' }, { "uuid", required_argument, 0, 'U' }, { "version", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { NULL, 0, 0, 0 } }; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); while((c = getopt_long(argc, argv, "cfp:L:v:U:Vh", longopts, NULL)) != -1) { switch (c) { case 'c': check=1; break; case 'f': force=1; break; case 'p': user_pagesize = strtou32_or_err(optarg, _("parsing page size failed")); break; case 'L': opt_label = optarg; break; case 'v': version = strtos32_or_err(optarg, _("parsing version number failed")); break; case 'U': #ifdef HAVE_LIBUUID opt_uuid = optarg; #else warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"), program_invocation_short_name); #endif break; case 'V': printf(UTIL_LINUX_VERSION); exit(EXIT_SUCCESS); case 'h': usage(stdout); default: usage(stderr); } } if (optind < argc) device_name = argv[optind++]; if (optind < argc) block_count = argv[optind++]; if (optind != argc) { warnx(_("only one device argument is currently supported")); usage(stderr); } if (version != 1) errx(EXIT_FAILURE, _("swapspace version %d is not supported"), version); #ifdef HAVE_LIBUUID if(opt_uuid) { if (uuid_parse(opt_uuid, uuid_dat) != 0) errx(EXIT_FAILURE, _("error: parsing UUID failed")); } else uuid_generate(uuid_dat); uuid = uuid_dat; #endif init_signature_page(); /* get pagesize */ if (!device_name) { warnx(_("error: Nowhere to set up swap on?")); usage(stderr); } if (block_count) { /* this silly user specified the number of blocks explicitly */ uint64_t blks = strtou64_or_err(block_count, _("invalid block count argument")); PAGES = blks / (pagesize / 1024); } sz = get_size(device_name); if (!PAGES) PAGES = sz; else if (PAGES > sz && !force) { errx(EXIT_FAILURE, _("error: " "size %llu KiB is larger than device size %llu KiB"), PAGES*(pagesize/1024), sz*(pagesize/1024)); } if (PAGES < MIN_GOODPAGES) { warnx(_("error: swap area needs to be at least %ld KiB"), (long)(MIN_GOODPAGES * pagesize/1024)); usage(stderr); } #ifdef __linux__ if (get_linux_version() >= KERNEL_VERSION(2,3,4)) maxpages = UINT_MAX + 1ULL; else if (get_linux_version() >= KERNEL_VERSION(2,2,1)) maxpages = V1_MAX_PAGES; else #endif maxpages = V1_OLD_MAX_PAGES; if (PAGES > maxpages) { PAGES = maxpages; warnx(_("warning: truncating swap area to %llu KiB"), PAGES * pagesize / 1024); } if (is_mounted(device_name)) errx(EXIT_FAILURE, _("error: " "%s is mounted; will not make swapspace"), device_name); if (stat(device_name, &statbuf) < 0) { perror(device_name); exit(EXIT_FAILURE); } if (S_ISBLK(statbuf.st_mode)) DEV = open(device_name, O_RDWR | O_EXCL); else DEV = open(device_name, O_RDWR); if (DEV < 0) { perror(device_name); exit(EXIT_FAILURE); } if (!S_ISBLK(statbuf.st_mode)) check=0; else if (blkdev_is_misaligned(DEV)) warnx(_("warning: %s is misaligned"), device_name); if (check) check_blocks(); wipe_device(DEV, device_name, force); hdr = (struct swap_header_v1_2 *) signature_page; hdr->version = 1; hdr->last_page = PAGES - 1; hdr->nr_badpages = badpages; if (badpages > PAGES - MIN_GOODPAGES) errx(EXIT_FAILURE, _("Unable to set up swap-space: unreadable")); goodpages = PAGES - badpages - 1; printf(_("Setting up swapspace version 1, size = %llu KiB\n"), goodpages * pagesize / 1024); write_signature("SWAPSPACE2"); write_uuid_and_label(uuid, opt_label); offset = 1024; if (lseek(DEV, offset, SEEK_SET) != offset) errx(EXIT_FAILURE, _("unable to rewind swap-device")); if (write_all(DEV, (char *) signature_page + offset, pagesize - offset) == -1) err(EXIT_FAILURE, _("%s: unable to write signature page"), device_name); #ifdef HAVE_LIBSELINUX if (S_ISREG(statbuf.st_mode) && is_selinux_enabled() > 0) { security_context_t context_string; security_context_t oldcontext; context_t newcontext; if (fgetfilecon(DEV, &oldcontext) < 0) { if (errno != ENODATA) err(EXIT_FAILURE, _("%s: unable to obtain selinux file label"), device_name); if (matchpathcon(device_name, statbuf.st_mode, &oldcontext)) errx(EXIT_FAILURE, _("unable to matchpathcon()")); } if (!(newcontext = context_new(oldcontext))) errx(EXIT_FAILURE, _("unable to create new selinux context")); if (context_type_set(newcontext, SELINUX_SWAPFILE_TYPE)) errx(EXIT_FAILURE, _("couldn't compute selinux context")); context_string = context_str(newcontext); if (strcmp(context_string, oldcontext)!=0) { if (fsetfilecon(DEV, context_string)) err(EXIT_FAILURE, _("unable to relabel %s to %s"), device_name, context_string); } context_free(newcontext); freecon(oldcontext); } #endif /* * A subsequent swapon() will fail if the signature * is not actually on disk. (This is a kernel bug.) * The fsync() in close_fd() will take care of writing. */ if (close_fd(DEV) != 0) err(EXIT_FAILURE, _("write failed")); return EXIT_SUCCESS; }
int main(int argc, char * argv[]) { int read_value = 0xbeefbeef, write_value = 0xbeefbeef, bomb_value = 0xbeefbeef; int read_set, write_set, bomb_set, set; char * devname; int fd; blkelv_ioctl_arg_t elevator; read_set = write_set = bomb_set = set = 0; setlocale(LC_MESSAGES, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); for (;;) { int opt; opt = getopt(argc, argv, "r:w:b:hv"); if (opt == -1) break; switch (opt) { case 'r': read_value = atoi(optarg); read_set = set = 1; break; case 'w': write_value = atoi(optarg); write_set = set = 1; break; case 'b': bomb_value = atoi(optarg); bomb_set = set = 1; break; case 'h': usage(), exit(0); case 'v': version(), exit(0); default: usage(), exit(1); } } if (optind >= argc) fprintf(stderr, _("missing blockdevice, use -h for help\n")), exit(1); while (optind < argc) { devname = argv[optind++]; fd = open(devname, O_RDONLY|O_NONBLOCK); if (fd < 0) { perror("open"); break; } /* mmj: If we get EINVAL it's not a 2.4 kernel, so warn about that and exit. It should return ENOTTY however, so check for that as well in case it gets corrected in the future */ if (ioctl(fd, BLKELVGET, &elevator) < 0) { int errsv = errno; perror("ioctl get"); if ((errsv == EINVAL || errsv == ENOTTY) && get_linux_version() >= KERNEL_VERSION(2,5,58)) { fprintf(stderr, _("\nelvtune is only useful on older " "kernels;\nfor 2.6 use IO scheduler " "sysfs tunables instead..\n")); } break; } if (set) { if (read_set) elevator.read_latency = read_value; if (write_set) elevator.write_latency = write_value; if (bomb_set) elevator.max_bomb_segments = bomb_value; if (ioctl(fd, BLKELVSET, &elevator) < 0) { perror("ioctl set"); break; } if (ioctl(fd, BLKELVGET, &elevator) < 0) { perror("ioctl reget"); break; } } printf("\n%s elevator ID\t\t%d\n", devname, elevator.queue_ID); printf("\tread_latency:\t\t%d\n", elevator.read_latency); printf("\twrite_latency:\t\t%d\n", elevator.write_latency); printf("\tmax_bomb_segments:\t%d\n\n", elevator.max_bomb_segments); if (close(fd) < 0) { perror("close"); break; } } return 0; }