]>
Commit | Line | Data |
---|---|---|
6cf8d46c | 1 | #include <stdio.h> |
6cf8d46c | 2 | #include <errno.h> |
7cf6a654 | 3 | #include <getopt.h> |
6cf8d46c KZ |
4 | |
5 | #ifdef HAVE_SYS_SWAP_H | |
6 | # include <sys/swap.h> | |
7 | #endif | |
8 | ||
9 | #include "nls.h" | |
10 | #include "c.h" | |
52f2fd9b | 11 | #include "xalloc.h" |
6cf8d46c KZ |
12 | #include "closestream.h" |
13 | ||
52f2fd9b | 14 | #include "swapprober.h" |
6cf8d46c KZ |
15 | #include "swapon-common.h" |
16 | ||
cf9b16f1 | 17 | #if !defined(HAVE_SWAPOFF) && defined(SYS_swapoff) |
6cf8d46c KZ |
18 | # include <sys/syscall.h> |
19 | # define swapoff(path) syscall(SYS_swapoff, path) | |
20 | #endif | |
21 | ||
22 | static int verbose; | |
23 | static int all; | |
24 | ||
25 | #define QUIET 1 | |
26 | #define CANONIC 1 | |
27 | ||
ecfa4dad | 28 | #define SWAPOFF_EX_OK 0 /* no errors */ |
e4253d3c KZ |
29 | #define SWAPOFF_EX_ENOMEM 2 /* swapoff(2) failed due to OOM */ |
30 | #define SWAPOFF_EX_FAILURE 4 /* swapoff(2) failed due to another reason */ | |
31 | #define SWAPOFF_EX_SYSERR 8 /* non-swaoff() errors */ | |
ecfa4dad KZ |
32 | #define SWAPOFF_EX_USAGE 16 /* usage, permissions or syntax error */ |
33 | #define SWAPOFF_EX_ALLERR 32 /* --all all failed */ | |
34 | #define SWAPOFF_EX_SOMEOK 64 /* --all some failed some OK */ | |
35 | ||
52f2fd9b | 36 | /* |
9e930041 | 37 | * This function works like mnt_resolve_tag(), but it's able to read UUID/LABEL |
52f2fd9b KZ |
38 | * from regular swap files too (according to entries in /proc/swaps). Note that |
39 | * mnt_resolve_tag() and mnt_resolve_spec() works with system visible block | |
40 | * devices only. | |
41 | */ | |
42 | static char *swapoff_resolve_tag(const char *name, const char *value, | |
43 | struct libmnt_cache *cache) | |
44 | { | |
45 | char *path; | |
46 | struct libmnt_table *tb; | |
47 | struct libmnt_iter *itr; | |
48 | struct libmnt_fs *fs; | |
49 | ||
50 | /* this is usual case for block devices (and it's really fast as it uses | |
51 | * udev /dev/disk/by-* symlinks by default */ | |
52 | path = mnt_resolve_tag(name, value, cache); | |
53 | if (path) | |
54 | return path; | |
55 | ||
56 | /* try regular files from /proc/swaps */ | |
57 | tb = get_swaps(); | |
58 | if (!tb) | |
59 | return NULL; | |
60 | ||
61 | itr = mnt_new_iter(MNT_ITER_BACKWARD); | |
62 | if (!itr) | |
ecfa4dad | 63 | err(SWAPOFF_EX_SYSERR, _("failed to initialize libmount iterator")); |
52f2fd9b KZ |
64 | |
65 | while (tb && mnt_table_next_fs(tb, itr, &fs) == 0) { | |
66 | blkid_probe pr = NULL; | |
67 | const char *src = mnt_fs_get_source(fs); | |
68 | const char *type = mnt_fs_get_swaptype(fs); | |
69 | const char *data = NULL; | |
70 | ||
71 | if (!src || !type || strcmp(type, "file") != 0) | |
72 | continue; | |
73 | pr = get_swap_prober(src); | |
74 | if (!pr) | |
75 | continue; | |
76 | blkid_probe_lookup_value(pr, name, &data, NULL); | |
77 | if (data && strcmp(data, value) == 0) | |
78 | path = xstrdup(src); | |
79 | blkid_free_probe(pr); | |
80 | if (path) | |
81 | break; | |
82 | } | |
83 | ||
84 | mnt_free_iter(itr); | |
85 | return path; | |
86 | } | |
87 | ||
6cf8d46c KZ |
88 | static int do_swapoff(const char *orig_special, int quiet, int canonic) |
89 | { | |
90 | const char *special = orig_special; | |
ecfa4dad | 91 | int rc = SWAPOFF_EX_OK; |
6cf8d46c KZ |
92 | |
93 | if (verbose) | |
e7b63bea | 94 | printf(_("swapoff %s\n"), orig_special); |
6cf8d46c KZ |
95 | |
96 | if (!canonic) { | |
52f2fd9b KZ |
97 | char *n, *v; |
98 | ||
6cf8d46c | 99 | special = mnt_resolve_spec(orig_special, mntcache); |
eeea7ef5 | 100 | if (!special && blkid_parse_tag_string(orig_special, &n, &v) == 0) { |
52f2fd9b | 101 | special = swapoff_resolve_tag(n, v, mntcache); |
eeea7ef5 KZ |
102 | free(n); |
103 | free(v); | |
104 | } | |
6cf8d46c KZ |
105 | if (!special) |
106 | return cannot_find(orig_special); | |
107 | } | |
108 | ||
109 | if (swapoff(special) == 0) | |
ecfa4dad KZ |
110 | rc = SWAPOFF_EX_OK; /* success */ |
111 | else { | |
112 | switch (errno) { | |
113 | case EPERM: | |
114 | errx(SWAPOFF_EX_USAGE, _("Not superuser.")); | |
115 | break; | |
116 | case ENOMEM: | |
117 | warn(_("%s: swapoff failed"), orig_special); | |
118 | rc = SWAPOFF_EX_ENOMEM; | |
119 | break; | |
120 | default: | |
121 | if (!quiet) | |
122 | warn(_("%s: swapoff failed"), orig_special); | |
123 | rc = SWAPOFF_EX_FAILURE; | |
124 | break; | |
125 | } | |
126 | } | |
6cf8d46c | 127 | |
ecfa4dad | 128 | return rc; |
6cf8d46c KZ |
129 | } |
130 | ||
52f2fd9b | 131 | static int swapoff_by(const char *name, const char *value, int quiet) |
6cf8d46c | 132 | { |
52f2fd9b KZ |
133 | const char *special = swapoff_resolve_tag(name, value, mntcache); |
134 | return special ? do_swapoff(special, quiet, CANONIC) : cannot_find(value); | |
6cf8d46c KZ |
135 | } |
136 | ||
6e1eda6f | 137 | static void __attribute__((__noreturn__)) usage(void) |
6cf8d46c | 138 | { |
6e1eda6f | 139 | FILE *out = stdout; |
7cf6a654 | 140 | fputs(USAGE_HEADER, out); |
6cf8d46c KZ |
141 | fprintf(out, _(" %s [options] [<spec>]\n"), program_invocation_short_name); |
142 | ||
451dbcfa BS |
143 | fputs(USAGE_SEPARATOR, out); |
144 | fputs(_("Disable devices and files for paging and swapping.\n"), out); | |
145 | ||
7cf6a654 | 146 | fputs(USAGE_OPTIONS, out); |
6cf8d46c | 147 | fputs(_(" -a, --all disable all swaps from /proc/swaps\n" |
7cf6a654 KZ |
148 | " -v, --verbose verbose mode\n"), out); |
149 | ||
150 | fputs(USAGE_SEPARATOR, out); | |
bad4c729 | 151 | fprintf(out, USAGE_HELP_OPTIONS(24)); |
6cf8d46c KZ |
152 | |
153 | fputs(_("\nThe <spec> parameter:\n" \ | |
154 | " -L <label> LABEL of device to be used\n" \ | |
155 | " -U <uuid> UUID of device to be used\n" \ | |
156 | " LABEL=<label> LABEL of device to be used\n" \ | |
157 | " UUID=<uuid> UUID of device to be used\n" \ | |
158 | " <device> name of device to be used\n" \ | |
7cf6a654 KZ |
159 | " <file> name of file to be used\n"), out); |
160 | ||
bad4c729 | 161 | fprintf(out, USAGE_MAN_TAIL("swapoff(8)")); |
ecfa4dad | 162 | exit(SWAPOFF_EX_OK); |
6cf8d46c KZ |
163 | } |
164 | ||
e7b63bea KZ |
165 | static int swapoff_all(void) |
166 | { | |
ecfa4dad | 167 | int nerrs = 0, nsucc = 0; |
e7b63bea KZ |
168 | struct libmnt_table *tb; |
169 | struct libmnt_fs *fs; | |
170 | struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD); | |
171 | ||
172 | if (!itr) | |
ecfa4dad | 173 | err(SWAPOFF_EX_SYSERR, _("failed to initialize libmount iterator")); |
e7b63bea KZ |
174 | |
175 | /* | |
176 | * In case /proc/swaps exists, unswap stuff listed there. We are quiet | |
177 | * but report errors in status. Errors might mean that /proc/swaps | |
178 | * exists as ordinary file, not in procfs. do_swapoff() exits | |
179 | * immediately on EPERM. | |
180 | */ | |
181 | tb = get_swaps(); | |
182 | ||
ecfa4dad KZ |
183 | while (tb && mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) { |
184 | if (do_swapoff(mnt_fs_get_source(fs), QUIET, CANONIC) == SWAPOFF_EX_OK) | |
185 | nsucc++; | |
186 | else | |
187 | nerrs++; | |
188 | } | |
e7b63bea KZ |
189 | |
190 | /* | |
191 | * Unswap stuff mentioned in /etc/fstab. Probably it was unmounted | |
192 | * already, so errors are not bad. Doing swapoff -a twice should not | |
193 | * give error messages. | |
194 | */ | |
a5a9b544 | 195 | tb = get_fstab(NULL); |
e7b63bea KZ |
196 | mnt_reset_iter(itr, MNT_ITER_FORWARD); |
197 | ||
198 | while (tb && mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) { | |
199 | if (!is_active_swap(mnt_fs_get_source(fs))) | |
200 | do_swapoff(mnt_fs_get_source(fs), QUIET, !CANONIC); | |
201 | } | |
202 | ||
203 | mnt_free_iter(itr); | |
ecfa4dad KZ |
204 | |
205 | if (nerrs == 0) | |
206 | return SWAPOFF_EX_OK; /* all success */ | |
207 | else if (nsucc == 0) | |
208 | return SWAPOFF_EX_ALLERR; /* all failed */ | |
209 | ||
210 | return SWAPOFF_EX_SOMEOK; /* some success, some failed */ | |
e7b63bea | 211 | } |
6cf8d46c KZ |
212 | |
213 | int main(int argc, char *argv[]) | |
214 | { | |
6cf8d46c KZ |
215 | int status = 0, c; |
216 | size_t i; | |
217 | ||
218 | static const struct option long_opts[] = { | |
87918040 SK |
219 | { "all", no_argument, NULL, 'a' }, |
220 | { "help", no_argument, NULL, 'h' }, | |
221 | { "verbose", no_argument, NULL, 'v' }, | |
222 | { "version", no_argument, NULL, 'V' }, | |
223 | { NULL, 0, NULL, 0 } | |
6cf8d46c KZ |
224 | }; |
225 | ||
226 | setlocale(LC_ALL, ""); | |
227 | bindtextdomain(PACKAGE, LOCALEDIR); | |
228 | textdomain(PACKAGE); | |
2c308875 | 229 | close_stdout_atexit(); |
6cf8d46c KZ |
230 | |
231 | while ((c = getopt_long(argc, argv, "ahvVL:U:", | |
232 | long_opts, NULL)) != -1) { | |
233 | switch (c) { | |
234 | case 'a': /* all */ | |
235 | ++all; | |
236 | break; | |
6cf8d46c KZ |
237 | case 'v': /* be chatty */ |
238 | ++verbose; | |
239 | break; | |
6cf8d46c KZ |
240 | case 'L': |
241 | add_label(optarg); | |
242 | break; | |
243 | case 'U': | |
244 | add_uuid(optarg); | |
245 | break; | |
2c308875 KZ |
246 | |
247 | case 'h': /* help */ | |
248 | usage(); | |
249 | case 'V': /* version */ | |
ecfa4dad | 250 | print_version(SWAPOFF_EX_OK); |
6cf8d46c | 251 | default: |
ecfa4dad | 252 | errtryhelp(SWAPOFF_EX_USAGE); |
6cf8d46c KZ |
253 | } |
254 | } | |
255 | argv += optind; | |
256 | ||
6e1eda6f RM |
257 | if (!all && !numof_labels() && !numof_uuids() && *argv == NULL) { |
258 | warnx(_("bad usage")); | |
ecfa4dad | 259 | errtryhelp(SWAPOFF_EX_USAGE); |
6e1eda6f | 260 | } |
6cf8d46c KZ |
261 | |
262 | mnt_init_debug(0); | |
263 | mntcache = mnt_new_cache(); | |
264 | ||
6cf8d46c | 265 | for (i = 0; i < numof_labels(); i++) |
52f2fd9b | 266 | status |= swapoff_by("LABEL", get_label(i), !QUIET); |
6cf8d46c KZ |
267 | |
268 | for (i = 0; i < numof_uuids(); i++) | |
52f2fd9b | 269 | status |= swapoff_by("UUID", get_uuid(i), !QUIET); |
6cf8d46c KZ |
270 | |
271 | while (*argv != NULL) | |
272 | status |= do_swapoff(*argv++, !QUIET, !CANONIC); | |
273 | ||
e7b63bea KZ |
274 | if (all) |
275 | status |= swapoff_all(); | |
6cf8d46c KZ |
276 | |
277 | free_tables(); | |
6195f9e6 | 278 | mnt_unref_cache(mntcache); |
6cf8d46c KZ |
279 | |
280 | return status; | |
281 | } |