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