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