swapoff: cleanup EXIT STATUS

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>
This commit is contained in:
Karel Zak 2020-05-27 18:58:30 +02:00
parent c7fce443b1
commit ecfa4dad6f
2 changed files with 75 additions and 18 deletions

View 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 */
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;
}
}
if (errno == EPERM)
errx(EXIT_FAILURE, _("Not superuser."));
if (!quiet || errno == ENOMEM)
warn(_("%s: swapoff failed"), orig_special);
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);

View 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.