2 * A swapon(8)/swapoff(8) for Linux 0.99.
12 #include <sys/types.h>
20 #include "swap_constants.h"
23 #include "pathnames.h"
24 #include "swapheader.h"
26 #define PATH_MKSWAP "/sbin/mkswap"
28 #ifdef HAVE_SYS_SWAP_H
29 # include <sys/swap.h>
32 #ifndef SWAPON_HAS_TWO_ARGS
33 /* libc is insane, let's call the kernel */
34 # include <sys/syscall.h>
35 # define swapon(path, flags) syscall(SYS_swapon, path, flags)
36 # define swapoff(path) syscall(SYS_swapoff, path)
39 #define streq(s, t) (strcmp ((s), (t)) == 0)
44 #define MAX_PAGESIZE (64 * 1024)
51 #define SWAP_SIGNATURE "SWAPSPACE2"
52 #define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
55 int priority = -1; /* non-prioritized swap by default */
57 /* If true, don't complain if the device/file doesn't exist */
64 static struct option longswaponopts[] = {
66 { "priority", required_argument, 0, 'p' },
67 { "ifexists", 0, 0, 'e' },
68 { "summary", 0, 0, 's' },
69 { "fixpgsz", 0, 0, 'f' },
70 /* also for swapoff */
72 { "help", 0, 0, 'h' },
73 { "verbose", 0, 0, 'v' },
74 { "version", 0, 0, 'V' },
78 static struct option *longswapoffopts = &longswaponopts[4];
80 static int cannot_find(const char *special);
82 #define PRINT_USAGE_SPECIAL(_fp) \
84 "The <special> parameter:\n" \
85 " {-L label | LABEL=label} LABEL of device to be used\n" \
86 " {-U uuid | UUID=uuid} UUID of device to be used\n" \
87 " <device> name of device to be used\n" \
88 " <file> name of file to be used\n\n"))
91 swapon_usage(FILE *fp, int n) {
92 fprintf(fp, _("\nUsage:\n"
93 " %1$s -a [-e] [-v] [-f] enable all swaps from /etc/fstab\n"
94 " %1$s [-p priority] [-v] [-f] <special> enable given swap\n"
95 " %1$s -s display swap usage summary\n"
96 " %1$s -h display help\n"
97 " %1$s -V display version\n\n"), progname);
99 PRINT_USAGE_SPECIAL(fp);
105 swapoff_usage(FILE *fp, int n) {
106 fprintf(fp, _("\nUsage:\n"
107 " %1$s -a [-v] disable all swaps\n"
108 " %1$s [-v] <special> disable given swap\n"
109 " %1$s -h display help\n"
110 " %1$s -V display version\n\n"), progname);
112 PRINT_USAGE_SPECIAL(fp);
118 * contents of /proc/swaps
121 static char **swapFiles; /* array of swap file and partition names */
124 read_proc_swaps(void) {
132 swaps = fopen(_PATH_PROC_SWAPS, "r");
134 return; /* nothing wrong */
136 /* skip the first line */
137 if (!fgets(line, sizeof(line), swaps)) {
138 /* do not whine about an empty file */
140 warn(_("%s: unexpected file format"), _PATH_PROC_SWAPS);
144 /* make sure the first line is the header */
145 if (line[0] != '\0' && strncmp(line, "Filename\t", 9))
146 goto valid_first_line;
148 while (fgets(line, sizeof(line), swaps)) {
151 * Cut the line "swap_device ... more info" after device.
152 * This will fail with names with embedded spaces.
154 for (p = line; *p && *p != ' '; p++);
157 q = realloc(swapFiles, (numSwaps+1) * sizeof(*swapFiles));
162 swapFiles[numSwaps++] = strdup(line);
168 is_in_proc_swaps(const char *fname) {
171 for (i = 0; i < numSwaps; i++)
172 if (swapFiles[i] && !strcmp(fname, swapFiles[i]))
178 display_summary(void)
183 if ((swaps = fopen(_PATH_PROC_SWAPS, "r")) == NULL) {
184 warn(_("%s: open failed"), _PATH_PROC_SWAPS);
188 while (fgets(line, sizeof(line), swaps))
197 swap_reinitialize(const char *device) {
198 const char *label = fsprobe_get_label_by_devname(device);
199 const char *uuid = fsprobe_get_uuid_by_devname(device);
205 warnx(_("%s: reinitializing the swap."), device);
207 switch((pid=fork())) {
208 case -1: /* fork error */
209 warn(_("fork failed"));
213 cmd[idx++] = PATH_MKSWAP;
214 if (label && *label) {
216 cmd[idx++] = (char *) label;
220 cmd[idx++] = (char *) uuid;
222 cmd[idx++] = (char *) device;
225 err(EXIT_FAILURE, _("execv failed"));
227 default: /* parent */
229 if ((ret = waitpid(pid, &status, 0)) < 0
233 warn(_("waitpid failed"));
238 /* mkswap returns: 0=suss, 1=error */
239 if (WIFEXITED(status) && WEXITSTATUS(status)==0)
242 return -1; /* error */
246 swap_rewrite_signature(const char *devname, unsigned int pagesize)
250 fd = open(devname, O_WRONLY);
252 warn(_("%s: open failed"), devname);
256 if (lseek(fd, pagesize - SWAP_SIGNATURE_SZ, SEEK_SET) < 0) {
257 warn(_("%s: lseek failed"), devname);
261 if (write(fd, (void *) SWAP_SIGNATURE,
262 SWAP_SIGNATURE_SZ) != SWAP_SIGNATURE_SZ) {
263 warn(_("%s: write signature failed"), devname);
274 swap_detect_signature(const char *buf, int *sig)
276 if (memcmp(buf, "SWAP-SPACE", 10) == 0 ||
277 memcmp(buf, "SWAPSPACE2", 10) == 0)
278 *sig = SIG_SWAPSPACE;
280 else if (memcmp(buf, "S1SUSPEND", 9) == 0 ||
281 memcmp(buf, "S2SUSPEND", 9) == 0 ||
282 memcmp(buf, "ULSUSPEND", 9) == 0 ||
283 memcmp(buf, "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8) == 0)
284 *sig = SIG_SWSUSPEND;
292 swap_get_header(int fd, int *sig, unsigned int *pagesize)
301 buf = malloc(MAX_PAGESIZE);
305 datasz = read(fd, buf, MAX_PAGESIZE);
306 if (datasz == (ssize_t) -1)
309 for (page = 0x1000; page <= MAX_PAGESIZE; page <<= 1) {
310 /* skip 32k pagesize since this does not seem to
314 /* the smallest swap area is PAGE_SIZE*10, it means
315 * 40k, that's less than MAX_PAGESIZE */
316 if (datasz < (page - SWAP_SIGNATURE_SZ))
318 if (swap_detect_signature(buf + page - SWAP_SIGNATURE_SZ, sig)) {
331 /* returns real size of swap space */
333 swap_get_size(const char *hdr, const char *devname, unsigned int pagesize)
335 unsigned int last_page = 0;
336 int swap_version = 0;
338 struct swap_header_v1_2 *s;
340 s = (struct swap_header_v1_2 *) hdr;
341 if (s->version == 1) {
343 last_page = s->last_page;
344 } else if (swab32(s->version) == 1) {
347 last_page = swab32(s->last_page);
350 warnx(_("%s: found %sswap v%d signature string"
351 " for %d KiB PAGE_SIZE\n"),
353 flip ? "other-endian " : "",
357 return (last_page + 1) * pagesize;
361 swapon_checks(const char *special)
366 unsigned int pagesize;
367 unsigned long long devsize = 0;
369 if (stat(special, &st) < 0) {
370 warn(_("%s: stat failed"), special);
374 /* people generally dislike this warning - now it is printed
375 only when `verbose' is set */
377 int permMask = (S_ISBLK(st.st_mode) ? 07007 : 07077);
379 if ((st.st_mode & permMask) != 0)
380 warnx(_("%s: insecure permissions %04o, %04o suggested."),
381 special, st.st_mode & 07777,
385 /* test for holes by LBT */
386 if (S_ISREG(st.st_mode)) {
387 if (st.st_blocks * 512 < st.st_size) {
388 warnx(_("%s: skipping - it appears to have holes."),
392 devsize = st.st_size;
395 fd = open(special, O_RDONLY);
397 warn(_("%s: open failed"), special);
401 if (S_ISBLK(st.st_mode) && blkdev_get_size(fd, &devsize)) {
402 warn(_("%s: get size failed"), special);
406 hdr = swap_get_header(fd, &sig, &pagesize);
408 warn(_("%s: read swap header failed"), special);
412 if (sig == SIG_SWAPSPACE && pagesize) {
413 unsigned long long swapsize =
414 swap_get_size(hdr, special, pagesize);
416 warnx("%s: pagesize=%d, swapsize=%llu, devsize=%llu",
417 special, pagesize, swapsize, devsize);
419 if (swapsize > devsize) {
421 warnx(_("%s: last_page 0x%08llx is larger"
422 " than actual size of swapspace"),
424 } else if (getpagesize() != pagesize) {
426 warnx(_("%s: swap format pagesize does not match."),
428 if (swap_reinitialize(special) < 0)
431 warnx(_("%s: swap format pagesize does not match. "
432 "(Use --fixpgsz to reinitialize it.)"),
435 } else if (sig == SIG_SWSUSPEND) {
436 /* We have to reinitialize swap with old (=useless) software suspend
437 * data. The problem is that if we don't do it, then we get data
438 * corruption the next time an attempt at unsuspending is made.
440 warnx(_("%s: software suspend data detected. "
441 "Rewriting the swap signature."),
443 if (swap_rewrite_signature(special, pagesize) < 0)
458 do_swapon(const char *orig_special, int prio, int canonic) {
460 const char *special = orig_special;
464 printf(_("%s on %s\n"), progname, orig_special);
467 special = fsprobe_get_devname_by_spec(orig_special);
469 return cannot_find(orig_special);
472 if (swapon_checks(special))
475 #ifdef SWAP_FLAG_PREFER
477 if (prio > SWAP_FLAG_PRIO_MASK)
478 prio = SWAP_FLAG_PRIO_MASK;
479 flags = SWAP_FLAG_PREFER
480 | ((prio & SWAP_FLAG_PRIO_MASK)
481 << SWAP_FLAG_PRIO_SHIFT);
484 status = swapon(special, flags);
486 warn(_("%s: swapon failed"), orig_special);
492 cannot_find(const char *special) {
493 warnx(_("cannot find the device for %s"), special);
498 swapon_by_label(const char *label, int prio) {
499 const char *special = fsprobe_get_devname_by_label(label);
500 return special ? do_swapon(special, prio, CANONIC) : cannot_find(label);
504 swapon_by_uuid(const char *uuid, int prio) {
505 const char *special = fsprobe_get_devname_by_uuid(uuid);
506 return special ? do_swapon(special, prio, CANONIC) : cannot_find(uuid);
510 do_swapoff(const char *orig_special, int quiet, int canonic) {
511 const char *special = orig_special;
514 printf(_("%s on %s\n"), progname, orig_special);
517 special = fsprobe_get_devname_by_spec(orig_special);
519 return cannot_find(orig_special);
522 if (swapoff(special) == 0)
523 return 0; /* success */
526 errx(EXIT_FAILURE, _("Not superuser."));
528 if (!quiet || errno == ENOMEM)
529 warn(_("%s: swapoff failed"), orig_special);
535 swapoff_by_label(const char *label, int quiet) {
536 const char *special = fsprobe_get_devname_by_label(label);
537 return special ? do_swapoff(special, quiet, CANONIC) : cannot_find(label);
541 swapoff_by_uuid(const char *uuid, int quiet) {
542 const char *special = fsprobe_get_devname_by_uuid(uuid);
543 return special ? do_swapoff(special, quiet, CANONIC) : cannot_find(uuid);
549 struct mntent *fstab;
554 fp = setmntent(_PATH_MNTTAB, "r");
556 err(2, _("%s: open failed"), _PATH_MNTTAB);
558 while ((fstab = getmntent(fp)) != NULL) {
564 if (!streq(fstab->mnt_type, MNTTYPE_SWAP))
567 opts = strdup(fstab->mnt_opts);
569 for (opt = strtok(opts, ","); opt != NULL;
570 opt = strtok(NULL, ",")) {
571 if (strncmp(opt, "pri=", 4) == 0)
573 if (strcmp(opt, "noauto") == 0)
581 special = fsprobe_get_devname_by_spec(fstab->mnt_fsname);
584 status |= cannot_find(fstab->mnt_fsname);
588 if (!is_in_proc_swaps(special) &&
589 (!ifexists || !access(special, R_OK)))
590 status |= do_swapon(special, pri, CANONIC);
592 free((void *) special);
599 static const char **llist = NULL;
601 static const char **ulist = NULL;
604 static void addl(const char *label) {
605 llist = (const char **) realloc(llist, (++llct) * sizeof(char *));
608 llist[llct-1] = label;
611 static void addu(const char *uuid) {
612 ulist = (const char **) realloc(ulist, (++ulct) * sizeof(char *));
615 ulist[ulct-1] = uuid;
619 main_swapon(int argc, char *argv[]) {
623 while ((c = getopt_long(argc, argv, "ahefp:svVL:U:",
624 longswaponopts, NULL)) != -1) {
630 swapon_usage(stdout, 0);
632 case 'p': /* priority */
633 priority = atoi(optarg);
641 case 'e': /* ifexists */
647 case 's': /* status report */
648 status = display_summary();
650 case 'v': /* be chatty */
653 case 'V': /* version */
654 printf("%s: (%s)\n", progname, PACKAGE_STRING);
660 swapon_usage(stderr, 1);
665 if (!all && !llct && !ulct && *argv == NULL)
666 swapon_usage(stderr, 2);
668 if (ifexists && (!all || strcmp(progname, "swapon")))
669 swapon_usage(stderr, 1);
672 status |= swapon_all();
674 for (i = 0; i < llct; i++)
675 status |= swapon_by_label(llist[i], priority);
677 for (i = 0; i < ulct; i++)
678 status |= swapon_by_uuid(ulist[i], priority);
680 while (*argv != NULL)
681 status |= do_swapon(*argv++, priority, !CANONIC);
687 main_swapoff(int argc, char *argv[]) {
689 struct mntent *fstab;
693 while ((c = getopt_long(argc, argv, "ahvVL:U:",
694 longswapoffopts, NULL)) != -1) {
700 swapoff_usage(stdout, 0);
702 case 'v': /* be chatty */
705 case 'V': /* version */
706 printf("%s (%s)\n", progname, PACKAGE_STRING);
718 swapoff_usage(stderr, 1);
723 if (!all && !llct && !ulct && *argv == NULL)
724 swapoff_usage(stderr, 2);
727 * swapoff any explicitly given arguments.
728 * Complain in case the swapoff call fails.
730 for (i = 0; i < llct; i++)
731 status |= swapoff_by_label(llist[i], !QUIET);
733 for (i = 0; i < ulct; i++)
734 status |= swapoff_by_uuid(ulist[i], !QUIET);
736 while (*argv != NULL)
737 status |= do_swapoff(*argv++, !QUIET, !CANONIC);
741 * In case /proc/swaps exists, unswap stuff listed there.
742 * We are quiet but report errors in status.
743 * Errors might mean that /proc/swaps
744 * exists as ordinary file, not in procfs.
745 * do_swapoff() exits immediately on EPERM.
748 for(i=0; i<numSwaps; i++)
749 status |= do_swapoff(swapFiles[i], QUIET, CANONIC);
752 * Unswap stuff mentioned in /etc/fstab.
753 * Probably it was unmounted already, so errors are not bad.
754 * Doing swapoff -a twice should not give error messages.
756 fp = setmntent(_PATH_MNTTAB, "r");
758 err(2, _("%s: open failed"), _PATH_MNTTAB);
760 while ((fstab = getmntent(fp)) != NULL) {
763 if (!streq(fstab->mnt_type, MNTTYPE_SWAP))
766 special = fsprobe_get_devname_by_spec(fstab->mnt_fsname);
770 if (!is_in_proc_swaps(special))
771 do_swapoff(special, QUIET, CANONIC);
780 main(int argc, char *argv[]) {
782 setlocale(LC_ALL, "");
783 bindtextdomain(PACKAGE, LOCALEDIR);
786 progname = program_invocation_short_name;
788 char *p = strrchr(argv[0], '/');
789 progname = p ? p+1 : argv[0];
792 if (streq(progname, "swapon"))
793 return main_swapon(argc, argv);
795 return main_swapoff(argc, argv);