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