]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/swapon.c
setpriv: check writing to a file descriptor was successful
[thirdparty/util-linux.git] / sys-utils / swapon.c
CommitLineData
e076b552 1#include <assert.h>
fd6b7a7f
KZ
2#include <stdlib.h>
3#include <stdio.h>
4#include <getopt.h>
5#include <string.h>
fd6b7a7f 6#include <errno.h>
5c36a0eb 7#include <sys/stat.h>
ffa63a3d 8#include <unistd.h>
6274b987
KC
9#include <sys/types.h>
10#include <sys/wait.h>
11#include <fcntl.h>
3399a218 12#include <stdint.h>
57a60bf0 13#include <ctype.h>
81772d3c 14
64b58881 15#include <libmount.h>
b5b2c388 16
d335c9bd
KZ
17#include "c.h"
18#include "nls.h"
3399a218
MK
19#include "bitops.h"
20#include "blkdev.h"
4e270e3f 21#include "pathnames.h"
bfbb12d2 22#include "xalloc.h"
efb8854f 23#include "closestream.h"
167eaed7 24
d335c9bd 25#include "swapheader.h"
0b0c231f 26#include "swapon-common.h"
e076b552
SK
27#include "strutils.h"
28#include "tt.h"
0b0c231f 29
6274b987
KC
30#define PATH_MKSWAP "/sbin/mkswap"
31
ffa63a3d
MF
32#ifdef HAVE_SYS_SWAP_H
33# include <sys/swap.h>
34#endif
35
c2301380
HD
36#ifndef SWAP_FLAG_DISCARD
37# define SWAP_FLAG_DISCARD 0x10000 /* discard swap cluster after use */
38#endif
39
9514a612
KZ
40#ifndef SWAP_FLAG_PREFER
41# define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */
42#endif
43
44#ifndef SWAP_FLAG_PRIO_MASK
45# define SWAP_FLAG_PRIO_MASK 0x7fff
46#endif
47
48#ifndef SWAP_FLAG_PRIO_SHIFT
49# define SWAP_FLAG_PRIO_SHIFT 0
50#endif
51
ffa63a3d
MF
52#ifndef SWAPON_HAS_TWO_ARGS
53/* libc is insane, let's call the kernel */
54# include <sys/syscall.h>
55# define swapon(path, flags) syscall(SYS_swapon, path, flags)
ffa63a3d
MF
56#endif
57
63cccae4 58#define QUIET 1
12ac2bbe 59#define CANONIC 1
63cccae4 60
3399a218
MK
61#define MAX_PAGESIZE (64 * 1024)
62
e8be80dd
KZ
63enum {
64 SIG_SWAPSPACE = 1,
65 SIG_SWSUSPEND
66};
67
617d8a3b
KZ
68#define SWAP_SIGNATURE "SWAPSPACE2"
69#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
70
16ff9813
TK
71static int all;
72static int priority = -1; /* non-prioritized swap by default */
73static int discard;
6dbe3af9 74
95f1bdee 75/* If true, don't complain if the device/file doesn't exist */
16ff9813
TK
76static int ifexists;
77static int fixpgsz;
16ff9813 78static int verbose;
95f1bdee 79
e076b552
SK
80/* column names */
81struct colinfo {
82 const char *name; /* header */
83 double whint; /* width hint (N < 1 is in percent of termwidth) */
84 int flags; /* TT_FL_* */
85 const char *help;
86};
87enum { COL_PATH, COL_TYPE, COL_SIZE, COL_USED, COL_PRIO };
88struct colinfo infos[] = {
89 [COL_PATH] = { "NAME", 0.20, 0, N_("device file or partition path") },
90 [COL_TYPE] = { "TYPE", 0.20, TT_FL_TRUNC, N_("type of the device")},
91 [COL_SIZE] = { "SIZE", 0.20, TT_FL_RIGHT, N_("size of the swap area")},
92 [COL_USED] = { "USED", 0.20, TT_FL_RIGHT, N_("bytes in use")},
93 [COL_PRIO] = { "PRIO", 0.20, TT_FL_RIGHT, N_("swap priority")},
94};
95#define NCOLS ARRAY_SIZE(infos)
96static int columns[NCOLS], ncolumns;
97
98static int column_name_to_id(const char *name, size_t namesz)
99{
100 size_t i;
101
102 assert(name);
103
104 for (i = 0; i < NCOLS; i++) {
105 const char *cn = infos[i].name;
106
107 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
108 return i;
109 }
110 warnx(_("unknown column: %s"), name);
111 return -1;
112}
113
114static inline int get_column_id(int num)
115{
116 assert(ARRAY_SIZE(columns) == NCOLS);
117 assert(num < ncolumns);
118 assert(columns[num] < (int)NCOLS);
119
120 return columns[num];
121}
122
123static inline struct colinfo *get_column_info(unsigned num)
124{
125 return &infos[get_column_id(num)];
126}
127
7ae8b469 128static void add_tt_line(struct tt *tt, struct libmnt_fs *fs, int bytes)
e076b552
SK
129{
130 int i;
131 struct tt_line *line;
132
133 assert(tt);
134 assert(fs);
135
136 line = tt_add_line(tt, NULL);
137 if (!line) {
138 warn(_("failed to add line to output"));
139 return;
140 }
141
142 for (i = 0; i < ncolumns; i++) {
143 char *str = NULL;
7ae8b469 144 off_t size;
e076b552
SK
145
146 switch (get_column_id(i)) {
147 case COL_PATH:
a0e35e30 148 xasprintf(&str, "%s", mnt_fs_get_source(fs));
e076b552
SK
149 break;
150 case COL_TYPE:
a0e35e30 151 xasprintf(&str, "%s", mnt_fs_get_swaptype(fs));
e076b552
SK
152 break;
153 case COL_SIZE:
7ae8b469
SK
154 size = mnt_fs_get_size(fs);
155 size *= 1024; /* convert to bytes */
156 if (bytes)
a0e35e30 157 xasprintf(&str, "%jd", size);
7ae8b469
SK
158 else
159 str = size_to_human_string(SIZE_SUFFIX_1LETTER, size);
e076b552
SK
160 break;
161 case COL_USED:
7ae8b469
SK
162 size = mnt_fs_get_usedsize(fs);
163 size *= 1024; /* convert to bytes */
164 if (bytes)
a0e35e30 165 xasprintf(&str, "%jd", size);
7ae8b469
SK
166 else
167 str = size_to_human_string(SIZE_SUFFIX_1LETTER, size);
e076b552
SK
168 break;
169 case COL_PRIO:
a0e35e30 170 xasprintf(&str, "%d", mnt_fs_get_priority(fs));
e076b552
SK
171 break;
172 default:
173 break;
174 }
175
a0e35e30 176 if (str)
e076b552
SK
177 tt_line_set_data(line, i, str);
178 }
179 return;
180}
181
d335c9bd 182static int display_summary(void)
fd6b7a7f 183{
5072b90a 184 struct libmnt_table *st = get_swaps();
64b58881
KZ
185 struct libmnt_iter *itr;
186 struct libmnt_fs *fs;
fd6b7a7f 187
64b58881 188 if (!st)
57a60bf0 189 return -1;
e8f26419 190
64b58881
KZ
191 itr = mnt_new_iter(MNT_ITER_FORWARD);
192 if (!itr)
193 err(EXIT_FAILURE, _("failed to initialize libmount iterator"));
57a60bf0 194
64b58881 195 if (mnt_table_get_nents(st) > 0)
0aec470c 196 printf(_("%s\t\t\t\tType\t\tSize\tUsed\tPriority\n"), _("Filename"));
64b58881
KZ
197
198 while (mnt_table_next_fs(st, itr, &fs) == 0) {
199 printf("%-39s\t%s\t%jd\t%jd\t%d\n",
200 mnt_fs_get_source(fs),
201 mnt_fs_get_swaptype(fs),
202 mnt_fs_get_size(fs),
203 mnt_fs_get_usedsize(fs),
204 mnt_fs_get_priority(fs));
57a60bf0 205 }
fd6b7a7f 206
64b58881
KZ
207 mnt_free_iter(itr);
208 return 0;
fd6b7a7f
KZ
209}
210
7ae8b469 211static int show_table(int tt_flags, int bytes)
e076b552
SK
212{
213 struct libmnt_table *st = get_swaps();
880f09c8 214 struct libmnt_iter *itr = NULL;
e076b552
SK
215 struct libmnt_fs *fs;
216
217 int i, rc = 0;
880f09c8 218 struct tt *tt = NULL;
e076b552
SK
219
220 if (!st)
221 return -1;
222
223 itr = mnt_new_iter(MNT_ITER_FORWARD);
224 if (!itr)
225 err(EXIT_FAILURE, _("failed to initialize libmount iterator"));
226
227 tt = tt_new_table(tt_flags);
228 if (!tt) {
229 warn(_("failed to initialize output table"));
880f09c8 230 goto done;
e076b552
SK
231 }
232
233 for (i = 0; i < ncolumns; i++) {
234 struct colinfo *col = get_column_info(i);
235
236 if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
237 warnx(_("failed to initialize output column"));
238 rc = -1;
239 goto done;
240 }
241 }
242
243 while (mnt_table_next_fs(st, itr, &fs) == 0)
7ae8b469 244 add_tt_line(tt, fs, bytes);
e076b552 245
e076b552
SK
246 tt_print_table(tt);
247 done:
880f09c8 248 mnt_free_iter(itr);
e076b552
SK
249 tt_free_table(tt);
250 return rc;
251}
252
6274b987 253/* calls mkswap */
d335c9bd
KZ
254static int swap_reinitialize(const char *device,
255 const char *label, const char *uuid)
b5b2c388 256{
6274b987
KC
257 pid_t pid;
258 int status, ret;
259 char *cmd[7];
260 int idx=0;
261
0d761944
KZ
262 warnx(_("%s: reinitializing the swap."), device);
263
6274b987
KC
264 switch((pid=fork())) {
265 case -1: /* fork error */
d51d05d3 266 warn(_("fork failed"));
6274b987
KC
267 return -1;
268
269 case 0: /* child */
270 cmd[idx++] = PATH_MKSWAP;
271 if (label && *label) {
272 cmd[idx++] = "-L";
273 cmd[idx++] = (char *) label;
274 }
275 if (uuid && *uuid) {
276 cmd[idx++] = "-U";
277 cmd[idx++] = (char *) uuid;
278 }
279 cmd[idx++] = (char *) device;
280 cmd[idx++] = NULL;
281 execv(cmd[0], cmd);
07ff972e 282 err(EXIT_FAILURE, _("failed to execute %s"), cmd[0]);
6274b987
KC
283
284 default: /* parent */
285 do {
286 if ((ret = waitpid(pid, &status, 0)) < 0
287 && errno == EINTR)
288 continue;
289 else if (ret < 0) {
d51d05d3 290 warn(_("waitpid failed"));
6274b987
KC
291 return -1;
292 }
293 } while (0);
294
295 /* mkswap returns: 0=suss, 1=error */
296 if (WIFEXITED(status) && WEXITSTATUS(status)==0)
297 return 0; /* ok */
f8ff4ebb 298 break;
6274b987
KC
299 }
300 return -1; /* error */
301}
302
d335c9bd 303static int swap_rewrite_signature(const char *devname, unsigned int pagesize)
617d8a3b
KZ
304{
305 int fd, rc = -1;
306
307 fd = open(devname, O_WRONLY);
308 if (fd == -1) {
289dcc90 309 warn(_("cannot open %s"), devname);
617d8a3b
KZ
310 return -1;
311 }
312
5dd53f43
KZ
313 if (lseek(fd, pagesize - SWAP_SIGNATURE_SZ, SEEK_SET) < 0) {
314 warn(_("%s: lseek failed"), devname);
617d8a3b 315 goto err;
5dd53f43 316 }
617d8a3b
KZ
317
318 if (write(fd, (void *) SWAP_SIGNATURE,
5dd53f43
KZ
319 SWAP_SIGNATURE_SZ) != SWAP_SIGNATURE_SZ) {
320 warn(_("%s: write signature failed"), devname);
617d8a3b 321 goto err;
5dd53f43 322 }
617d8a3b
KZ
323
324 rc = 0;
325err:
326 close(fd);
327 return rc;
328}
329
d335c9bd 330static int swap_detect_signature(const char *buf, int *sig)
3399a218 331{
e8be80dd
KZ
332 if (memcmp(buf, "SWAP-SPACE", 10) == 0 ||
333 memcmp(buf, "SWAPSPACE2", 10) == 0)
334 *sig = SIG_SWAPSPACE;
335
336 else if (memcmp(buf, "S1SUSPEND", 9) == 0 ||
337 memcmp(buf, "S2SUSPEND", 9) == 0 ||
338 memcmp(buf, "ULSUSPEND", 9) == 0 ||
5a16af58
KZ
339 memcmp(buf, "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8) == 0 ||
340 memcmp(buf, "LINHIB0001", 10) == 0)
e8be80dd
KZ
341 *sig = SIG_SWSUSPEND;
342 else
343 return 0;
3399a218 344
e8be80dd 345 return 1;
3399a218
MK
346}
347
d335c9bd 348static char *swap_get_header(int fd, int *sig, unsigned int *pagesize)
3399a218 349{
3399a218 350 char *buf;
e8be80dd
KZ
351 ssize_t datasz;
352 unsigned int page;
3399a218 353
e8be80dd
KZ
354 *pagesize = 0;
355 *sig = 0;
3399a218 356
bfbb12d2 357 buf = xmalloc(MAX_PAGESIZE);
3399a218
MK
358
359 datasz = read(fd, buf, MAX_PAGESIZE);
e8be80dd
KZ
360 if (datasz == (ssize_t) -1)
361 goto err;
3399a218
MK
362
363 for (page = 0x1000; page <= MAX_PAGESIZE; page <<= 1) {
364 /* skip 32k pagesize since this does not seem to
365 * be supported */
366 if (page == 0x8000)
367 continue;
368 /* the smallest swap area is PAGE_SIZE*10, it means
369 * 40k, that's less than MAX_PAGESIZE */
24f010e8 370 if (datasz < 0 || (size_t) datasz < (page - SWAP_SIGNATURE_SZ))
3399a218 371 break;
617d8a3b 372 if (swap_detect_signature(buf + page - SWAP_SIGNATURE_SZ, sig)) {
e8be80dd 373 *pagesize = page;
3399a218
MK
374 break;
375 }
376 }
377
e8be80dd
KZ
378 if (*pagesize)
379 return buf;
3399a218 380err:
e8be80dd
KZ
381 free(buf);
382 return NULL;
383}
384
385/* returns real size of swap space */
d335c9bd
KZ
386static unsigned long long swap_get_size(const char *hdr, const char *devname,
387 unsigned int pagesize)
e8be80dd
KZ
388{
389 unsigned int last_page = 0;
390 int swap_version = 0;
391 int flip = 0;
392 struct swap_header_v1_2 *s;
393
394 s = (struct swap_header_v1_2 *) hdr;
395 if (s->version == 1) {
396 swap_version = 1;
397 last_page = s->last_page;
398 } else if (swab32(s->version) == 1) {
399 flip = 1;
400 swap_version = 1;
401 last_page = swab32(s->last_page);
402 }
403 if (verbose)
04c94441
KZ
404 warnx(_("%s: found swap signature: version %d, "
405 "page-size %d, %s byte order"),
e8be80dd 406 devname,
e8be80dd 407 swap_version,
04c94441
KZ
408 pagesize / 1024,
409 flip ? _("different") : _("same"));
e8be80dd 410
98e9ff61 411 return ((unsigned long long) last_page + 1) * pagesize;
3399a218
MK
412}
413
d335c9bd 414static void swap_get_info(const char *hdr, char **label, char **uuid)
b5b2c388
KZ
415{
416 struct swap_header_v1_2 *s = (struct swap_header_v1_2 *) hdr;
417
418 if (s && *s->volume_name && label)
419 *label = xstrdup(s->volume_name);
420
421 if (s && *s->uuid && uuid) {
422 const unsigned char *u = s->uuid;
423 char str[37];
424
425 snprintf(str, sizeof(str),
426 "%02x%02x%02x%02x-"
427 "%02x%02x-%02x%02x-"
428 "%02x%02x-%02x%02x%02x%02x%02x%02x",
429 u[0], u[1], u[2], u[3],
430 u[4], u[5], u[6], u[7],
431 u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]);
432 *uuid = xstrdup(str);
433 }
434}
435
d335c9bd 436static int swapon_checks(const char *special)
05c79b78 437{
63cccae4 438 struct stat st;
05c79b78
KZ
439 int fd = -1, sig;
440 char *hdr = NULL;
e8be80dd
KZ
441 unsigned int pagesize;
442 unsigned long long devsize = 0;
cd04b26b 443 int permMask;
63cccae4 444
63cccae4 445 if (stat(special, &st) < 0) {
add1b8af 446 warn(_("stat failed %s"), special);
05c79b78 447 goto err;
63cccae4
KZ
448 }
449
cd04b26b
KZ
450 permMask = S_ISBLK(st.st_mode) ? 07007 : 07077;
451 if ((st.st_mode & permMask) != 0)
452 warnx(_("%s: insecure permissions %04o, %04o suggested."),
d51d05d3 453 special, st.st_mode & 07777,
88530f9f 454 ~permMask & 0666);
306c1df2 455
cd04b26b
KZ
456 if (S_ISREG(st.st_mode) && st.st_uid != 0)
457 warnx(_("%s: insecure file owner %d, 0 (root) suggested."),
306c1df2 458 special, st.st_uid);
88530f9f
KZ
459
460 /* test for holes by LBT */
461 if (S_ISREG(st.st_mode)) {
462 if (st.st_blocks * 512 < st.st_size) {
d51d05d3
KZ
463 warnx(_("%s: skipping - it appears to have holes."),
464 special);
05c79b78 465 goto err;
88530f9f 466 }
e8be80dd
KZ
467 devsize = st.st_size;
468 }
469
470 fd = open(special, O_RDONLY);
471 if (fd == -1) {
289dcc90 472 warn(_("cannot open %s"), special);
05c79b78 473 goto err;
e8be80dd
KZ
474 }
475
05c79b78
KZ
476 if (S_ISBLK(st.st_mode) && blkdev_get_size(fd, &devsize)) {
477 warn(_("%s: get size failed"), special);
478 goto err;
e8be80dd
KZ
479 }
480
481 hdr = swap_get_header(fd, &sig, &pagesize);
482 if (!hdr) {
d51d05d3 483 warn(_("%s: read swap header failed"), special);
05c79b78 484 goto err;
88530f9f
KZ
485 }
486
e8be80dd
KZ
487 if (sig == SIG_SWAPSPACE && pagesize) {
488 unsigned long long swapsize =
489 swap_get_size(hdr, special, pagesize);
24f010e8
KZ
490 int syspg = getpagesize();
491
3399a218 492 if (verbose)
e6b0611b 493 warnx(_("%s: pagesize=%d, swapsize=%llu, devsize=%llu"),
e8be80dd
KZ
494 special, pagesize, swapsize, devsize);
495
496 if (swapsize > devsize) {
497 if (verbose)
d51d05d3
KZ
498 warnx(_("%s: last_page 0x%08llx is larger"
499 " than actual size of swapspace"),
e8be80dd 500 special, swapsize);
24f010e8 501 } else if (syspg < 0 || (unsigned) syspg != pagesize) {
0d761944 502 if (fixpgsz) {
b5b2c388
KZ
503 char *label = NULL, *uuid = NULL;
504 int rc;
505
506 swap_get_info(hdr, &label, &uuid);
507
93bfcc94 508 warnx(_("%s: swap format pagesize does not match."),
0d761944 509 special);
b5b2c388
KZ
510 rc = swap_reinitialize(special, label, uuid);
511 free(label);
512 free(uuid);
513 if (rc < 0)
0d761944
KZ
514 goto err;
515 } else
93bfcc94
KZ
516 warnx(_("%s: swap format pagesize does not match. "
517 "(Use --fixpgsz to reinitialize it.)"),
0d761944 518 special);
e8be80dd
KZ
519 }
520 } else if (sig == SIG_SWSUSPEND) {
521 /* We have to reinitialize swap with old (=useless) software suspend
522 * data. The problem is that if we don't do it, then we get data
523 * corruption the next time an attempt at unsuspending is made.
524 */
d51d05d3 525 warnx(_("%s: software suspend data detected. "
617d8a3b 526 "Rewriting the swap signature."),
d51d05d3 527 special);
617d8a3b 528 if (swap_rewrite_signature(special, pagesize) < 0)
05c79b78 529 goto err;
6274b987
KC
530 }
531
05c79b78
KZ
532 free(hdr);
533 close(fd);
534 return 0;
05c79b78
KZ
535err:
536 if (fd != -1)
537 close(fd);
538 free(hdr);
539 return -1;
540}
63cccae4 541
d335c9bd
KZ
542static int do_swapon(const char *orig_special, int prio,
543 int fl_discard, int canonic)
544{
05c79b78
KZ
545 int status;
546 const char *special = orig_special;
547 int flags = 0;
63cccae4 548
05c79b78 549 if (verbose)
d9f07b10 550 printf(_("swapon %s\n"), orig_special);
05c79b78
KZ
551
552 if (!canonic) {
e5157fc9 553 special = mnt_resolve_spec(orig_special, mntcache);
05c79b78
KZ
554 if (!special)
555 return cannot_find(orig_special);
63cccae4 556 }
ffa63a3d 557
05c79b78
KZ
558 if (swapon_checks(special))
559 return -1;
560
561#ifdef SWAP_FLAG_PREFER
562 if (prio >= 0) {
563 if (prio > SWAP_FLAG_PRIO_MASK)
564 prio = SWAP_FLAG_PRIO_MASK;
565 flags = SWAP_FLAG_PREFER
566 | ((prio & SWAP_FLAG_PRIO_MASK)
567 << SWAP_FLAG_PRIO_SHIFT);
568 }
569#endif
c2301380
HD
570 if (fl_discard)
571 flags |= SWAP_FLAG_DISCARD;
572
05c79b78 573 status = swapon(special, flags);
d51d05d3
KZ
574 if (status < 0)
575 warn(_("%s: swapon failed"), orig_special);
63cccae4
KZ
576
577 return status;
578}
579
d335c9bd
KZ
580static int swapon_by_label(const char *label, int prio, int dsc)
581{
e5157fc9 582 const char *special = mnt_resolve_tag("LABEL", label, mntcache);
c2301380
HD
583 return special ? do_swapon(special, prio, dsc, CANONIC) :
584 cannot_find(label);
756bfd01
KZ
585}
586
d335c9bd
KZ
587static int swapon_by_uuid(const char *uuid, int prio, int dsc)
588{
e5157fc9 589 const char *special = mnt_resolve_tag("UUID", uuid, mntcache);
c2301380
HD
590 return special ? do_swapon(special, prio, dsc, CANONIC) :
591 cannot_find(uuid);
756bfd01
KZ
592}
593
d335c9bd
KZ
594static int swapon_all(void)
595{
5072b90a
KZ
596 struct libmnt_table *tb = get_fstab();
597 struct libmnt_iter *itr;
598 struct libmnt_fs *fs;
63cccae4 599 int status = 0;
63cccae4 600
5072b90a 601 if (!tb)
d335c9bd 602 err(EXIT_FAILURE, _("failed to parse %s"), mnt_get_fstab_path());
756bfd01 603
5072b90a
KZ
604 itr = mnt_new_iter(MNT_ITER_FORWARD);
605 if (!itr)
606 err(EXIT_FAILURE, _("failed to initialize libmount iterator"));
756bfd01 607
5072b90a
KZ
608 while (mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) {
609 /* defaults */
610 int pri = priority, dsc = discard, nofail = ifexists;
611 char *p, *src;
1b414d89 612
5072b90a 613 if (mnt_fs_get_option(fs, "noauto", NULL, NULL) == 0)
1b414d89 614 continue;
5072b90a
KZ
615 if (mnt_fs_get_option(fs, "discard", NULL, NULL) == 0)
616 dsc = 1;
617 if (mnt_fs_get_option(fs, "nofail", NULL, NULL) == 0)
618 nofail = 1;
619 if (mnt_fs_get_option(fs, "pri", &p, NULL) == 0 && p)
620 pri = atoi(p);
621
622 src = mnt_resolve_spec(mnt_fs_get_source(fs), mntcache);
623 if (!src) {
a5fd3d68 624 if (!nofail)
5072b90a 625 status |= cannot_find(mnt_fs_get_source(fs));
756bfd01 626 continue;
1b414d89 627 }
756bfd01 628
5072b90a
KZ
629 if (!is_active_swap(src) &&
630 (!nofail || !access(src, R_OK)))
631 status |= do_swapon(src, pri, dsc, CANONIC);
756bfd01 632 }
756bfd01 633
5072b90a 634 mnt_free_iter(itr);
756bfd01
KZ
635 return status;
636}
637
8b0d5341
KZ
638static void __attribute__ ((__noreturn__)) usage(FILE * out)
639{
e09bd8d0 640 size_t i;
8b0d5341
KZ
641 fputs(USAGE_HEADER, out);
642
643 fprintf(out, _(" %s [options] [<spec>]\n"), program_invocation_short_name);
644
645 fputs(USAGE_OPTIONS, out);
646 fputs(_(" -a, --all enable all swaps from /etc/fstab\n"
647 " -d, --discard discard freed pages before they are reused\n"
59114ba3 648 " -e, --ifexists silently skip devices that do not exist\n"
8b0d5341
KZ
649 " -f, --fixpgsz reinitialize the swap space if necessary\n"
650 " -p, --priority <prio> specify the priority of the swap device\n"
e076b552
SK
651 " -s, --summary display summary about used swap devices\n"
652 " --show[=<columns>] display summary in definable table\n"
653 " --noheadings don't print headings, use with --show\n"
654 " --raw use the raw output format, use with --show\n"
7ae8b469 655 " --bytes display swap size in bytes in --show output\n"
8b0d5341
KZ
656 " -v, --verbose verbose mode\n"), out);
657
658 fputs(USAGE_SEPARATOR, out);
659 fputs(USAGE_HELP, out);
660 fputs(USAGE_VERSION, out);
661
662 fputs(_("\nThe <spec> parameter:\n" \
9f9d0f21
KZ
663 " -L <label> synonym for LABEL=<label>\n"
664 " -U <uuid> synonym for UUID=<uuid>\n"
665 " LABEL=<label> specifies device by swap area label\n"
666 " UUID=<uuid> specifies device by swap area UUID\n"
667 " PARTLABEL=<label> specifies device by partition label\n"
668 " PARTUUID=<uuid> specifies device by partition UUID\n"
669 " <device> name of device to be used\n"
8b0d5341
KZ
670 " <file> name of file to be used\n"), out);
671
e076b552 672 fputs(_("\nAvailable columns (for --show):\n"), out);
e09bd8d0 673 for (i = 0; i < NCOLS; i++)
e076b552
SK
674 fprintf(out, " %4s %s\n", infos[i].name, _(infos[i].help));
675
8b0d5341
KZ
676 fprintf(out, USAGE_MAN_TAIL("swapon(8)"));
677 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
678}
679
d9f07b10
KZ
680int main(int argc, char *argv[])
681{
8b0d5341 682 int status = 0, c;
e076b552 683 int show = 0, tt_flags = 0;
7ae8b469 684 int bytes = 0;
0b0c231f 685 size_t i;
756bfd01 686
e076b552
SK
687 enum {
688 SHOW_OPTION = CHAR_MAX + 1,
689 RAW_OPTION,
7ae8b469
SK
690 NOHEADINGS_OPTION,
691 BYTES_OPTION
e076b552
SK
692 };
693
8b0d5341
KZ
694 static const struct option long_opts[] = {
695 { "priority", 1, 0, 'p' },
696 { "discard", 0, 0, 'd' },
697 { "ifexists", 0, 0, 'e' },
698 { "summary", 0, 0, 's' },
699 { "fixpgsz", 0, 0, 'f' },
700 { "all", 0, 0, 'a' },
701 { "help", 0, 0, 'h' },
702 { "verbose", 0, 0, 'v' },
703 { "version", 0, 0, 'V' },
e076b552
SK
704 { "show", 2, 0, SHOW_OPTION },
705 { "noheadings", 0, 0, NOHEADINGS_OPTION },
706 { "raw", 0, 0, RAW_OPTION },
7ae8b469 707 { "bytes", 0, 0, BYTES_OPTION },
8b0d5341
KZ
708 { NULL, 0, 0, 0 }
709 };
710
d9f07b10
KZ
711 setlocale(LC_ALL, "");
712 bindtextdomain(PACKAGE, LOCALEDIR);
713 textdomain(PACKAGE);
714 atexit(close_stdout);
715
716 mnt_init_debug(0);
717 mntcache = mnt_new_cache();
718
c2301380 719 while ((c = getopt_long(argc, argv, "ahdefp:svVL:U:",
8b0d5341 720 long_opts, NULL)) != -1) {
63cccae4
KZ
721 switch (c) {
722 case 'a': /* all */
723 ++all;
724 break;
725 case 'h': /* help */
8b0d5341 726 usage(stdout);
63cccae4
KZ
727 break;
728 case 'p': /* priority */
9db6a749
SK
729 priority = strtos16_or_err(optarg,
730 _("failed to parse priority"));
63cccae4 731 break;
756bfd01 732 case 'L':
0b0c231f 733 add_label(optarg);
756bfd01
KZ
734 break;
735 case 'U':
0b0c231f 736 add_uuid(optarg);
756bfd01 737 break;
c2301380
HD
738 case 'd':
739 discard = 1;
740 break;
95f1bdee
KZ
741 case 'e': /* ifexists */
742 ifexists = 1;
743 break;
0d761944
KZ
744 case 'f':
745 fixpgsz = 1;
746 break;
63cccae4
KZ
747 case 's': /* status report */
748 status = display_summary();
8b0d5341 749 return status;
63cccae4
KZ
750 case 'v': /* be chatty */
751 ++verbose;
752 break;
e076b552
SK
753 case SHOW_OPTION:
754 if (optarg) {
755 ncolumns = string_to_idarray(optarg,
756 columns,
757 ARRAY_SIZE(columns),
758 column_name_to_id);
759 if (ncolumns < 0)
760 return EXIT_FAILURE;
761 }
762 show = 1;
763 break;
764 case NOHEADINGS_OPTION:
765 tt_flags |= TT_FL_NOHEADINGS;
766 break;
767 case RAW_OPTION:
768 tt_flags |= TT_FL_RAW;
769 break;
7ae8b469
SK
770 case BYTES_OPTION:
771 bytes = 1;
772 break;
63cccae4 773 case 'V': /* version */
d9f07b10
KZ
774 printf(UTIL_LINUX_VERSION);
775 return EXIT_SUCCESS;
63cccae4
KZ
776 case 0:
777 break;
778 case '?':
779 default:
8b0d5341 780 usage(stderr);
63cccae4
KZ
781 }
782 }
783 argv += optind;
784
d96b743f 785 if (show || (!all && !numof_labels() && !numof_uuids() && *argv == NULL)) {
e076b552
SK
786 if (!ncolumns) {
787 /* default columns */
788 columns[ncolumns++] = COL_PATH;
789 columns[ncolumns++] = COL_TYPE;
790 columns[ncolumns++] = COL_SIZE;
791 columns[ncolumns++] = COL_USED;
792 columns[ncolumns++] = COL_PRIO;
793 }
7ae8b469 794 status = show_table(tt_flags, bytes);
e076b552
SK
795 return status;
796 }
797
d9f07b10 798 if (ifexists && !all)
8b0d5341 799 usage(stderr);
95f1bdee 800
756bfd01
KZ
801 if (all)
802 status |= swapon_all();
63cccae4 803
0b0c231f
KZ
804 for (i = 0; i < numof_labels(); i++)
805 status |= swapon_by_label(get_label(i), priority, discard);
63cccae4 806
0b0c231f
KZ
807 for (i = 0; i < numof_uuids(); i++)
808 status |= swapon_by_uuid(get_uuid(i), priority, discard);
63cccae4
KZ
809
810 while (*argv != NULL)
c2301380 811 status |= do_swapon(*argv++, priority, discard, !CANONIC);
63cccae4 812
0b0c231f 813 free_tables();
64b58881 814 mnt_free_cache(mntcache);
d9f07b10 815
64b58881 816 return status;
6dbe3af9 817}