[git commit] swapon/swapoff: size reduction, cleanup, fixes, improvements

Denys Vlasenko vda.linux at googlemail.com
Mon Mar 31 14:39:26 UTC 2014


commit: http://git.busybox.net/busybox/commit/?id=a3f326cd6619cadb44cb4bb051b1d4e54bcd3477
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

1) real swapon/swapoff handles also devices on the commandline with -a;
2) xstat(device)  in  swap_enable_disable aborts on error when cycling through
   fstab so some devices  are not handled;
3) duplicated code for ENABLE_FEATURE_SWAPON_DISCARD and
   ENABLE_FEATURE_SWAPON_PRI was moved to functions.
4) silence some error messages with -a;
5) minor cleanups and code refactoring reduced the size as per bloat-check:
6) I also added support for /proc/swaps handling to swapoff:
"When the -a flag is given, swapping is disabled on all known  swap  devices
 and  files  (as  found  in  /proc/swaps  or /etc/fstab)."
So now swapoff first cycles through  /proc/swaps and then through fstab
to swapoff all devices.

function                                             old     new   delta
set_discard_flag                                       -     106    +106
swap_enable_disable                                  147     238     +91
set_priority_flag                                      -      79     +79
retrieve_file_data                                   470     467      -3
swap_on_off_main                                     638     418    -220
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/2 up/down: 276/-223)           Total: 53 bytes

Signed-off-by: Tito Ragusa <farmatito at tiscali.it>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 util-linux/swaponoff.c |  276 ++++++++++++++++++++++++++++--------------------
 1 files changed, 161 insertions(+), 115 deletions(-)

diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index a7ad6db..acdb677 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -63,90 +63,142 @@ struct globals {
 } FIX_ALIASING;
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define g_flags (G.flags)
+#define save_g_flags()    int save_g_flags = g_flags
+#define restore_g_flags() g_flags = save_g_flags
 #else
 #define g_flags 0
+#define save_g_flags()    ((void)0)
+#define restore_g_flags() ((void)0)
 #endif
 #define INIT_G() do { } while (0)
 
