busybox/libbb/executable.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Utility routines.
   4 *
   5 * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu>
   6 *
   7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   8 */
   9#include "libbb.h"
  10
  11/* check if path points to an executable file;
  12 * return 1 if found;
  13 * return 0 otherwise;
  14 */
  15int FAST_FUNC file_is_executable(const char *name)
  16{
  17        struct stat s;
  18        return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
  19}
  20
  21/* search (*PATHp) for an executable file;
  22 * return allocated string containing full path if found;
  23 *  PATHp points to the component after the one where it was found
  24 *  (or NULL),
  25 *  you may call find_executable again with this PATHp to continue
  26 *  (if it's not NULL).
  27 * return NULL otherwise; (PATHp is undefined)
  28 * in all cases (*PATHp) contents are temporarily modified
  29 * but are restored on return (s/:/NUL/ and back).
  30 */
  31char* FAST_FUNC find_executable(const char *filename, char **PATHp)
  32{
  33        /* About empty components in $PATH:
  34         * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
  35         * 8.3 Other Environment Variables - PATH
  36         * A zero-length prefix is a legacy feature that indicates the current
  37         * working directory. It appears as two adjacent colons ( "::" ), as an
  38         * initial colon preceding the rest of the list, or as a trailing colon
  39         * following the rest of the list.
  40         */
  41        char *p, *n;
  42
  43        p = *PATHp;
  44        while (p) {
  45                int ex;
  46
  47                n = strchr(p, ':');
  48                if (n) *n = '\0';
  49                p = concat_path_file(
  50                        p[0] ? p : ".", /* handle "::" case */
  51                        filename
  52                );
  53                ex = file_is_executable(p);
  54                if (n) *n++ = ':';
  55                if (ex) {
  56                        *PATHp = n;
  57                        return p;
  58                }
  59                free(p);
  60                p = n;
  61        } /* on loop exit p == NULL */
  62        return p;
  63}
  64
  65/* search $PATH for an executable file;
  66 * return 1 if found;
  67 * return 0 otherwise;
  68 */
  69int FAST_FUNC executable_exists(const char *filename)
  70{
  71        char *path = getenv("PATH");
  72        char *ret = find_executable(filename, &path);
  73        free(ret);
  74        return ret != NULL;
  75}
  76
  77#if ENABLE_FEATURE_PREFER_APPLETS
  78/* just like the real execvp, but try to launch an applet named 'file' first */
  79int FAST_FUNC BB_EXECVP(const char *file, char *const argv[])
  80{
  81        if (find_applet_by_name(file) >= 0)
  82                execvp(bb_busybox_exec_path, argv);
  83        return execvp(file, argv);
  84}
  85#endif
  86
  87void FAST_FUNC BB_EXECVP_or_die(char **argv)
  88{
  89        BB_EXECVP(argv[0], argv);
  90        /* SUSv3-mandated exit codes */
  91        xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
  92        bb_perror_msg_and_die("can't execute '%s'", argv[0]);
  93}
  94
  95/* Typical idiom for applets which exec *optional* PROG [ARGS] */
  96void FAST_FUNC exec_prog_or_SHELL(char **argv)
  97{
  98        if (argv[0]) {
  99                BB_EXECVP_or_die(argv);
 100        }
 101        run_shell(getenv("SHELL"), /*login:*/ 1, NULL);
 102}
 103