2 * SPDX-License-Identifier: GPL-2.0-or-later
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.
9 * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com>
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.
18 #ifdef HAVE_SYS_SWAP_H
19 # include <sys/swap.h>
25 #include "closestream.h"
27 #include "swapprober.h"
28 #include "swapon-common.h"
30 #if !defined(HAVE_SWAPOFF) && defined(SYS_swapoff)
31 # include <sys/syscall.h>
32 # define swapoff(path) syscall(SYS_swapoff, path)
41 #define SWAPOFF_EX_OK 0 /* no errors */
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 */
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 */
50 * This function works like mnt_resolve_tag(), but it's able to read UUID/LABEL
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
55 static char *swapoff_resolve_tag(const char *name
, const char *value
,
56 struct libmnt_cache
*cache
)
59 struct libmnt_table
*tb
;
60 struct libmnt_iter
*itr
;
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
);
69 /* try regular files from /proc/swaps */
74 itr
= mnt_new_iter(MNT_ITER_BACKWARD
);
76 err(SWAPOFF_EX_SYSERR
, _("failed to initialize libmount iterator"));
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
;
84 if (!src
|| !type
|| strcmp(type
, "file") != 0)
86 pr
= get_swap_prober(src
);
89 blkid_probe_lookup_value(pr
, name
, &data
, NULL
);
90 if (data
&& strcmp(data
, value
) == 0)
101 static int do_swapoff(const char *orig_special
, int quiet
, int canonic
)
103 const char *special
= orig_special
;
104 int rc
= SWAPOFF_EX_OK
;
107 printf(_("swapoff %s\n"), orig_special
);
112 special
= mnt_resolve_spec(orig_special
, mntcache
);
113 if (!special
&& blkid_parse_tag_string(orig_special
, &n
, &v
) == 0) {
114 special
= swapoff_resolve_tag(n
, v
, mntcache
);
119 return cannot_find(orig_special
);
122 if (swapoff(special
) == 0)
123 rc
= SWAPOFF_EX_OK
; /* success */
127 errx(SWAPOFF_EX_USAGE
, _("Not superuser."));
130 warn(_("%s: swapoff failed"), orig_special
);
131 rc
= SWAPOFF_EX_ENOMEM
;
135 warn(_("%s: swapoff failed"), orig_special
);
136 rc
= SWAPOFF_EX_FAILURE
;
144 static int swapoff_by(const char *name
, const char *value
, int quiet
)
146 const char *special
= swapoff_resolve_tag(name
, value
, mntcache
);
147 return special
? do_swapoff(special
, quiet
, CANONIC
) : cannot_find(value
);
150 static void __attribute__((__noreturn__
)) usage(void)
153 fputs(USAGE_HEADER
, out
);
154 fprintf(out
, _(" %s [options] [<spec>]\n"), program_invocation_short_name
);
156 fputs(USAGE_SEPARATOR
, out
);
157 fputs(_("Disable devices and files for paging and swapping.\n"), out
);
159 fputs(USAGE_OPTIONS
, out
);
160 fputs(_(" -a, --all disable all swaps from /proc/swaps\n"
161 " -v, --verbose verbose mode\n"), out
);
163 fputs(USAGE_SEPARATOR
, out
);
164 fprintf(out
, USAGE_HELP_OPTIONS(24));
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" \
172 " <file> name of file to be used\n"), out
);
174 fprintf(out
, USAGE_MAN_TAIL("swapoff(8)"));
178 static int swapoff_all(void)
180 int nerrs
= 0, nsucc
= 0;
181 struct libmnt_table
*tb
;
182 struct libmnt_fs
*fs
;
183 struct libmnt_iter
*itr
= mnt_new_iter(MNT_ITER_BACKWARD
);
186 err(SWAPOFF_EX_SYSERR
, _("failed to initialize libmount iterator"));
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.
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
)
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.
208 tb
= get_fstab(NULL
);
209 mnt_reset_iter(itr
, MNT_ITER_FORWARD
);
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
);
219 return SWAPOFF_EX_OK
; /* all success */
221 return SWAPOFF_EX_ALLERR
; /* all failed */
223 return SWAPOFF_EX_SOMEOK
; /* some success, some failed */
226 int main(int argc
, char *argv
[])
231 static const struct option long_opts
[] = {
232 { "all", no_argument
, NULL
, 'a' },
233 { "help", no_argument
, NULL
, 'h' },
234 { "verbose", no_argument
, NULL
, 'v' },
235 { "version", no_argument
, NULL
, 'V' },
239 setlocale(LC_ALL
, "");
240 bindtextdomain(PACKAGE
, LOCALEDIR
);
242 close_stdout_atexit();
244 while ((c
= getopt_long(argc
, argv
, "ahvVL:U:",
245 long_opts
, NULL
)) != -1) {
250 case 'v': /* be chatty */
262 case 'V': /* version */
263 print_version(SWAPOFF_EX_OK
);
265 errtryhelp(SWAPOFF_EX_USAGE
);
270 if (!all
&& !numof_labels() && !numof_uuids() && *argv
== NULL
) {
271 warnx(_("bad usage"));
272 errtryhelp(SWAPOFF_EX_USAGE
);
276 mntcache
= mnt_new_cache();
278 for (i
= 0; i
< numof_labels(); i
++)
279 status
|= swapoff_by("LABEL", get_label(i
), !QUIET
);
281 for (i
= 0; i
< numof_uuids(); i
++)
282 status
|= swapoff_by("UUID", get_uuid(i
), !QUIET
);
284 while (*argv
!= NULL
)
285 status
|= do_swapoff(*argv
++, !QUIET
, !CANONIC
);
288 status
|= swapoff_all();
291 mnt_unref_cache(mntcache
);