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