(root)/
util-linux-2.39/
sys-utils/
swapoff.c
       1  #include <stdio.h>
       2  #include <errno.h>
       3  #include <getopt.h>
       4  
       5  #ifdef HAVE_SYS_SWAP_H
       6  # include <sys/swap.h>
       7  #endif
       8  
       9  #include "nls.h"
      10  #include "c.h"
      11  #include "xalloc.h"
      12  #include "closestream.h"
      13  
      14  #include "swapprober.h"
      15  #include "swapon-common.h"
      16  
      17  #if !defined(HAVE_SWAPOFF) && defined(SYS_swapoff)
      18  # include <sys/syscall.h>
      19  # define swapoff(path) syscall(SYS_swapoff, path)
      20  #endif
      21  
      22  static int verbose;
      23  static int all;
      24  
      25  #define QUIET	1
      26  #define CANONIC	1
      27  
      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 */
      35  
      36  /*
      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
      40   * devices only.
      41   */
      42  static char *swapoff_resolve_tag(const char *name, const char *value,
      43  				 struct libmnt_cache *cache)
      44  {
      45  	char *path;
      46  	struct libmnt_table *tb;
      47  	struct libmnt_iter *itr;
      48  	struct libmnt_fs *fs;
      49  
      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);
      53  	if (path)
      54  		return path;
      55  
      56  	/* try regular files from /proc/swaps */
      57  	tb = get_swaps();
      58  	if (!tb)
      59  		return NULL;
      60  
      61  	itr = mnt_new_iter(MNT_ITER_BACKWARD);
      62  	if (!itr)
      63  		err(SWAPOFF_EX_SYSERR, _("failed to initialize libmount iterator"));
      64  
      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;
      70  
      71  		if (!src || !type || strcmp(type, "file") != 0)
      72  			continue;
      73  		pr = get_swap_prober(src);
      74  		if (!pr)
      75  			continue;
      76  		blkid_probe_lookup_value(pr, name, &data, NULL);
      77  		if (data && strcmp(data, value) == 0)
      78  			path = xstrdup(src);
      79  		blkid_free_probe(pr);
      80  		if (path)
      81  			break;
      82  	}
      83  
      84  	mnt_free_iter(itr);
      85  	return path;
      86  }
      87  
      88  static int do_swapoff(const char *orig_special, int quiet, int canonic)
      89  {
      90          const char *special = orig_special;
      91  	int rc = SWAPOFF_EX_OK;
      92  
      93  	if (verbose)
      94  		printf(_("swapoff %s\n"), orig_special);
      95  
      96  	if (!canonic) {
      97  		char *n, *v;
      98  
      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);
     102  			free(n);
     103  			free(v);
     104  		}
     105  		if (!special)
     106  			return cannot_find(orig_special);
     107  	}
     108  
     109  	if (swapoff(special) == 0)
     110  		rc = SWAPOFF_EX_OK;	/* success */
     111  	else {
     112  		switch (errno) {
     113  		case EPERM:
     114  			errx(SWAPOFF_EX_USAGE, _("Not superuser."));
     115  			break;
     116  		case ENOMEM:
     117  			warn(_("%s: swapoff failed"), orig_special);
     118  			rc = SWAPOFF_EX_ENOMEM;
     119  			break;
     120  		default:
     121  			if (!quiet)
     122  				warn(_("%s: swapoff failed"), orig_special);
     123  			rc = SWAPOFF_EX_FAILURE;
     124  			break;
     125  		}
     126  	}
     127  
     128  	return rc;
     129  }
     130  
     131  static int swapoff_by(const char *name, const char *value, int quiet)
     132  {
     133  	const char *special = swapoff_resolve_tag(name, value, mntcache);
     134  	return special ? do_swapoff(special, quiet, CANONIC) : cannot_find(value);
     135  }
     136  
     137  static void __attribute__((__noreturn__)) usage(void)
     138  {
     139  	FILE *out = stdout;
     140  	fputs(USAGE_HEADER, out);
     141  	fprintf(out, _(" %s [options] [<spec>]\n"), program_invocation_short_name);
     142  
     143  	fputs(USAGE_SEPARATOR, out);
     144  	fputs(_("Disable devices and files for paging and swapping.\n"), out);
     145  
     146  	fputs(USAGE_OPTIONS, out);
     147  	fputs(_(" -a, --all              disable all swaps from /proc/swaps\n"
     148  		" -v, --verbose          verbose mode\n"), out);
     149  
     150  	fputs(USAGE_SEPARATOR, out);
     151  	printf(USAGE_HELP_OPTIONS(24));
     152  
     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);
     160  
     161  	printf(USAGE_MAN_TAIL("swapoff(8)"));
     162  	exit(SWAPOFF_EX_OK);
     163  }
     164  
     165  static int swapoff_all(void)
     166  {
     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);
     171  
     172  	if (!itr)
     173  		err(SWAPOFF_EX_SYSERR, _("failed to initialize libmount iterator"));
     174  
     175  	/*
     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.
     180  	 */
     181  	tb = get_swaps();
     182  
     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)
     185  			nsucc++;
     186  		else
     187  			nerrs++;
     188  	}
     189  
     190  	/*
     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.
     194  	 */
     195  	tb = get_fstab(NULL);
     196  	mnt_reset_iter(itr, MNT_ITER_FORWARD);
     197  
     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);
     201  	}
     202  
     203  	mnt_free_iter(itr);
     204  
     205  	if (nerrs == 0)
     206  		return SWAPOFF_EX_OK;		/* all success */
     207  	else if (nsucc == 0)
     208  		return SWAPOFF_EX_ALLERR;	/* all failed */
     209  
     210  	return SWAPOFF_EX_SOMEOK;		/* some success, some failed */
     211  }
     212  
     213  int main(int argc, char *argv[])
     214  {
     215  	int status = 0, c;
     216  	size_t i;
     217  
     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' },
     223  		{ NULL, 0, NULL, 0 }
     224  	};
     225  
     226  	setlocale(LC_ALL, "");
     227  	bindtextdomain(PACKAGE, LOCALEDIR);
     228  	textdomain(PACKAGE);
     229  	close_stdout_atexit();
     230  
     231  	while ((c = getopt_long(argc, argv, "ahvVL:U:",
     232  				 long_opts, NULL)) != -1) {
     233  		switch (c) {
     234  		case 'a':		/* all */
     235  			++all;
     236  			break;
     237  		case 'v':		/* be chatty */
     238  			++verbose;
     239  			break;
     240  		case 'L':
     241  			add_label(optarg);
     242  			break;
     243  		case 'U':
     244  			add_uuid(optarg);
     245  			break;
     246  
     247  		case 'h':		/* help */
     248  			usage();
     249  		case 'V':		/* version */
     250  			print_version(SWAPOFF_EX_OK);
     251  		default:
     252  			errtryhelp(SWAPOFF_EX_USAGE);
     253  		}
     254  	}
     255  	argv += optind;
     256  
     257  	if (!all && !numof_labels() && !numof_uuids() && *argv == NULL) {
     258  		warnx(_("bad usage"));
     259  		errtryhelp(SWAPOFF_EX_USAGE);
     260  	}
     261  
     262  	mnt_init_debug(0);
     263  	mntcache = mnt_new_cache();
     264  
     265  	for (i = 0; i < numof_labels(); i++)
     266  		status |= swapoff_by("LABEL", get_label(i), !QUIET);
     267  
     268  	for (i = 0; i < numof_uuids(); i++)
     269  		status |= swapoff_by("UUID", get_uuid(i), !QUIET);
     270  
     271  	while (*argv != NULL)
     272  		status |= do_swapoff(*argv++, !QUIET, !CANONIC);
     273  
     274  	if (all)
     275  		status |= swapoff_all();
     276  
     277  	free_tables();
     278  	mnt_unref_cache(mntcache);
     279  
     280  	return status;
     281  }