+#define do_swapoff   (applet_name[5] == 'f')
+
+/* Command line options */
+enum {
+	OPTBIT_a,                              /* -a all      */
+	IF_FEATURE_SWAPON_DISCARD( OPTBIT_d ,) /* -d discard  */
+	IF_FEATURE_SWAPON_PRI    ( OPTBIT_p ,) /* -p priority */
+	OPT_a = 1 << OPTBIT_a,
+	OPT_d = IF_FEATURE_SWAPON_DISCARD((1 << OPTBIT_d)) + 0,
+	OPT_p = IF_FEATURE_SWAPON_PRI    ((1 << OPTBIT_p)) + 0,
+};
+
+#define OPT_ALL      (option_mask32 & OPT_a)
+#define OPT_DISCARD  (option_mask32 & OPT_d)
+#define OPT_PRIO     (option_mask32 & OPT_p)
+
 static int swap_enable_disable(char *device)
 {
-	int status;
+	int err = 0;
+	int quiet = 0;
 	struct stat st;
 
 	resolve_mount_spec(&device);
-	xstat(device, &st);
-
-#if ENABLE_DESKTOP
-	/* test for holes */
-	if (S_ISREG(st.st_mode))
-		if (st.st_blocks * (off_t)512 < st.st_size)
-			bb_error_msg("warning: swap file has holes");
-#endif
 
-	if (applet_name[5] == 'n')
-		status = swapon(device, g_flags);
-	else
-		status = swapoff(device);
+	if (do_swapoff) {
+		err = swapoff(device);
+		/* Don't complain on OPT_ALL if not a swap device or if it doesn't exist */
+		quiet = (OPT_ALL && (errno == EINVAL || errno == ENOENT));
+	} else {
+		/* swapon */
+		err = stat(device, &st);
+		if (!err) {
+			if (ENABLE_DESKTOP && S_ISREG(st.st_mode)) {
+				if (st.st_blocks * (off_t)512 < st.st_size) {
+					bb_error_msg("%s: file has holes", device);
+					return 1;
+				}
+			}
+			err = swapon(device, g_flags);
+			/* Don't complain on swapon -a if device is already in use */
+			quiet = (OPT_ALL && errno == EBUSY);
+		}
+	}
 
-	if (status != 0) {
-		bb_simple_perror_msg(device);
+	if (err) {
+		if (!quiet)
+			bb_simple_perror_msg(device);
 		return 1;
 	}
-
 	return 0;
 }
 
-static int do_em_all(void)
+#if ENABLE_FEATURE_SWAPON_DISCARD
+static void set_discard_flag(char *s)
 {
-	struct mntent *m;
-	FILE *f;
-	int err;
-#ifdef G
-	int cl_flags = g_flags;
+	/* Unset the flag first to allow fstab options to override */
+	/* options set on the command line */
+	g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD;
+
+	if (!s) /* No optional policy value on the commandline */
+		return;
+	/* Skip prepended '=' */
+	if (*s == '=')
+		s++;
+	/* For fstab parsing: remove other appended options */
+	*strchrnul(s, ',') = '\0';
+
+	if (strcmp(s, "once") == 0)
+		g_flags |= SWAP_FLAG_DISCARD_ONCE;
+	if  (strcmp(s, "pages") == 0)
+		g_flags |= SWAP_FLAG_DISCARD_PAGES;
+}
+#else
+#define set_discard_flag(s) ((void)0)
+#endif
+
+#if ENABLE_FEATURE_SWAPON_PRI
+static void set_priority_flag(char *s)
+{
+	unsigned prio;
+
+	/* For fstab parsing: remove other appended options */
+	*strchrnul(s, ',') = '\0';
+	/* Max allowed 32767 (== SWAP_FLAG_PRIO_MASK) */
+	prio = bb_strtou(s, NULL, 10);
+	if (!errno) {
+		/* Unset the flag first to allow fstab options to override */
+		/* options set on the command line */
+		g_flags = (g_flags & ~SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER |
+					MIN(prio, SWAP_FLAG_PRIO_MASK);
+	}
+}
+#else
+#define set_priority_flag(s) ((void)0)
 #endif
 
-	f = setmntent("/etc/fstab", "r");
-	if (f == NULL)
-		bb_perror_msg_and_die("/etc/fstab");
+static int do_em_all_in_fstab(void)
+{
+	struct mntent *m;
+	int err = 0;
+	FILE *f = xfopen_for_read("/etc/fstab");
 
-	err = 0;
 	while ((m = getmntent(f)) != NULL) {
 		if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) {
 			/* swapon -a should ignore entries with noauto,
-			 * but swapoff -a should process them */
-			if (applet_name[5] != 'n'
-			 || hasmntopt(m, MNTOPT_NOAUTO) == NULL
-			) {
-#if ENABLE_FEATURE_SWAPON_DISCARD || ENABLE_FEATURE_SWAPON_PRI
-				char *p;
-				g_flags = cl_flags; /* each swap space might have different flags */
-#if ENABLE_FEATURE_SWAPON_DISCARD
-				p = hasmntopt(m, "discard");
-				if (p) {
-					if (p[7] == '=') {
-						if (strncmp(p + 8, "once", 4) == 0 && (p[12] == ',' || p[12] == '\0'))
-							g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE;
-						else if (strncmp(p + 8, "pages", 5) == 0 && (p[13] == ',' || p[13] == '\0'))
-							g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_PAGES;
+			 * but swapoff -a should process them
+			 */
+			if (do_swapoff || hasmntopt(m, MNTOPT_NOAUTO) == NULL) {
+				/* each swap space might have different flags */
+				/* save global flags for the next round */
+				save_g_flags();
+				if (ENABLE_FEATURE_SWAPON_DISCARD) {
+					char *p = hasmntopt(m, "discard");
+					if (p) {
+						/* move to '=' or to end of string */
+						p += 7;
+						set_discard_flag(p);
 					}
-					else if (p[7] == ',' || p[7] == '\0')
-						g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD;
 				}
-#endif
-#if ENABLE_FEATURE_SWAPON_PRI
-				p = hasmntopt(m, "pri");
-				if (p) {
-					/* Max allowed 32767 (== SWAP_FLAG_PRIO_MASK) */
-					unsigned prio = bb_strtou(p + 4, NULL, 10);
-					/* We want to allow "NNNN,foo", thus errno == EINVAL is allowed too */
-					if (errno != ERANGE) {
-						g_flags = (g_flags & ~SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER |
-							MIN(prio, SWAP_FLAG_PRIO_MASK);
+				if (ENABLE_FEATURE_SWAPON_PRI) {
+					char *p = hasmntopt(m, "pri");
+					if (p) {
+						set_priority_flag(p + 4);
 					}
 				}
-#endif
-#endif
-				err += swap_enable_disable(m->mnt_fsname);
+				err |= swap_enable_disable(m->mnt_fsname);
+				restore_g_flags();
 			}
 		}
 	}
@@ -157,74 +209,68 @@ static int do_em_all(void)
 	return err;
 }
 
+static int do_all_in_proc_swaps(void)
+{
+	char *line;
+	int err = 0;
+	FILE *f = fopen_for_read("/proc/swaps");
+	/* Don't complain if missing */
+	if (f) {
+		while ((line = xmalloc_fgetline(f)) != NULL) {
+			if (line[0] == '/') {
+				*strchrnul(line, ' ') = '\0';
+				err |= swap_enable_disable(line);
+			}
+			free(line);
+		}
+		if (ENABLE_FEATURE_CLEAN_UP)
+			fclose(f);
+	}
+
+	return err;
+}
+
+#define OPTSTR_SWAPON "a" \
+	IF_FEATURE_SWAPON_DISCARD("d::") \
+	IF_FEATURE_SWAPON_PRI("p:")
+
 int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int swap_on_off_main(int argc UNUSED_PARAM, char **argv)
 {
-	int ret;
-#if ENABLE_FEATURE_SWAPON_DISCARD
-	char *discard = NULL;
-#endif
-#if ENABLE_FEATURE_SWAPON_PRI
-	unsigned prio;
-#endif
+	IF_FEATURE_SWAPON_PRI(char *prio;)
+	IF_FEATURE_SWAPON_DISCARD(char *discard = NULL;)
+	int ret = 0;
 
 	INIT_G();
 
-#if !ENABLE_FEATURE_SWAPON_DISCARD && !ENABLE_FEATURE_SWAPON_PRI
-	ret = getopt32(argv, "a");
-#else
-#if ENABLE_FEATURE_SWAPON_PRI
-	if (applet_name[5] == 'n')
-		opt_complementary = "p+";
-#endif
-	ret = getopt32(argv, (applet_name[5] == 'n') ?
-#if ENABLE_FEATURE_SWAPON_DISCARD
-		"d::"
-#endif
-#if ENABLE_FEATURE_SWAPON_PRI
-		"p:"
-#endif
-		"a" : "a"
-#if ENABLE_FEATURE_SWAPON_DISCARD
-		, &discard
-#endif
-#if ENABLE_FEATURE_SWAPON_PRI
-		, &prio
-#endif
-		);
-#endif
-
-#if ENABLE_FEATURE_SWAPON_DISCARD
-	if (ret & 1) { // -d
-		if (!discard)
-			g_flags |= SWAP_FLAG_DISCARD;
-		else if (strcmp(discard, "once") == 0)
-			g_flags |= SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE;
-		else if (strcmp(discard, "pages") == 0)
-			g_flags |= SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_PAGES;
-		else
-			bb_show_usage();
-	}
-	ret >>= 1;
-#endif
-#if ENABLE_FEATURE_SWAPON_PRI
-	if (ret & 1) // -p
-		g_flags |= SWAP_FLAG_PREFER |
-			MIN(prio, SWAP_FLAG_PRIO_MASK);
-	ret >>= 1;
-#endif
-
-	if (ret /* & 1: not needed */) // -a
-		return do_em_all();
+	getopt32(argv, do_swapoff ? "a" : OPTSTR_SWAPON
+			IF_FEATURE_SWAPON_DISCARD(, &discard)
+			IF_FEATURE_SWAPON_PRI(, &prio)
+	);
 
 	argv += optind;
-	if (!*argv)
-		bb_show_usage();
 
-	/* ret = 0; redundant */
-	do {
-		ret += swap_enable_disable(*argv);
-	} while (*++argv);
+	if (OPT_DISCARD) {
+		set_discard_flag(discard);
+	}
+	if (OPT_PRIO) {
+		set_priority_flag(prio);
+	}
 
+	if (OPT_ALL) {
+		/* swapoff -a does also /proc/swaps */
+		if (do_swapoff)
+			ret = do_all_in_proc_swaps();
+		ret |= do_em_all_in_fstab();
+	} else if (!*argv) {
+		/* if not -a we need at least one arg */
+		bb_show_usage();
+	}
+	/* Unset -a now to allow for more messages in swap_enable_disable */
+	option_mask32 = option_mask32 & ~OPT_a;
+	/* Now process devices on the commandline if any */
+	while (*argv) {
+		ret |= swap_enable_disable(*argv++);
+	}
 	return ret;
 }


More information about the busybox-cvs mailing list