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