| #include <stdio.h> |
| #include <errno.h> |
| #include <getopt.h> |
| |
| #ifdef HAVE_SYS_SWAP_H |
| # include <sys/swap.h> |
| #endif |
| |
| #include "nls.h" |
| #include "c.h" |
| #include "xalloc.h" |
| #include "closestream.h" |
| |
| #include "swapprober.h" |
| #include "swapon-common.h" |
| |
| #if !defined(HAVE_SWAPOFF) && defined(SYS_swapoff) |
| # include <sys/syscall.h> |
| # define swapoff(path) syscall(SYS_swapoff, path) |
| #endif |
| |
| static int verbose; |
| static int all; |
| |
| #define QUIET 1 |
| #define CANONIC 1 |
| |
| /* |
| * This function works like mnt_resolve_tag(), but it's able to read UUID/LABEL |
| * from regular swap files too (according to entries in /proc/swaps). Note that |
| * mnt_resolve_tag() and mnt_resolve_spec() works with system visible block |
| * devices only. |
| */ |
| static char *swapoff_resolve_tag(const char *name, const char *value, |
| struct libmnt_cache *cache) |
| { |
| char *path; |
| struct libmnt_table *tb; |
| struct libmnt_iter *itr; |
| struct libmnt_fs *fs; |
| |
| /* this is usual case for block devices (and it's really fast as it uses |
| * udev /dev/disk/by-* symlinks by default */ |
| path = mnt_resolve_tag(name, value, cache); |
| if (path) |
| return path; |
| |
| /* try regular files from /proc/swaps */ |
| tb = get_swaps(); |
| if (!tb) |
| return NULL; |
| |
| itr = mnt_new_iter(MNT_ITER_BACKWARD); |
| if (!itr) |
| err(EXIT_FAILURE, _("failed to initialize libmount iterator")); |
| |
| while (tb && mnt_table_next_fs(tb, itr, &fs) == 0) { |
| blkid_probe pr = NULL; |
| const char *src = mnt_fs_get_source(fs); |
| const char *type = mnt_fs_get_swaptype(fs); |
| const char *data = NULL; |
| |
| if (!src || !type || strcmp(type, "file") != 0) |
| continue; |
| pr = get_swap_prober(src); |
| if (!pr) |
| continue; |
| blkid_probe_lookup_value(pr, name, &data, NULL); |
| if (data && strcmp(data, value) == 0) |
| path = xstrdup(src); |
| blkid_free_probe(pr); |
| if (path) |
| break; |
| } |
| |
| mnt_free_iter(itr); |
| return path; |
| } |
| |
| static int do_swapoff(const char *orig_special, int quiet, int canonic) |
| { |
| const char *special = orig_special; |
| |
| if (verbose) |
| printf(_("swapoff %s\n"), orig_special); |
| |
| if (!canonic) { |
| char *n, *v; |
| |
| special = mnt_resolve_spec(orig_special, mntcache); |
| if (!special && blkid_parse_tag_string(orig_special, &n, &v) == 0) { |
| special = swapoff_resolve_tag(n, v, mntcache); |
| free(n); |
| free(v); |
| } |
| if (!special) |
| return cannot_find(orig_special); |
| } |
| |
| if (swapoff(special) == 0) |
| return 0; /* success */ |
| |
| if (errno == EPERM) |
| errx(EXIT_FAILURE, _("Not superuser.")); |
| |
| if (!quiet || errno == ENOMEM) |
| warn(_("%s: swapoff failed"), orig_special); |
| |
| return -1; |
| } |
| |
| static int swapoff_by(const char *name, const char *value, int quiet) |
| { |
| const char *special = swapoff_resolve_tag(name, value, mntcache); |
| return special ? do_swapoff(special, quiet, CANONIC) : cannot_find(value); |
| } |
| |
| static void __attribute__((__noreturn__)) usage(void) |
| { |
| FILE *out = stdout; |
| fputs(USAGE_HEADER, out); |
| fprintf(out, _(" %s [options] [<spec>]\n"), program_invocation_short_name); |
| |
| fputs(USAGE_SEPARATOR, out); |
| fputs(_("Disable devices and files for paging and swapping.\n"), out); |
| |
| fputs(USAGE_OPTIONS, out); |
| fputs(_(" -a, --all disable all swaps from /proc/swaps\n" |
| " -v, --verbose verbose mode\n"), out); |
| |
| fputs(USAGE_SEPARATOR, out); |
| printf(USAGE_HELP_OPTIONS(24)); |
| |
| fputs(_("\nThe <spec> parameter:\n" \ |
| " -L <label> LABEL of device to be used\n" \ |
| " -U <uuid> UUID of device to be used\n" \ |
| " LABEL=<label> LABEL of device to be used\n" \ |
| " UUID=<uuid> UUID of device to be used\n" \ |
| " <device> name of device to be used\n" \ |
| " <file> name of file to be used\n"), out); |
| |
| printf(USAGE_MAN_TAIL("swapoff(8)")); |
| exit(EXIT_SUCCESS); |
| } |
| |
| static int swapoff_all(void) |
| { |
| int status = 0; |
| struct libmnt_table *tb; |
| struct libmnt_fs *fs; |
| struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD); |
| |
| if (!itr) |
| err(EXIT_FAILURE, _("failed to initialize libmount iterator")); |
| |
| /* |
| * In case /proc/swaps exists, unswap stuff listed there. We are quiet |
| * but report errors in status. Errors might mean that /proc/swaps |
| * exists as ordinary file, not in procfs. do_swapoff() exits |
| * immediately on EPERM. |
| */ |
| tb = get_swaps(); |
| |
| while (tb && mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) |
| status |= do_swapoff(mnt_fs_get_source(fs), QUIET, CANONIC); |
| |
| /* |
| * Unswap stuff mentioned in /etc/fstab. Probably it was unmounted |
| * already, so errors are not bad. Doing swapoff -a twice should not |
| * give error messages. |
| */ |
| tb = get_fstab(); |
| mnt_reset_iter(itr, MNT_ITER_FORWARD); |
| |
| while (tb && mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) { |
| if (!is_active_swap(mnt_fs_get_source(fs))) |
| do_swapoff(mnt_fs_get_source(fs), QUIET, !CANONIC); |
| } |
| |
| mnt_free_iter(itr); |
| return status; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| int status = 0, c; |
| size_t i; |
| |
| static const struct option long_opts[] = { |
| { "all", no_argument, NULL, 'a' }, |
| { "help", no_argument, NULL, 'h' }, |
| { "verbose", no_argument, NULL, 'v' }, |
| { "version", no_argument, NULL, 'V' }, |
| { NULL, 0, NULL, 0 } |
| }; |
| |
| setlocale(LC_ALL, ""); |
| bindtextdomain(PACKAGE, LOCALEDIR); |
| textdomain(PACKAGE); |
| atexit(close_stdout); |
| |
| while ((c = getopt_long(argc, argv, "ahvVL:U:", |
| long_opts, NULL)) != -1) { |
| switch (c) { |
| case 'a': /* all */ |
| ++all; |
| break; |
| case 'h': /* help */ |
| usage(); |
| break; |
| case 'v': /* be chatty */ |
| ++verbose; |
| break; |
| case 'V': /* version */ |
| printf(UTIL_LINUX_VERSION); |
| return EXIT_SUCCESS; |
| case 'L': |
| add_label(optarg); |
| break; |
| case 'U': |
| add_uuid(optarg); |
| break; |
| default: |
| errtryhelp(EXIT_FAILURE); |
| } |
| } |
| argv += optind; |
| |
| if (!all && !numof_labels() && !numof_uuids() && *argv == NULL) { |
| warnx(_("bad usage")); |
| errtryhelp(EXIT_FAILURE); |
| } |
| |
| mnt_init_debug(0); |
| mntcache = mnt_new_cache(); |
| |
| for (i = 0; i < numof_labels(); i++) |
| status |= swapoff_by("LABEL", get_label(i), !QUIET); |
| |
| for (i = 0; i < numof_uuids(); i++) |
| status |= swapoff_by("UUID", get_uuid(i), !QUIET); |
| |
| while (*argv != NULL) |
| status |= do_swapoff(*argv++, !QUIET, !CANONIC); |
| |
| if (all) |
| status |= swapoff_all(); |
| |
| free_tables(); |
| mnt_unref_cache(mntcache); |
| |
| return status; |
| } |