]> git.ipfire.org Git - thirdparty/util-linux.git/blame - mount/swapon.c
swapon: cleanup man page
[thirdparty/util-linux.git] / mount / swapon.c
CommitLineData
6dbe3af9
KZ
1/*
2 * A swapon(8)/swapoff(8) for Linux 0.99.
6dbe3af9 3 */
fd6b7a7f
KZ
4#include <stdlib.h>
5#include <stdio.h>
6#include <getopt.h>
7#include <string.h>
8#include <mntent.h>
9#include <errno.h>
5c36a0eb 10#include <sys/stat.h>
ffa63a3d 11#include <unistd.h>
6274b987
KC
12#include <sys/types.h>
13#include <sys/wait.h>
14#include <fcntl.h>
3399a218 15#include <stdint.h>
d51d05d3 16#include <err.h>
81772d3c 17
3399a218
MK
18#include "bitops.h"
19#include "blkdev.h"
5c36a0eb 20#include "swap_constants.h"
7eda085c 21#include "nls.h"
0964afe1 22#include "fsprobe.h"
4e270e3f 23#include "pathnames.h"
3399a218 24#include "swapheader.h"
167eaed7 25
6274b987
KC
26#define PATH_MKSWAP "/sbin/mkswap"
27
ffa63a3d
MF
28#ifdef HAVE_SYS_SWAP_H
29# include <sys/swap.h>
30#endif
31
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)
37#endif
38
fd6b7a7f
KZ
39#define streq(s, t) (strcmp ((s), (t)) == 0)
40
63cccae4 41#define QUIET 1
12ac2bbe 42#define CANONIC 1
63cccae4 43
3399a218
MK
44#define MAX_PAGESIZE (64 * 1024)
45
e8be80dd
KZ
46enum {
47 SIG_SWAPSPACE = 1,
48 SIG_SWSUSPEND
49};
50
617d8a3b
KZ
51#define SWAP_SIGNATURE "SWAPSPACE2"
52#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
53
81772d3c 54int all;
726f69e2 55int priority = -1; /* non-prioritized swap by default */
6dbe3af9 56
95f1bdee 57/* If true, don't complain if the device/file doesn't exist */
81772d3c
KZ
58int ifexists;
59
60int verbose;
61char *progname;
95f1bdee 62
63cccae4
KZ
63static struct option longswaponopts[] = {
64 /* swapon only */
65 { "priority", required_argument, 0, 'p' },
95f1bdee 66 { "ifexists", 0, 0, 'e' },
63cccae4
KZ
67 { "summary", 0, 0, 's' },
68 /* also for swapoff */
69 { "all", 0, 0, 'a' },
70 { "help", 0, 0, 'h' },
71 { "verbose", 0, 0, 'v' },
72 { "version", 0, 0, 'V' },
73 { NULL, 0, 0, 0 }
6dbe3af9
KZ
74};
75
1581e22c 76static struct option *longswapoffopts = &longswaponopts[3];
63cccae4 77
12ac2bbe
KZ
78static int cannot_find(const char *special);
79
240e20b5
KZ
80#define PRINT_USAGE_SPECIAL(_fp) \
81 fprintf(_fp, _( \
d08a2b44 82 "The <special> parameter:\n" \
ce6479e2
BS
83 " {-L label | LABEL=label} LABEL of device to be used\n" \
84 " {-U uuid | UUID=uuid} UUID of device to be used\n" \
85 " <device> name of device to be used\n" \
86 " <file> name of file to be used\n\n"))
240e20b5 87
6dbe3af9 88static void
63cccae4 89swapon_usage(FILE *fp, int n) {
240e20b5
KZ
90 fprintf(fp, _("\nUsage:\n"
91 " %1$s -a [-e] [-v] enable all swaps from /etc/fstab\n"
ce6479e2 92 " %1$s [-p priority] [-v] <special> enable given swap\n"
d08a2b44
KZ
93 " %1$s -s display swap usage summary\n"
94 " %1$s -h display help\n"
95 " %1$s -V display version\n\n"), progname);
240e20b5
KZ
96
97 PRINT_USAGE_SPECIAL(fp);
98
63cccae4
KZ
99 exit(n);
100}
101
102static void
103swapoff_usage(FILE *fp, int n) {
240e20b5 104 fprintf(fp, _("\nUsage:\n"
ce6479e2
BS
105 " %1$s -a [-v] disable all swaps\n"
106 " %1$s [-v] <special> disable given swap\n"
107 " %1$s -h display help\n"
108 " %1$s -V display version\n\n"), progname);
240e20b5
KZ
109
110 PRINT_USAGE_SPECIAL(fp);
111
63cccae4 112 exit(n);
6dbe3af9
KZ
113}
114
63cccae4
KZ
115/*
116 * contents of /proc/swaps
117 */
118static int numSwaps;
119static char **swapFiles; /* array of swap file and partition names */
6dbe3af9 120
63cccae4
KZ
121static void
122read_proc_swaps(void) {
123 FILE *swaps;
124 char line[1024];
a47f2e66 125 char *p, **q;
5c36a0eb 126
63cccae4
KZ
127 numSwaps = 0;
128 swapFiles = NULL;
fd6b7a7f 129
4e270e3f 130 swaps = fopen(_PATH_PROC_SWAPS, "r");
63cccae4
KZ
131 if (swaps == NULL)
132 return; /* nothing wrong */
133
134 /* skip the first line */
03f0d3e9 135 if (!fgets(line, sizeof(line), swaps)) {
d51d05d3 136 warnx(_("%s: unexpected file format"), _PATH_PROC_SWAPS);
03f0d3e9
RD
137 fclose(swaps);
138 return;
139 }
63cccae4
KZ
140 while (fgets(line, sizeof(line), swaps)) {
141 /*
142 * Cut the line "swap_device ... more info" after device.
143 * This will fail with names with embedded spaces.
144 */
145 for (p = line; *p && *p != ' '; p++);
146 *p = 0;
6dbe3af9 147
a47f2e66
KZ
148 q = realloc(swapFiles, (numSwaps+1) * sizeof(*swapFiles));
149 if (q == NULL)
150 break;
151 swapFiles = q;
152
153 swapFiles[numSwaps++] = strdup(line);
63cccae4
KZ
154 }
155 fclose(swaps);
156}
157
158static int
756bfd01 159is_in_proc_swaps(const char *fname) {
63cccae4
KZ
160 int i;
161
162 for (i = 0; i < numSwaps; i++)
07d9b366 163 if (swapFiles[i] && !strcmp(fname, swapFiles[i]))
63cccae4
KZ
164 return 1;
165 return 0;
6dbe3af9
KZ
166}
167
fd6b7a7f
KZ
168static int
169display_summary(void)
170{
171 FILE *swaps;
63cccae4 172 char line[1024] ;
fd6b7a7f 173
4e270e3f 174 if ((swaps = fopen(_PATH_PROC_SWAPS, "r")) == NULL) {
d51d05d3 175 warn(_("%s: open failed"), _PATH_PROC_SWAPS);
41d8815a 176 return -1;
fd6b7a7f 177 }
e8f26419 178
63cccae4
KZ
179 while (fgets(line, sizeof(line), swaps))
180 printf("%s", line);
fd6b7a7f 181
e8f26419 182 fclose(swaps);
fd6b7a7f
KZ
183 return 0 ;
184}
185
6274b987
KC
186/* calls mkswap */
187static int
188swap_reinitialize(const char *device) {
189 const char *label = fsprobe_get_label_by_devname(device);
190 const char *uuid = fsprobe_get_uuid_by_devname(device);
191 pid_t pid;
192 int status, ret;
193 char *cmd[7];
194 int idx=0;
195
196 switch((pid=fork())) {
197 case -1: /* fork error */
d51d05d3 198 warn(_("fork failed"));
6274b987
KC
199 return -1;
200
201 case 0: /* child */
202 cmd[idx++] = PATH_MKSWAP;
203 if (label && *label) {
204 cmd[idx++] = "-L";
205 cmd[idx++] = (char *) label;
206 }
207 if (uuid && *uuid) {
208 cmd[idx++] = "-U";
209 cmd[idx++] = (char *) uuid;
210 }
211 cmd[idx++] = (char *) device;
212 cmd[idx++] = NULL;
213 execv(cmd[0], cmd);
d51d05d3 214 err(EXIT_FAILURE, _("execv failed"));
6274b987
KC
215
216 default: /* parent */
217 do {
218 if ((ret = waitpid(pid, &status, 0)) < 0
219 && errno == EINTR)
220 continue;
221 else if (ret < 0) {
d51d05d3 222 warn(_("waitpid failed"));
6274b987
KC
223 return -1;
224 }
225 } while (0);
226
227 /* mkswap returns: 0=suss, 1=error */
228 if (WIFEXITED(status) && WEXITSTATUS(status)==0)
229 return 0; /* ok */
230 }
231 return -1; /* error */
232}
233
617d8a3b
KZ
234static int
235swap_rewrite_signature(const char *devname, unsigned int pagesize)
236{
237 int fd, rc = -1;
238
239 fd = open(devname, O_WRONLY);
240 if (fd == -1) {
241 warn(_("%s: open failed"), devname);
242 return -1;
243 }
244
245 if (lseek(fd, pagesize - SWAP_SIGNATURE_SZ, SEEK_SET) < 0)
246 goto err;
247
248 if (write(fd, (void *) SWAP_SIGNATURE,
249 SWAP_SIGNATURE_SZ) != SWAP_SIGNATURE_SZ)
250 goto err;
251
252 rc = 0;
253err:
254 close(fd);
255 return rc;
256}
257
e8be80dd
KZ
258static int
259swap_detect_signature(const char *buf, int *sig)
3399a218 260{
e8be80dd
KZ
261 if (memcmp(buf, "SWAP-SPACE", 10) == 0 ||
262 memcmp(buf, "SWAPSPACE2", 10) == 0)
263 *sig = SIG_SWAPSPACE;
264
265 else if (memcmp(buf, "S1SUSPEND", 9) == 0 ||
266 memcmp(buf, "S2SUSPEND", 9) == 0 ||
267 memcmp(buf, "ULSUSPEND", 9) == 0 ||
268 memcmp(buf, "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8) == 0)
269 *sig = SIG_SWSUSPEND;
270 else
271 return 0;
3399a218 272
e8be80dd 273 return 1;
3399a218
MK
274}
275
e8be80dd
KZ
276static char *
277swap_get_header(int fd, int *sig, unsigned int *pagesize)
3399a218 278{
3399a218 279 char *buf;
e8be80dd
KZ
280 ssize_t datasz;
281 unsigned int page;
3399a218 282
e8be80dd
KZ
283 *pagesize = 0;
284 *sig = 0;
3399a218
MK
285
286 buf = malloc(MAX_PAGESIZE);
e8be80dd
KZ
287 if (!buf)
288 return NULL;
3399a218
MK
289
290 datasz = read(fd, buf, MAX_PAGESIZE);
e8be80dd
KZ
291 if (datasz == (ssize_t) -1)
292 goto err;
3399a218
MK
293
294 for (page = 0x1000; page <= MAX_PAGESIZE; page <<= 1) {
295 /* skip 32k pagesize since this does not seem to
296 * be supported */
297 if (page == 0x8000)
298 continue;
299 /* the smallest swap area is PAGE_SIZE*10, it means
300 * 40k, that's less than MAX_PAGESIZE */
617d8a3b 301 if (datasz < (page - SWAP_SIGNATURE_SZ))
3399a218 302 break;
617d8a3b 303 if (swap_detect_signature(buf + page - SWAP_SIGNATURE_SZ, sig)) {
e8be80dd 304 *pagesize = page;
3399a218
MK
305 break;
306 }
307 }
308
e8be80dd
KZ
309 if (*pagesize)
310 return buf;
3399a218 311err:
e8be80dd
KZ
312 free(buf);
313 return NULL;
314}
315
316/* returns real size of swap space */
317unsigned long long
318swap_get_size(const char *hdr, const char *devname, unsigned int pagesize)
319{
320 unsigned int last_page = 0;
321 int swap_version = 0;
322 int flip = 0;
323 struct swap_header_v1_2 *s;
324
325 s = (struct swap_header_v1_2 *) hdr;
326 if (s->version == 1) {
327 swap_version = 1;
328 last_page = s->last_page;
329 } else if (swab32(s->version) == 1) {
330 flip = 1;
331 swap_version = 1;
332 last_page = swab32(s->last_page);
333 }
334 if (verbose)
d51d05d3 335 warnx(_("%s: found %sswap v%d signature string"
e8be80dd
KZ
336 " for %d KiB PAGE_SIZE\n"),
337 devname,
338 flip ? "other-endian " : "",
339 swap_version,
340 pagesize / 1024);
341
342 return (last_page + 1) * pagesize;
3399a218
MK
343}
344
63cccae4 345static int
05c79b78
KZ
346swapon_checks(const char *special)
347{
63cccae4 348 struct stat st;
05c79b78
KZ
349 int fd = -1, sig;
350 char *hdr = NULL;
e8be80dd
KZ
351 unsigned int pagesize;
352 unsigned long long devsize = 0;
63cccae4 353
63cccae4 354 if (stat(special, &st) < 0) {
d51d05d3 355 warn(_("%s: stat failed"), special);
05c79b78 356 goto err;
63cccae4
KZ
357 }
358
88530f9f
KZ
359 /* people generally dislike this warning - now it is printed
360 only when `verbose' is set */
361 if (verbose) {
362 int permMask = (S_ISBLK(st.st_mode) ? 07007 : 07077);
363
d51d05d3
KZ
364 if ((st.st_mode & permMask) != 0)
365 warnx(_("%s: insecure permissions %04o, %04o suggested."),
366 special, st.st_mode & 07777,
88530f9f 367 ~permMask & 0666);
88530f9f
KZ
368 }
369
370 /* test for holes by LBT */
371 if (S_ISREG(st.st_mode)) {
372 if (st.st_blocks * 512 < st.st_size) {
d51d05d3
KZ
373 warnx(_("%s: skipping - it appears to have holes."),
374 special);
05c79b78 375 goto err;
88530f9f 376 }
e8be80dd
KZ
377 devsize = st.st_size;
378 }
379
380 fd = open(special, O_RDONLY);
381 if (fd == -1) {
d51d05d3 382 warn(_("%s: open failed"), special);
05c79b78 383 goto err;
e8be80dd
KZ
384 }
385
05c79b78
KZ
386 if (S_ISBLK(st.st_mode) && blkdev_get_size(fd, &devsize)) {
387 warn(_("%s: get size failed"), special);
388 goto err;
e8be80dd
KZ
389 }
390
391 hdr = swap_get_header(fd, &sig, &pagesize);
392 if (!hdr) {
d51d05d3 393 warn(_("%s: read swap header failed"), special);
05c79b78 394 goto err;
88530f9f
KZ
395 }
396
e8be80dd
KZ
397 if (sig == SIG_SWAPSPACE && pagesize) {
398 unsigned long long swapsize =
399 swap_get_size(hdr, special, pagesize);
3399a218 400 if (verbose)
d51d05d3 401 warnx("%s: pagesize=%d, swapsize=%llu, devsize=%llu",
e8be80dd
KZ
402 special, pagesize, swapsize, devsize);
403
404 if (swapsize > devsize) {
405 if (verbose)
d51d05d3
KZ
406 warnx(_("%s: last_page 0x%08llx is larger"
407 " than actual size of swapspace"),
e8be80dd
KZ
408 special, swapsize);
409 } else if (getpagesize() != pagesize) {
d51d05d3
KZ
410 warn(_("%s: swap format pagesize does not match."
411 " Reinitializing the swap."),
412 special);
617d8a3b
KZ
413 if (swap_reinitialize(special) < 0)
414 goto err;
e8be80dd
KZ
415 }
416 } else if (sig == SIG_SWSUSPEND) {
417 /* We have to reinitialize swap with old (=useless) software suspend
418 * data. The problem is that if we don't do it, then we get data
419 * corruption the next time an attempt at unsuspending is made.
420 */
d51d05d3 421 warnx(_("%s: software suspend data detected. "
617d8a3b 422 "Rewriting the swap signature."),
d51d05d3 423 special);
617d8a3b 424 if (swap_rewrite_signature(special, pagesize) < 0)
05c79b78 425 goto err;
6274b987
KC
426 }
427
05c79b78
KZ
428 free(hdr);
429 close(fd);
430 return 0;
05c79b78
KZ
431err:
432 if (fd != -1)
433 close(fd);
434 free(hdr);
435 return -1;
436}
63cccae4 437
05c79b78
KZ
438static int
439do_swapon(const char *orig_special, int prio, int canonic) {
440 int status;
441 const char *special = orig_special;
442 int flags = 0;
63cccae4 443
05c79b78
KZ
444 if (verbose)
445 printf(_("%s on %s\n"), progname, orig_special);
446
447 if (!canonic) {
448 special = fsprobe_get_devname_by_spec(orig_special);
449 if (!special)
450 return cannot_find(orig_special);
63cccae4 451 }
ffa63a3d 452
05c79b78
KZ
453 if (swapon_checks(special))
454 return -1;
455
456#ifdef SWAP_FLAG_PREFER
457 if (prio >= 0) {
458 if (prio > SWAP_FLAG_PRIO_MASK)
459 prio = SWAP_FLAG_PRIO_MASK;
460 flags = SWAP_FLAG_PREFER
461 | ((prio & SWAP_FLAG_PRIO_MASK)
462 << SWAP_FLAG_PRIO_SHIFT);
463 }
464#endif
465 status = swapon(special, flags);
d51d05d3
KZ
466 if (status < 0)
467 warn(_("%s: swapon failed"), orig_special);
63cccae4
KZ
468
469 return status;
470}
471
472static int
756bfd01 473cannot_find(const char *special) {
d51d05d3 474 warnx(_("cannot find the device for %s"), special);
756bfd01
KZ
475 return -1;
476}
477
478static int
479swapon_by_label(const char *label, int prio) {
950f648f 480 const char *special = fsprobe_get_devname_by_label(label);
12ac2bbe 481 return special ? do_swapon(special, prio, CANONIC) : cannot_find(label);
756bfd01
KZ
482}
483
484static int
485swapon_by_uuid(const char *uuid, int prio) {
950f648f 486 const char *special = fsprobe_get_devname_by_uuid(uuid);
12ac2bbe 487 return special ? do_swapon(special, prio, CANONIC) : cannot_find(uuid);
756bfd01
KZ
488}
489
490static int
12ac2bbe
KZ
491do_swapoff(const char *orig_special, int quiet, int canonic) {
492 const char *special = orig_special;
756bfd01 493
63cccae4 494 if (verbose)
756bfd01
KZ
495 printf(_("%s on %s\n"), progname, orig_special);
496
12ac2bbe 497 if (!canonic) {
81772d3c 498 special = fsprobe_get_devname_by_spec(orig_special);
12ac2bbe
KZ
499 if (!special)
500 return cannot_find(orig_special);
501 }
63cccae4
KZ
502
503 if (swapoff(special) == 0)
504 return 0; /* success */
505
d51d05d3
KZ
506 if (errno == EPERM)
507 errx(EXIT_FAILURE, _("Not superuser."));
508
509 if (!quiet || errno == ENOMEM)
510 warn(_("%s: swapoff failed"), orig_special);
63cccae4 511
63cccae4
KZ
512 return -1;
513}
514
515static int
756bfd01 516swapoff_by_label(const char *label, int quiet) {
950f648f 517 const char *special = fsprobe_get_devname_by_label(label);
12ac2bbe 518 return special ? do_swapoff(special, quiet, CANONIC) : cannot_find(label);
756bfd01
KZ
519}
520
521static int
522swapoff_by_uuid(const char *uuid, int quiet) {
950f648f 523 const char *special = fsprobe_get_devname_by_uuid(uuid);
12ac2bbe 524 return special ? do_swapoff(special, quiet, CANONIC) : cannot_find(uuid);
756bfd01
KZ
525}
526
527static int
528swapon_all(void) {
63cccae4
KZ
529 FILE *fp;
530 struct mntent *fstab;
531 int status = 0;
63cccae4 532
756bfd01
KZ
533 read_proc_swaps();
534
4e270e3f 535 fp = setmntent(_PATH_MNTTAB, "r");
d51d05d3
KZ
536 if (fp == NULL)
537 err(2, _("%s: open failed"), _PATH_MNTTAB);
756bfd01
KZ
538
539 while ((fstab = getmntent(fp)) != NULL) {
756bfd01
KZ
540 const char *special;
541 int skip = 0;
542 int pri = priority;
1b414d89 543 char *opt, *opts;
756bfd01
KZ
544
545 if (!streq(fstab->mnt_type, MNTTYPE_SWAP))
546 continue;
547
1b414d89
KZ
548 opts = strdup(fstab->mnt_opts);
549
550 for (opt = strtok(opts, ","); opt != NULL;
551 opt = strtok(NULL, ",")) {
552 if (strncmp(opt, "pri=", 4) == 0)
553 pri = atoi(opt+4);
554 if (strcmp(opt, "noauto") == 0)
555 skip = 1;
556 }
557 free(opts);
558
559 if (skip)
560 continue;
561
81772d3c 562 special = fsprobe_get_devname_by_spec(fstab->mnt_fsname);
1b414d89
KZ
563 if (!special) {
564 if (!ifexists)
565 status |= cannot_find(fstab->mnt_fsname);
756bfd01 566 continue;
1b414d89 567 }
756bfd01
KZ
568
569 if (!is_in_proc_swaps(special) &&
1b414d89
KZ
570 (!ifexists || !access(special, R_OK)))
571 status |= do_swapon(special, pri, CANONIC);
572
573 free((void *) special);
756bfd01
KZ
574 }
575 fclose(fp);
576
577 return status;
578}
579
580static const char **llist = NULL;
581static int llct = 0;
582static const char **ulist = NULL;
583static int ulct = 0;
584
585static void addl(const char *label) {
81772d3c
KZ
586 llist = (const char **) realloc(llist, (++llct) * sizeof(char *));
587 if (!llist)
588 exit(EXIT_FAILURE);
756bfd01
KZ
589 llist[llct-1] = label;
590}
591
592static void addu(const char *uuid) {
81772d3c
KZ
593 ulist = (const char **) realloc(ulist, (++ulct) * sizeof(char *));
594 if (!ulist)
595 exit(EXIT_FAILURE);
756bfd01
KZ
596 ulist[ulct-1] = uuid;
597}
598
599static int
600main_swapon(int argc, char *argv[]) {
601 int status = 0;
602 int c, i;
603
604 while ((c = getopt_long(argc, argv, "ahep:svVL:U:",
605 longswaponopts, NULL)) != -1) {
63cccae4
KZ
606 switch (c) {
607 case 'a': /* all */
608 ++all;
609 break;
610 case 'h': /* help */
611 swapon_usage(stdout, 0);
612 break;
613 case 'p': /* priority */
614 priority = atoi(optarg);
615 break;
756bfd01
KZ
616 case 'L':
617 addl(optarg);
618 break;
619 case 'U':
620 addu(optarg);
621 break;
95f1bdee
KZ
622 case 'e': /* ifexists */
623 ifexists = 1;
624 break;
63cccae4
KZ
625 case 's': /* status report */
626 status = display_summary();
627 exit(status);
628 case 'v': /* be chatty */
629 ++verbose;
630 break;
631 case 'V': /* version */
baf39af1 632 printf("%s: (%s)\n", progname, PACKAGE_STRING);
63cccae4
KZ
633 exit(0);
634 case 0:
635 break;
636 case '?':
637 default:
638 swapon_usage(stderr, 1);
639 }
640 }
641 argv += optind;
642
756bfd01 643 if (!all && !llct && !ulct && *argv == NULL)
63cccae4
KZ
644 swapon_usage(stderr, 2);
645
756bfd01
KZ
646 if (ifexists && (!all || strcmp(progname, "swapon")))
647 swapon_usage(stderr, 1);
95f1bdee 648
756bfd01
KZ
649 if (all)
650 status |= swapon_all();
63cccae4 651
756bfd01
KZ
652 for (i = 0; i < llct; i++)
653 status |= swapon_by_label(llist[i], priority);
63cccae4 654
756bfd01
KZ
655 for (i = 0; i < ulct; i++)
656 status |= swapon_by_uuid(ulist[i], priority);
63cccae4
KZ
657
658 while (*argv != NULL)
12ac2bbe 659 status |= do_swapon(*argv++, priority, !CANONIC);
63cccae4
KZ
660
661 return status;
662}
663
664static int
665main_swapoff(int argc, char *argv[]) {
666 FILE *fp;
667 struct mntent *fstab;
668 int status = 0;
669 int c, i;
670
756bfd01 671 while ((c = getopt_long(argc, argv, "ahvVL:U:",
63cccae4
KZ
672 longswapoffopts, NULL)) != -1) {
673 switch (c) {
674 case 'a': /* all */
675 ++all;
676 break;
677 case 'h': /* help */
678 swapoff_usage(stdout, 0);
679 break;
680 case 'v': /* be chatty */
681 ++verbose;
682 break;
683 case 'V': /* version */
baf39af1 684 printf("%s (%s)\n", progname, PACKAGE_STRING);
63cccae4 685 exit(0);
756bfd01
KZ
686 case 'L':
687 addl(optarg);
688 break;
689 case 'U':
690 addu(optarg);
691 break;
63cccae4
KZ
692 case 0:
693 break;
694 case '?':
695 default:
696 swapoff_usage(stderr, 1);
697 }
698 }
699 argv += optind;
700
756bfd01 701 if (!all && !llct && !ulct && *argv == NULL)
63cccae4
KZ
702 swapoff_usage(stderr, 2);
703
704 /*
705 * swapoff any explicitly given arguments.
706 * Complain in case the swapoff call fails.
707 */
756bfd01
KZ
708 for (i = 0; i < llct; i++)
709 status |= swapoff_by_label(llist[i], !QUIET);
710
711 for (i = 0; i < ulct; i++)
712 status |= swapoff_by_uuid(ulist[i], !QUIET);
713
63cccae4 714 while (*argv != NULL)
12ac2bbe 715 status |= do_swapoff(*argv++, !QUIET, !CANONIC);
63cccae4
KZ
716
717 if (all) {
718 /*
a47f2e66 719 * In case /proc/swaps exists, unswap stuff listed there.
63cccae4
KZ
720 * We are quiet but report errors in status.
721 * Errors might mean that /proc/swaps
722 * exists as ordinary file, not in procfs.
723 * do_swapoff() exits immediately on EPERM.
724 */
725 read_proc_swaps();
726 for(i=0; i<numSwaps; i++)
12ac2bbe 727 status |= do_swapoff(swapFiles[i], QUIET, CANONIC);
63cccae4
KZ
728
729 /*
a47f2e66 730 * Unswap stuff mentioned in /etc/fstab.
63cccae4
KZ
731 * Probably it was unmounted already, so errors are not bad.
732 * Doing swapoff -a twice should not give error messages.
733 */
4e270e3f 734 fp = setmntent(_PATH_MNTTAB, "r");
d51d05d3
KZ
735 if (fp == NULL)
736 err(2, _("%s: open failed"), _PATH_MNTTAB);
737
63cccae4 738 while ((fstab = getmntent(fp)) != NULL) {
4ee7bde1
LJ
739 const char *special;
740
741 if (!streq(fstab->mnt_type, MNTTYPE_SWAP))
742 continue;
743
81772d3c 744 special = fsprobe_get_devname_by_spec(fstab->mnt_fsname);
4ee7bde1
LJ
745 if (!special)
746 continue;
747
748 if (!is_in_proc_swaps(special))
12ac2bbe 749 do_swapoff(special, QUIET, CANONIC);
63cccae4 750 }
c129767e 751 fclose(fp);
63cccae4
KZ
752 }
753
754 return status;
755}
756
757int
758main(int argc, char *argv[]) {
63cccae4
KZ
759
760 setlocale(LC_ALL, "");
761 bindtextdomain(PACKAGE, LOCALEDIR);
762 textdomain(PACKAGE);
763
d51d05d3
KZ
764 progname = program_invocation_short_name;
765 if (!progname) {
766 char *p = strrchr(argv[0], '/');
767 progname = p ? p+1 : argv[0];
768 }
63cccae4 769
756bfd01 770 if (streq(progname, "swapon"))
63cccae4
KZ
771 return main_swapon(argc, argv);
772 else
773 return main_swapoff(argc, argv);
6dbe3af9 774}