]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
swapoff: cleanup EXIT STATUS
authorKarel Zak <kzak@redhat.com>
Wed, 27 May 2020 16:58:30 +0000 (18:58 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 27 May 2020 16:58:30 +0000 (18:58 +0200)
The current code hides details about reason why swapoff(8) and swapoff(2) failed. For example
ENOMEM from swapoff(2) is important as it indicates OOM.

The patch also clean ups --all return codes to be more compatible for
example with [u]mount --all, etc.

Addresses: https://github.com/karelzak/util-linux/issues/1050
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/swapoff.c
sys-utils/swapon.8

index a13d4f1e582385af7f2bd44e9fadd3e914720d9f..dade6fd5e9620e20c5f907ee183e167709ed0c90 100644 (file)
@@ -25,6 +25,14 @@ static int all;
 #define QUIET  1
 #define CANONIC        1
 
+#define SWAPOFF_EX_OK          0       /* no errors */
+#define SWAPOFF_EX_ENOMEM      1       /* swapoff(2) failed due to OOM */
+#define SWAPOFF_EX_FAILURE     2       /* swapoff(2) failed due to another reason */
+#define SWAPOFF_EX_SYSERR      4       /* non-swaoff() errors */
+#define SWAPOFF_EX_USAGE       16      /* usage, permissions or syntax error */
+#define SWAPOFF_EX_ALLERR      32      /* --all all failed */
+#define SWAPOFF_EX_SOMEOK      64      /* --all some failed some OK */
+
 /*
  * 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
@@ -52,7 +60,7 @@ static char *swapoff_resolve_tag(const char *name, const char *value,
 
        itr = mnt_new_iter(MNT_ITER_BACKWARD);
        if (!itr)
-               err(EXIT_FAILURE, _("failed to initialize libmount iterator"));
+               err(SWAPOFF_EX_SYSERR, _("failed to initialize libmount iterator"));
 
        while (tb && mnt_table_next_fs(tb, itr, &fs) == 0) {
                blkid_probe pr = NULL;
@@ -80,6 +88,7 @@ static char *swapoff_resolve_tag(const char *name, const char *value,
 static int do_swapoff(const char *orig_special, int quiet, int canonic)
 {
         const char *special = orig_special;
+       int rc = SWAPOFF_EX_OK;
 
        if (verbose)
                printf(_("swapoff %s\n"), orig_special);
@@ -98,15 +107,25 @@ static int do_swapoff(const char *orig_special, int quiet, int canonic)
        }
 
        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);
+               rc = SWAPOFF_EX_OK;     /* success */
+       else {
+               switch (errno) {
+               case EPERM:
+                       errx(SWAPOFF_EX_USAGE, _("Not superuser."));
+                       break;
+               case ENOMEM:
+                       warn(_("%s: swapoff failed"), orig_special);
+                       rc = SWAPOFF_EX_ENOMEM;
+                       break;
+               default:
+                       if (!quiet)
+                               warn(_("%s: swapoff failed"), orig_special);
+                       rc = SWAPOFF_EX_FAILURE;
+                       break;
+               }
+       }
 
-       return -1;
+       return rc;
 }
 
 static int swapoff_by(const char *name, const char *value, int quiet)
@@ -140,18 +159,18 @@ static void __attribute__((__noreturn__)) usage(void)
                " <file>                 name of file to be used\n"), out);
 
        printf(USAGE_MAN_TAIL("swapoff(8)"));
-       exit(EXIT_SUCCESS);
+       exit(SWAPOFF_EX_OK);
 }
 
 static int swapoff_all(void)
 {
-       int status = 0;
+       int nerrs = 0, nsucc = 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"));
+               err(SWAPOFF_EX_SYSERR, _("failed to initialize libmount iterator"));
 
        /*
         * In case /proc/swaps exists, unswap stuff listed there.  We are quiet
@@ -161,8 +180,12 @@ static int swapoff_all(void)
         */
        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);
+       while (tb && mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) {
+               if (do_swapoff(mnt_fs_get_source(fs), QUIET, CANONIC) == SWAPOFF_EX_OK)
+                       nsucc++;
+               else
+                       nerrs++;
+       }
 
        /*
         * Unswap stuff mentioned in /etc/fstab.  Probably it was unmounted
@@ -178,7 +201,13 @@ static int swapoff_all(void)
        }
 
        mnt_free_iter(itr);
-       return status;
+
+       if (nerrs == 0)
+               return SWAPOFF_EX_OK;           /* all success */
+       else if (nsucc == 0)
+               return SWAPOFF_EX_ALLERR;       /* all failed */
+
+       return SWAPOFF_EX_SOMEOK;               /* some success, some failed */
 }
 
 int main(int argc, char *argv[])
@@ -218,16 +247,16 @@ int main(int argc, char *argv[])
                case 'h':               /* help */
                        usage();
                case 'V':               /* version */
-                       print_version(EXIT_SUCCESS);
+                       print_version(SWAPOFF_EX_OK);
                default:
-                       errtryhelp(EXIT_FAILURE);
+                       errtryhelp(SWAPOFF_EX_USAGE);
                }
        }
        argv += optind;
 
        if (!all && !numof_labels() && !numof_uuids() && *argv == NULL) {
                warnx(_("bad usage"));
-               errtryhelp(EXIT_FAILURE);
+               errtryhelp(SWAPOFF_EX_USAGE);
        }
 
        mnt_init_debug(0);
index 276e36e007bdeaafa8fa3991d53c06b72682bfb9..e43ceb54f273ec53d1cb3db4591489feb08b4ed9 100644 (file)
@@ -187,6 +187,34 @@ Be verbose.
 .TP
 .BR \-V , " \-\-version"
 Display version information and exit.
+.SH EXIT STATUS
+.B swapoff
+has the following exit status values:
+.TP
+.B 0
+success
+.TP
+.B 1
+system has insufficient memory to stop swapping (OOM)
+.TP
+.B 2
+swapoff syscall failed for another reason
+.TP
+.B 4
+non-swapoff syscall system error (out of memory, ...)
+.TP
+.B 16
+usage or syntax error
+.TP
+.B 32
+all swapoff failed on \fB\-\-all\fR
+.TP
+.B 64
+some swapoff succeeded on \fB\-\-all\fR
+
+The command \fBswapoff \-\-all\fR returns 0 (all succeeded), 32 (all failed), or 64 (some
+failed, some succeeded).
+
 .SH ENVIRONMENT
 .IP LIBMOUNT_DEBUG=all
 enables libmount debug output.