]>
Commit | Line | Data |
---|---|---|
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 |
46 | enum { |
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 | 54 | int all; |
726f69e2 | 55 | int 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 |
58 | int ifexists; |
59 | ||
60 | int verbose; | |
61 | char *progname; | |
95f1bdee | 62 | |
63cccae4 KZ |
63 | static 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 | 76 | static struct option *longswapoffopts = &longswaponopts[3]; |
63cccae4 | 77 | |
12ac2bbe KZ |
78 | static 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 | 88 | static void |
63cccae4 | 89 | swapon_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 | ||
102 | static void | |
103 | swapoff_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 | */ | |
118 | static int numSwaps; | |
119 | static char **swapFiles; /* array of swap file and partition names */ | |
6dbe3af9 | 120 | |
63cccae4 KZ |
121 | static void |
122 | read_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 | ||
158 | static int | |
756bfd01 | 159 | is_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 |
168 | static int |
169 | display_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 */ |
187 | static int | |
188 | swap_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 |
234 | static int |
235 | swap_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; | |
253 | err: | |
254 | close(fd); | |
255 | return rc; | |
256 | } | |
257 | ||
e8be80dd KZ |
258 | static int |
259 | swap_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 |
276 | static char * |
277 | swap_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 | 311 | err: |
e8be80dd KZ |
312 | free(buf); |
313 | return NULL; | |
314 | } | |
315 | ||
316 | /* returns real size of swap space */ | |
317 | unsigned long long | |
318 | swap_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 | 345 | static int |
05c79b78 KZ |
346 | swapon_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 |
431 | err: |
432 | if (fd != -1) | |
433 | close(fd); | |
434 | free(hdr); | |
435 | return -1; | |
436 | } | |
63cccae4 | 437 | |
05c79b78 KZ |
438 | static int |
439 | do_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 | ||
472 | static int | |
756bfd01 | 473 | cannot_find(const char *special) { |
d51d05d3 | 474 | warnx(_("cannot find the device for %s"), special); |
756bfd01 KZ |
475 | return -1; |
476 | } | |
477 | ||
478 | static int | |
479 | swapon_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 | ||
484 | static int | |
485 | swapon_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 | ||
490 | static int | |
12ac2bbe KZ |
491 | do_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 | ||
515 | static int | |
756bfd01 | 516 | swapoff_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 | ||
521 | static int | |
522 | swapoff_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 | ||
527 | static int | |
528 | swapon_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 | ||
580 | static const char **llist = NULL; | |
581 | static int llct = 0; | |
582 | static const char **ulist = NULL; | |
583 | static int ulct = 0; | |
584 | ||
585 | static 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 | ||
592 | static 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 | ||
599 | static int | |
600 | main_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 | ||
664 | static int | |
665 | main_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 | ||
757 | int | |
758 | main(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 | } |