12 #include "closestream.h"
14 #include "swapprober.h"
15 #include "swapon-common.h"
17 #if !defined(HAVE_SWAPOFF) && defined(SYS_swapoff)
18 # include <sys/syscall.h>
19 # define swapoff(path) syscall(SYS_swapoff, path)
28 #define SWAPOFF_EX_OK 0 /* no errors */
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 */
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 */
37 * This function works like mnt_resolve_tag(), but it's able to read UUID/LABEL
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
42 static char *swapoff_resolve_tag(const char *name
, const char *value
,
43 struct libmnt_cache
*cache
)
46 struct libmnt_table
*tb
;
47 struct libmnt_iter
*itr
;
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
);
56 /* try regular files from /proc/swaps */
61 itr
= mnt_new_iter(MNT_ITER_BACKWARD
);
63 err(SWAPOFF_EX_SYSERR
, _("failed to initialize libmount iterator"));
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
;
71 if (!src
|| !type
|| strcmp(type
, "file") != 0)
73 pr
= get_swap_prober(src
);
76 blkid_probe_lookup_value(pr
, name
, &data
, NULL
);
77 if (data
&& strcmp(data
, value
) == 0)
88 static int do_swapoff(const char *orig_special
, int quiet
, int canonic
)
90 const char *special
= orig_special
;
91 int rc
= SWAPOFF_EX_OK
;
94 printf(_("swapoff %s\n"), orig_special
);
99 special
= mnt_resolve_spec(orig_special
, mntcache
);
100 if (!special
&& blkid_parse_tag_string(orig_special
, &n
, &v
) == 0) {
101 special
= swapoff_resolve_tag(n
, v
, mntcache
);
106 return cannot_find(orig_special
);
109 if (swapoff(special
) == 0)
110 rc
= SWAPOFF_EX_OK
; /* success */
114 errx(SWAPOFF_EX_USAGE
, _("Not superuser."));
117 warn(_("%s: swapoff failed"), orig_special
);
118 rc
= SWAPOFF_EX_ENOMEM
;
122 warn(_("%s: swapoff failed"), orig_special
);
123 rc
= SWAPOFF_EX_FAILURE
;
131 static int swapoff_by(const char *name
, const char *value
, int quiet
)
133 const char *special
= swapoff_resolve_tag(name
, value
, mntcache
);
134 return special
? do_swapoff(special
, quiet
, CANONIC
) : cannot_find(value
);
137 static void __attribute__((__noreturn__
)) usage(void)
140 fputs(USAGE_HEADER
, out
);
141 fprintf(out
, _(" %s [options] [<spec>]\n"), program_invocation_short_name
);
143 fputs(USAGE_SEPARATOR
, out
);
144 fputs(_("Disable devices and files for paging and swapping.\n"), out
);
146 fputs(USAGE_OPTIONS
, out
);
147 fputs(_(" -a, --all disable all swaps from /proc/swaps\n"
148 " -v, --verbose verbose mode\n"), out
);
150 fputs(USAGE_SEPARATOR
, out
);
151 fprintf(out
, USAGE_HELP_OPTIONS(24));
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" \
159 " <file> name of file to be used\n"), out
);
161 fprintf(out
, USAGE_MAN_TAIL("swapoff(8)"));
165 static int swapoff_all(void)
167 int nerrs
= 0, nsucc
= 0;
168 struct libmnt_table
*tb
;
169 struct libmnt_fs
*fs
;
170 struct libmnt_iter
*itr
= mnt_new_iter(MNT_ITER_BACKWARD
);
173 err(SWAPOFF_EX_SYSERR
, _("failed to initialize libmount iterator"));
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.
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
)
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.
195 tb
= get_fstab(NULL
);
196 mnt_reset_iter(itr
, MNT_ITER_FORWARD
);
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
);
206 return SWAPOFF_EX_OK
; /* all success */
208 return SWAPOFF_EX_ALLERR
; /* all failed */
210 return SWAPOFF_EX_SOMEOK
; /* some success, some failed */
213 int main(int argc
, char *argv
[])
218 static const struct option long_opts
[] = {
219 { "all", no_argument
, NULL
, 'a' },
220 { "help", no_argument
, NULL
, 'h' },
221 { "verbose", no_argument
, NULL
, 'v' },
222 { "version", no_argument
, NULL
, 'V' },
226 setlocale(LC_ALL
, "");
227 bindtextdomain(PACKAGE
, LOCALEDIR
);
229 close_stdout_atexit();
231 while ((c
= getopt_long(argc
, argv
, "ahvVL:U:",
232 long_opts
, NULL
)) != -1) {
237 case 'v': /* be chatty */
249 case 'V': /* version */
250 print_version(SWAPOFF_EX_OK
);
252 errtryhelp(SWAPOFF_EX_USAGE
);
257 if (!all
&& !numof_labels() && !numof_uuids() && *argv
== NULL
) {
258 warnx(_("bad usage"));
259 errtryhelp(SWAPOFF_EX_USAGE
);
263 mntcache
= mnt_new_cache();
265 for (i
= 0; i
< numof_labels(); i
++)
266 status
|= swapoff_by("LABEL", get_label(i
), !QUIET
);
268 for (i
= 0; i
< numof_uuids(); i
++)
269 status
|= swapoff_by("UUID", get_uuid(i
), !QUIET
);
271 while (*argv
!= NULL
)
272 status
|= do_swapoff(*argv
++, !QUIET
, !CANONIC
);
275 status
|= swapoff_all();
278 mnt_unref_cache(mntcache
);