Re: [PATCH] Fail like the shell when execvp fails

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 16 Apr 2016, Nir Soffer wrote:

> Commands executing another command (e.g. taskset) should fail in a
> consistent and detectable way when the other command fail to execute.
> Change most of the commands that used to fail with EXIT_FAILURE to fail
> with the special exit code 127, like the shell.
> 
> For example, running the fuser command via taskset when fuser command is
> not installed is failing now like this:
> 
>     $ taskset -c 1 fuser /path/to/file; echo $?
>     taskset: failed to execute fuser: No such file or directory
>     1
> 
> This failure looks like a real failure of the fuser command:
> 
>     $ taskset -c 1 fuser /path/to/file; echo $?
>     Specified filename /path/to/file does not exist.
>     1
> 
> Based on the exit code, a management program may do the wrong thing,
> leading to catastrophic results. Detecting such failure requires fragile
> parsing of standard error.
> 
> With this patch this failure is easy to detect:
> 
>     $ taskset -c 1 fuser /path/to/file; echo $?
>     taskset: failed to execute fuser: No such file or directory
>     127
> 
> The return code seems to be undocumented for most commands, except the
> su command, promising to exit with exit code 126 if a command cannot be
> executed, and 127 if a command was not found. However, the actual
> command always exit with exit code 1. This patch implement the
> documented behavior.
> 
> Signed-off-by: Nir Soffer <nsoffer@xxxxxxxxxx>
> ---
>  disk-utils/mkfs.c                   | 3 ++-
>  include/exitcodes.h                 | 7 +++++++
>  lib/pager.c                         | 3 ++-
>  login-utils/su-common.c             | 7 ++++++-
>  schedutils/chrt.c                   | 3 ++-
>  schedutils/ionice.c                 | 3 ++-
>  schedutils/taskset.c                | 3 ++-
>  sys-utils/flock.c                   | 4 +++-
>  sys-utils/nsenter.c                 | 3 ++-
>  sys-utils/prlimit.c                 | 3 ++-
>  sys-utils/setarch.c                 | 7 ++++---
>  sys-utils/setpriv.c                 | 3 ++-
>  sys-utils/setsid.c                  | 3 ++-
>  sys-utils/swapon.c                  | 3 ++-
>  sys-utils/unshare.c                 | 3 ++-
>  tests/expected/misc/setarch-options | 2 +-
>  text-utils/more.c                   | 3 ++-
>  17 files changed, 45 insertions(+), 18 deletions(-)

Lots of change in a single patch. Could these change be split to something 
like:

1. include/exitcodes.h
2. lib/pager.c
3. changes to commands
4. updates to tests
5. manual page updates


> diff --git a/disk-utils/mkfs.c b/disk-utils/mkfs.c
> index cf1a312..88f125d 100644
> --- a/disk-utils/mkfs.c
> +++ b/disk-utils/mkfs.c
> @@ -33,6 +33,7 @@
>  #include "closestream.h"
>  #include "nls.h"
>  #include "xalloc.h"
> +#include "exitcodes.h"
>  
>  #ifndef DEFAULT_FSTYPE
>  #define DEFAULT_FSTYPE	"ext2"
> @@ -136,5 +137,5 @@ int main(int argc, char **argv)
>  
>  	/* Execute the program */
>  	execvp(progname, argv + optind);
> -	err(EXIT_FAILURE, _("failed to execute %s"), progname);
> +	err(EX_EXEC, _("failed to execute %s"), progname);
>  }
> diff --git a/include/exitcodes.h b/include/exitcodes.h
> index 24ee123..2063c54 100644
> --- a/include/exitcodes.h
> +++ b/include/exitcodes.h
> @@ -32,4 +32,11 @@
>  #define MOUNT_EX_FAIL		32	/* mount failure */
>  #define MOUNT_EX_SOMEOK		64	/* some mount succeeded */
>  
> +/* Exit codes use by the su program */
> +#define SU_EX_EXEC			126 /* faied to execute a program */
> +#define SU_EX_NOENT			127 /* program was not found */
> +
> +/* General exit codes */
> +#define EX_EXEC				127 /* faied to execute a program */
> +

Looks like typo x2

s/faied/failed/

