]>
Commit | Line | Data |
---|---|---|
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 |
63 | enum { |
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 |
71 | static int all; |
72 | static int priority = -1; /* non-prioritized swap by default */ | |
73 | static int discard; | |
6dbe3af9 | 74 | |
95f1bdee | 75 | /* If true, don't complain if the device/file doesn't exist */ |
16ff9813 TK |
76 | static int ifexists; |
77 | static int fixpgsz; | |
16ff9813 | 78 | static int verbose; |
95f1bdee | 79 | |
e076b552 SK |
80 | /* column names */ |
81 | struct 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 | }; | |
87 | enum { COL_PATH, COL_TYPE, COL_SIZE, COL_USED, COL_PRIO }; | |
88 | struct 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) | |
96 | static int columns[NCOLS], ncolumns; | |
97 | ||
98 | static 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 | ||
114 | static 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 | ||
123 | static inline struct colinfo *get_column_info(unsigned num) | |
124 | { | |
125 | return &infos[get_column_id(num)]; | |
126 | } | |
127 | ||
7ae8b469 | 128 | static 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 | 182 | static 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 | |
a2f17bb2 KZ |
191 | if (mnt_table_is_empty(st)) |
192 | return 0; | |
193 | ||
64b58881 KZ |
194 | itr = mnt_new_iter(MNT_ITER_FORWARD); |
195 | if (!itr) | |
196 | err(EXIT_FAILURE, _("failed to initialize libmount iterator")); | |
57a60bf0 | 197 | |
a2f17bb2 | 198 | printf(_("%s\t\t\t\tType\t\tSize\tUsed\tPriority\n"), _("Filename")); |
64b58881 KZ |
199 | |
200 | while (mnt_table_next_fs(st, itr, &fs) == 0) { | |
201 | printf("%-39s\t%s\t%jd\t%jd\t%d\n", | |
202 | mnt_fs_get_source(fs), | |
203 | mnt_fs_get_swaptype(fs), | |
204 | mnt_fs_get_size(fs), | |
205 | mnt_fs_get_usedsize(fs), | |
206 | mnt_fs_get_priority(fs)); | |
57a60bf0 | 207 | } |
fd6b7a7f | 208 | |
64b58881 KZ |
209 | mnt_free_iter(itr); |
210 | return 0; | |
fd6b7a7f KZ |
211 | } |
212 | ||
7ae8b469 | 213 | static int show_table(int tt_flags, int bytes) |
e076b552 SK |
214 | { |
215 | struct libmnt_table *st = get_swaps(); | |
880f09c8 | 216 | struct libmnt_iter *itr = NULL; |
e076b552 SK |
217 | struct libmnt_fs *fs; |
218 | ||
219 | int i, rc = 0; | |
880f09c8 | 220 | struct tt *tt = NULL; |
e076b552 SK |
221 | |
222 | if (!st) | |
223 | return -1; | |
224 | ||
225 | itr = mnt_new_iter(MNT_ITER_FORWARD); | |
226 | if (!itr) | |
227 | err(EXIT_FAILURE, _("failed to initialize libmount iterator")); | |
228 | ||
229 | tt = tt_new_table(tt_flags); | |
230 | if (!tt) { | |
231 | warn(_("failed to initialize output table")); | |
880f09c8 | 232 | goto done; |
e076b552 SK |
233 | } |
234 | ||
235 | for (i = 0; i < ncolumns; i++) { | |
236 | struct colinfo *col = get_column_info(i); | |
237 | ||
238 | if (!tt_define_column(tt, col->name, col->whint, col->flags)) { | |
239 | warnx(_("failed to initialize output column")); | |
240 | rc = -1; | |
241 | goto done; | |
242 | } | |
243 | } | |
244 | ||
245 | while (mnt_table_next_fs(st, itr, &fs) == 0) | |
7ae8b469 | 246 | add_tt_line(tt, fs, bytes); |
e076b552 | 247 | |
e076b552 SK |
248 | tt_print_table(tt); |
249 | done: | |
880f09c8 | 250 | mnt_free_iter(itr); |
e076b552 SK |
251 | tt_free_table(tt); |
252 | return rc; | |
253 | } | |
254 | ||
6274b987 | 255 | /* calls mkswap */ |
d335c9bd KZ |
256 | static int swap_reinitialize(const char *device, |
257 | const char *label, const char *uuid) | |
b5b2c388 | 258 | { |
6274b987 KC |
259 | pid_t pid; |
260 | int status, ret; | |
261 | char *cmd[7]; | |
262 | int idx=0; | |
263 | ||
0d761944 KZ |
264 | warnx(_("%s: reinitializing the swap."), device); |
265 | ||
6274b987 KC |
266 | switch((pid=fork())) { |
267 | case -1: /* fork error */ | |
d51d05d3 | 268 | warn(_("fork failed")); |
6274b987 KC |
269 | return -1; |
270 | ||
271 | case 0: /* child */ | |
272 | cmd[idx++] = PATH_MKSWAP; | |
273 | if (label && *label) { | |
274 | cmd[idx++] = "-L"; | |
275 | cmd[idx++] = (char *) label; | |
276 | } | |
277 | if (uuid && *uuid) { | |
278 | cmd[idx++] = "-U"; | |
279 | cmd[idx++] = (char *) uuid; | |
280 | } | |
281 | cmd[idx++] = (char *) device; | |
282 | cmd[idx++] = NULL; | |
283 | execv(cmd[0], cmd); | |
07ff972e | 284 | err(EXIT_FAILURE, _("failed to execute %s"), cmd[0]); |
6274b987 KC |
285 | |
286 | default: /* parent */ | |
287 | do { | |
288 | if ((ret = waitpid(pid, &status, 0)) < 0 | |
289 | && errno == EINTR) | |
290 | continue; | |
291 | else if (ret < 0) { | |
d51d05d3 | 292 | warn(_("waitpid failed")); |
6274b987 KC |
293 | return -1; |
294 | } | |
295 | } while (0); | |
296 | ||
297 | /* mkswap returns: 0=suss, 1=error */ | |
298 | if (WIFEXITED(status) && WEXITSTATUS(status)==0) | |
299 | return 0; /* ok */ | |
f8ff4ebb | 300 | break; |
6274b987 KC |
301 | } |
302 | return -1; /* error */ | |
303 | } | |
304 | ||
d335c9bd | 305 | static int swap_rewrite_signature(const char *devname, unsigned int pagesize) |
617d8a3b KZ |
306 | { |
307 | int fd, rc = -1; | |
308 | ||
309 | fd = open(devname, O_WRONLY); | |
310 | if (fd == -1) { | |
289dcc90 | 311 | warn(_("cannot open %s"), devname); |
617d8a3b KZ |
312 | return -1; |
313 | } | |
314 | ||
5dd53f43 KZ |
315 | if (lseek(fd, pagesize - SWAP_SIGNATURE_SZ, SEEK_SET) < 0) { |
316 | warn(_("%s: lseek failed"), devname); | |
617d8a3b | 317 | goto err; |
5dd53f43 | 318 | } |
617d8a3b KZ |
319 | |
320 | if (write(fd, (void *) SWAP_SIGNATURE, | |
5dd53f43 KZ |
321 | SWAP_SIGNATURE_SZ) != SWAP_SIGNATURE_SZ) { |
322 | warn(_("%s: write signature failed"), devname); | |
617d8a3b | 323 | goto err; |
5dd53f43 | 324 | } |
617d8a3b KZ |
325 | |
326 | rc = 0; | |
327 | err: | |
14699715 SK |
328 | if (close_fd(fd) != 0) { |
329 | warn(_("write failed: %s"), devname); | |
330 | rc = -1; | |
331 | } | |
617d8a3b KZ |
332 | return rc; |
333 | } | |
334 | ||
d335c9bd | 335 | static int swap_detect_signature(const char *buf, int *sig) |
3399a218 | 336 | { |
e8be80dd KZ |
337 | if (memcmp(buf, "SWAP-SPACE", 10) == 0 || |
338 | memcmp(buf, "SWAPSPACE2", 10) == 0) | |
339 | *sig = SIG_SWAPSPACE; | |
340 | ||
341 | else if (memcmp(buf, "S1SUSPEND", 9) == 0 || | |
342 | memcmp(buf, "S2SUSPEND", 9) == 0 || | |
343 | memcmp(buf, "ULSUSPEND", 9) == 0 || | |
5a16af58 KZ |
344 | memcmp(buf, "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8) == 0 || |
345 | memcmp(buf, "LINHIB0001", 10) == 0) | |
e8be80dd KZ |
346 | *sig = SIG_SWSUSPEND; |
347 | else | |
348 | return 0; | |
3399a218 | 349 | |
e8be80dd | 350 | return 1; |
3399a218 MK |
351 | } |
352 | ||
d335c9bd | 353 | static char *swap_get_header(int fd, int *sig, unsigned int *pagesize) |
3399a218 | 354 | { |
3399a218 | 355 | char *buf; |
e8be80dd KZ |
356 | ssize_t datasz; |
357 | unsigned int page; | |
3399a218 | 358 | |
e8be80dd KZ |
359 | *pagesize = 0; |
360 | *sig = 0; | |
3399a218 | 361 | |
bfbb12d2 | 362 | buf = xmalloc(MAX_PAGESIZE); |
3399a218 MK |
363 | |
364 | datasz = read(fd, buf, MAX_PAGESIZE); | |
e8be80dd KZ |
365 | if (datasz == (ssize_t) -1) |
366 | goto err; | |
3399a218 MK |
367 | |
368 | for (page = 0x1000; page <= MAX_PAGESIZE; page <<= 1) { | |
369 | /* skip 32k pagesize since this does not seem to | |
370 | * be supported */ | |
371 | if (page == 0x8000) | |
372 | continue; | |
373 | /* the smallest swap area is PAGE_SIZE*10, it means | |
374 | * 40k, that's less than MAX_PAGESIZE */ | |
24f010e8 | 375 | if (datasz < 0 || (size_t) datasz < (page - SWAP_SIGNATURE_SZ)) |
3399a218 | 376 | break; |
617d8a3b | 377 | if (swap_detect_signature(buf + page - SWAP_SIGNATURE_SZ, sig)) { |
e8be80dd | 378 | *pagesize = page; |
3399a218 MK |
379 | break; |
380 | } | |
381 | } | |
382 | ||
e8be80dd KZ |
383 | if (*pagesize) |
384 | return buf; | |
3399a218 | 385 | err: |
e8be80dd KZ |
386 | free(buf); |
387 | return NULL; | |
388 | } | |
389 | ||
390 | /* returns real size of swap space */ | |
d335c9bd KZ |
391 | static unsigned long long swap_get_size(const char *hdr, const char *devname, |
392 | unsigned int pagesize) | |
e8be80dd KZ |
393 | { |
394 | unsigned int last_page = 0; | |
395 | int swap_version = 0; | |
396 | int flip = 0; | |
397 | struct swap_header_v1_2 *s; | |
398 | ||
399 | s = (struct swap_header_v1_2 *) hdr; | |
400 | if (s->version == 1) { | |
401 | swap_version = 1; | |
402 | last_page = s->last_page; | |
403 | } else if (swab32(s->version) == 1) { | |
404 | flip = 1; | |
405 | swap_version = 1; | |
406 | last_page = swab32(s->last_page); | |
407 | } | |
408 | if (verbose) | |
04c94441 KZ |
409 | warnx(_("%s: found swap signature: version %d, " |
410 | "page-size %d, %s byte order"), | |
e8be80dd | 411 | devname, |
e8be80dd | 412 | swap_version, |
04c94441 KZ |
413 | pagesize / 1024, |
414 | flip ? _("different") : _("same")); | |
e8be80dd | 415 | |
98e9ff61 | 416 | return ((unsigned long long) last_page + 1) * pagesize; |
3399a218 MK |
417 | } |
418 | ||
d335c9bd | 419 | static void swap_get_info(const char *hdr, char **label, char **uuid) |
b5b2c388 KZ |
420 | { |
421 | struct swap_header_v1_2 *s = (struct swap_header_v1_2 *) hdr; | |
422 | ||
423 | if (s && *s->volume_name && label) | |
424 | *label = xstrdup(s->volume_name); | |
425 | ||
426 | if (s && *s->uuid && uuid) { | |
427 | const unsigned char *u = s->uuid; | |
428 | char str[37]; | |
429 | ||
430 | snprintf(str, sizeof(str), | |
431 | "%02x%02x%02x%02x-" | |
432 | "%02x%02x-%02x%02x-" | |
433 | "%02x%02x-%02x%02x%02x%02x%02x%02x", | |
434 | u[0], u[1], u[2], u[3], | |
435 | u[4], u[5], u[6], u[7], | |
436 | u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15]); | |
437 | *uuid = xstrdup(str); | |
438 | } | |
439 | } | |
440 | ||
d335c9bd | 441 | static int swapon_checks(const char *special) |
05c79b78 | 442 | { |
63cccae4 | 443 | struct stat st; |
05c79b78 KZ |
444 | int fd = -1, sig; |
445 | char *hdr = NULL; | |
e8be80dd KZ |
446 | unsigned int pagesize; |
447 | unsigned long long devsize = 0; | |
cd04b26b | 448 | int permMask; |
63cccae4 | 449 | |
63cccae4 | 450 | if (stat(special, &st) < 0) { |
add1b8af | 451 | warn(_("stat failed %s"), special); |
05c79b78 | 452 | goto err; |
63cccae4 KZ |
453 | } |
454 | ||
cd04b26b KZ |
455 | permMask = S_ISBLK(st.st_mode) ? 07007 : 07077; |
456 | if ((st.st_mode & permMask) != 0) | |
457 | warnx(_("%s: insecure permissions %04o, %04o suggested."), | |
d51d05d3 | 458 | special, st.st_mode & 07777, |
88530f9f | 459 | ~permMask & 0666); |
306c1df2 | 460 | |
cd04b26b KZ |
461 | if (S_ISREG(st.st_mode) && st.st_uid != 0) |
462 | warnx(_("%s: insecure file owner %d, 0 (root) suggested."), | |
306c1df2 | 463 | special, st.st_uid); |
88530f9f KZ |
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 |
540 | err: |
541 | if (fd != -1) | |
542 | close(fd); | |
543 | free(hdr); | |
544 | return -1; | |
545 | } | |
63cccae4 | 546 | |
d335c9bd KZ |
547 | static 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 |
585 | static 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 |
592 | static 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 |
599 | static 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 |
643 | static 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 |
685 | int 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 | ||
d96b743f | 790 | if (show || (!all && !numof_labels() && !numof_uuids() && *argv == NULL)) { |
e076b552 SK |
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 | ||
d9f07b10 | 803 | if (ifexists && !all) |
8b0d5341 | 804 | usage(stderr); |
95f1bdee | 805 | |
756bfd01 KZ |
806 | if (all) |
807 | status |= swapon_all(); | |
63cccae4 | 808 | |
0b0c231f KZ |
809 | for (i = 0; i < numof_labels(); i++) |
810 | status |= swapon_by_label(get_label(i), priority, discard); | |
63cccae4 | 811 | |
0b0c231f KZ |
812 | for (i = 0; i < numof_uuids(); i++) |
813 | status |= swapon_by_uuid(get_uuid(i), priority, discard); | |
63cccae4 KZ |
814 | |
815 | while (*argv != NULL) | |
c2301380 | 816 | status |= do_swapon(*argv++, priority, discard, !CANONIC); |
63cccae4 | 817 | |
0b0c231f | 818 | free_tables(); |
6195f9e6 | 819 | mnt_unref_cache(mntcache); |
d9f07b10 | 820 | |
64b58881 | 821 | return status; |
6dbe3af9 | 822 | } |