>  #endif	/* UTIL_LINUX_EXITCODES_H */
> diff --git a/lib/pager.c b/lib/pager.c
> index 330659e..381294a 100644
> --- a/lib/pager.c
> +++ b/lib/pager.c
> @@ -17,6 +17,7 @@
>  #include "c.h"
>  #include "xalloc.h"
>  #include "nls.h"
> +#include "exitcodes.h"
>  
>  #define NULL_DEVICE	"/dev/null"
>  
> @@ -73,7 +74,7 @@ static int start_command(struct child_process *cmd)
>  
>  		cmd->preexec_cb();
>  		execvp(cmd->argv[0], (char *const*) cmd->argv);
> -		exit(127); /* cmd not found */
> +		exit(EX_EXEC); /* cmd not found */
>  	}
>  
>  	if (cmd->pid < 0) {
> diff --git a/login-utils/su-common.c b/login-utils/su-common.c
> index fe6d0c8..b17b133 100644
> --- a/login-utils/su-common.c
> +++ b/login-utils/su-common.c
> @@ -71,6 +71,7 @@ enum
>  #include "closestream.h"
>  #include "strutils.h"
>  #include "ttyutils.h"
> +#include "exitcodes.h"
>  
>  /* name of the pam configuration files. separate configs for su and su -  */
>  #define PAM_SRVNAME_SU "su"
> @@ -983,7 +984,11 @@ su_main (int argc, char **argv, int mode)
>      run_shell (shell, command, argv + optind, max (0, argc - optind));
>    else {
>      execvp(argv[optind], &argv[optind]);
> -    err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
> +    /* su(1) promise to fail with exit code 126 if the command
> +       cannot be executed, and 127 if the command was not
> +       found. */
> +    err(errno == ENOENT ? SU_EX_NOENT : SU_EX_EXEC,
> +        _("failed to execute %s"), argv[optind]);
>    }
>  }
>  
> diff --git a/schedutils/chrt.c b/schedutils/chrt.c
> index 202ce25..40f6cfe 100644
> --- a/schedutils/chrt.c
> +++ b/schedutils/chrt.c
> @@ -32,6 +32,7 @@
>  #include "closestream.h"
>  #include "strutils.h"
>  #include "procutils.h"
> +#include "exitcodes.h"
>  
>  /* the SCHED_BATCH is supported since Linux 2.6.16
>   *  -- temporary workaround for people with old glibc headers
> @@ -517,7 +518,7 @@ int main(int argc, char **argv)
>  	if (!ctl->pid) {
>  		argv += optind + 1;
>  		execvp(argv[0], argv);
> -		err(EXIT_FAILURE, _("failed to execute %s"), argv[0]);
> +		err(EX_EXEC, _("failed to execute %s"), argv[0]);
>  	}
>  
>  	return EXIT_SUCCESS;
> diff --git a/schedutils/ionice.c b/schedutils/ionice.c
> index 5528afe..0d6a2d2 100644
> --- a/schedutils/ionice.c
> +++ b/schedutils/ionice.c
> @@ -18,6 +18,7 @@
>  #include "strutils.h"
>  #include "c.h"
>  #include "closestream.h"
> +#include "exitcodes.h"
>  
>  static int tolerant;
>  
> @@ -257,7 +258,7 @@ int main(int argc, char **argv)
>  		 */
>  		ioprio_setid(0, ioclass, data, IOPRIO_WHO_PROCESS);
>  		execvp(argv[optind], &argv[optind]);
> -		err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
> +		err(EX_EXEC, _("failed to execute %s"), argv[optind]);
>  	} else
>  		usage(stderr);
>  
> diff --git a/schedutils/taskset.c b/schedutils/taskset.c
> index d6b21e4..e68068d 100644
> --- a/schedutils/taskset.c
> +++ b/schedutils/taskset.c
> @@ -34,6 +34,7 @@
>  #include "procutils.h"
>  #include "c.h"
>  #include "closestream.h"
> +#include "exitcodes.h"
>  
>  struct taskset {
>  	pid_t		pid;		/* task PID */
> @@ -236,7 +237,7 @@ int main(int argc, char **argv)
>  	if (!pid) {
>  		argv += optind + 1;
>  		execvp(argv[0], argv);
> -		err(EXIT_FAILURE, _("failed to execute %s"), argv[0]);
> +		err(EX_EXEC, _("failed to execute %s"), argv[0]);
>  	}
>  
>  	return EXIT_SUCCESS;
> diff --git a/sys-utils/flock.c b/sys-utils/flock.c
> index b5c4d91..d2d994a 100644
> --- a/sys-utils/flock.c
> +++ b/sys-utils/flock.c
> @@ -45,6 +45,7 @@
>  #include "closestream.h"
>  #include "monotonic.h"
>  #include "timer.h"
> +#include "exitcodes.h"
>  
>  static void __attribute__((__noreturn__)) usage(int ex)
>  {
> @@ -330,7 +331,8 @@ int main(int argc, char *argv[])
>  			execvp(cmd_argv[0], cmd_argv);
>  			/* execvp() failed */
>  			warn(_("failed to execute %s"), cmd_argv[0]);
> -			_exit((errno == ENOMEM) ? EX_OSERR : EX_UNAVAILABLE);
> +			/* Behave mostly like the shell */
> +			_exit((errno == ENOMEM) ? EX_OSERR : EX_EXEC);

This conflicts with flock(1) manual page. Either this change should not be 
done, or manual page needs update as well.

>  		} else {
>  			do {
>  				w = waitpid(f, &status, 0);
> diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c
> index d8690db..558b4d0 100644
> --- a/sys-utils/nsenter.c
> +++ b/sys-utils/nsenter.c
> @@ -40,6 +40,7 @@
>  #include "closestream.h"
>  #include "namespace.h"
>  #include "exec_shell.h"
> +#include "exitcodes.h"
>  
>  static struct namespace_file {
>  	int nstype;
> @@ -413,7 +414,7 @@ int main(int argc, char *argv[])
>  
>  	if (optind < argc) {
>  		execvp(argv[optind], argv + optind);
> -		err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
> +		err(EX_EXEC, _("failed to execute %s"), argv[optind]);
>  	}
>  	exec_shell();
>  }
> diff --git a/sys-utils/prlimit.c b/sys-utils/prlimit.c
> index b244ddb..6a3d527 100644
> --- a/sys-utils/prlimit.c
> +++ b/sys-utils/prlimit.c
> @@ -35,6 +35,7 @@
>  #include "strutils.h"
>  #include "list.h"
>  #include "closestream.h"
> +#include "exitcodes.h"
>  
>  #ifndef RLIMIT_RTTIME
>  # define RLIMIT_RTTIME 15
> @@ -641,7 +642,7 @@ int main(int argc, char **argv)
>  	if (argc > optind) {
>  		/* prlimit [options] COMMAND */
>  		execvp(argv[optind], &argv[optind]);
> -		err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
> +		err(EX_EXEC, _("failed to execute %s"), argv[optind]);
>  	}
>  
>  	return EXIT_SUCCESS;
> diff --git a/sys-utils/setarch.c b/sys-utils/setarch.c
> index cf29cf7..bda3e8f 100644
> --- a/sys-utils/setarch.c
> +++ b/sys-utils/setarch.c
> @@ -35,6 +35,7 @@
>  #include "nls.h"
>  #include "c.h"
>  #include "closestream.h"
> +#include "exitcodes.h"
>  
>  #ifndef HAVE_PERSONALITY
>  # include <syscall.h>
> @@ -399,10 +400,10 @@ int main(int argc, char *argv[])
>  
>  	if (!argc) {
>  		execl("/bin/sh", "-sh", NULL);
> -		err(EXIT_FAILURE, _("failed to execute %s"), "/bin/sh");
> +		err(EX_EXEC, _("failed to execute %s"), "/bin/sh");
>  	}
>  
>  	execvp(argv[0], argv);
> -	err(EXIT_FAILURE, "%s", argv[0]);
> -	return EXIT_FAILURE;
> +	err(EX_EXEC, "%s", argv[0]);
> +	return EX_EXEC;
>  }
> diff --git a/sys-utils/setpriv.c b/sys-utils/setpriv.c
> index 1630122..2015f30 100644
> --- a/sys-utils/setpriv.c
> +++ b/sys-utils/setpriv.c
> @@ -38,6 +38,7 @@
>  #include "strutils.h"
>  #include "xalloc.h"
>  #include "pathnames.h"
> +#include "exitcodes.h"
>  
>  #ifndef PR_SET_NO_NEW_PRIVS
>  # define PR_SET_NO_NEW_PRIVS 38
> @@ -839,5 +840,5 @@ int main(int argc, char **argv)
>  
>  	execvp(argv[optind], argv + optind);
>  
> -	err(EXIT_FAILURE, _("cannot execute: %s"), argv[optind]);
> +	err(EX_EXEC, _("cannot execute: %s"), argv[optind]);
>  }
> diff --git a/sys-utils/setsid.c b/sys-utils/setsid.c
> index bb089df..466c5cf 100644
> --- a/sys-utils/setsid.c
> +++ b/sys-utils/setsid.c
> @@ -24,6 +24,7 @@
>  #include "c.h"
>  #include "nls.h"
>  #include "closestream.h"
> +#include "exitcodes.h"
>  
>  static void __attribute__ ((__noreturn__)) usage(FILE * out)
>  {
> @@ -114,5 +115,5 @@ int main(int argc, char **argv)
>  			err(EXIT_FAILURE, _("failed to set the controlling terminal"));
>  	}
>  	execvp(argv[optind], argv + optind);
> -	err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
> +	err(EX_EXEC, _("failed to execute %s"), argv[optind]);
>  }
> diff --git a/sys-utils/swapon.c b/sys-utils/swapon.c
> index 97acf1e..294112b 100644
> --- a/sys-utils/swapon.c
> +++ b/sys-utils/swapon.c
> @@ -23,6 +23,7 @@
>  #include "strutils.h"
>  #include "optutils.h"
>  #include "closestream.h"
> +#include "exitcodes.h"
>  
>  #include "swapheader.h"
>  #include "swapprober.h"
> @@ -337,7 +338,7 @@ static int swap_reinitialize(struct swap_device *dev)
>  		cmd[idx++] = dev->path;
>  		cmd[idx++] = NULL;
>  		execvp(cmd[0], (char * const *) cmd);
> -		err(EXIT_FAILURE, _("failed to execute %s"), cmd[0]);
> +		err(EX_EXEC, _("failed to execute %s"), cmd[0]);
>  
>  	default: /* parent */
>  		do {
> diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
> index 234c750..9e6b4bb 100644
> --- a/sys-utils/unshare.c
> +++ b/sys-utils/unshare.c
> @@ -40,6 +40,7 @@
>  #include "xalloc.h"
>  #include "pathnames.h"
>  #include "all-io.h"
> +#include "exitcodes.h"
>  
>  /* synchronize parent and child by pipe */
>  #define PIPE_SYNC_BYTE	0x06
> @@ -458,7 +459,7 @@ int main(int argc, char *argv[])
>  
>  	if (optind < argc) {
>  		execvp(argv[optind], argv + optind);
> -		err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
> +		err(EX_EXEC, _("failed to execute %s"), argv[optind]);
>  	}
>  	exec_shell();
>  }
> diff --git a/tests/expected/misc/setarch-options b/tests/expected/misc/setarch-options
> index 698db52..ebe52f0 100644
> --- a/tests/expected/misc/setarch-options
> +++ b/tests/expected/misc/setarch-options
> @@ -4,7 +4,7 @@ exit: 1
>  ###### unknown command
>  Execute command `/das/gibs/nicht'.
>  setarch: /das/gibs/nicht: No such file or directory
> -exit: 1
> +exit: 127
>  ###### noop uname -a
>  Execute command `uname'.
>  uname -a unchanged
> diff --git a/text-utils/more.c b/text-utils/more.c
> index 0a5f494..42f49ba 100644
> --- a/text-utils/more.c
> +++ b/text-utils/more.c
> @@ -65,6 +65,7 @@
>  #include "xalloc.h"
>  #include "widechar.h"
>  #include "closestream.h"
> +#include "exitcodes.h"
>  
>  #include <regex.h>
>  
> @@ -1622,7 +1623,7 @@ void execute(char *filename, char *cmd, ...)
>  
>  		execvp(cmd, args);
>  		putserr(_("exec failed\n"));
> -		exit(EXIT_FAILURE);
> +		exit(EX_EXEC);
>  	}
>  	if (id > 0) {
>  		signal(SIGINT, SIG_IGN);
> 

-- 
Sami Kerola
http://www.iki.fi/kerolasa/
--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux