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
  10#include "libbb.h"
  11
  12/* check if path points to an executable file;
  13 * return 1 if found;
  14 * return 0 otherwise;
  15 */
  16int FAST_FUNC file_is_executable(const char *name)
  17{
  18        struct stat s;
  19        return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
  20}
  21
  22/* search (*PATHp) for an executable file;
  23 * return allocated string containing full path if found;
  24 *  PATHp points to the component after the one where it was found
  25 *  (or NULL),
  26 *  you may call find_executable again with this PATHp to continue
  27 *  (if it's not NULL).
  28 * return NULL otherwise; (PATHp is undefined)
  29 * in all cases (*PATHp) contents will be trashed (s/:/NUL/).
  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                n = strchr(p, ':');
  46                if (n)
  47                        *n++ = '\0';
  48                p = concat_path_file(
  49                        p[0] ? p : ".", /* handle "::" case */
  50                        filename
  51                );
  52                if (file_is_executable(p)) {
  53                        *PATHp = n;
  54                        return p;
  55                }
  56                free(p);
  57                p = n;
  58        } /* on loop exit p == NULL */
  59        return p;
  60}
  61
  62/* search $PATH for an executable file;
  63 * return 1 if found;
  64 * return 0 otherwise;
  65 */
  66int FAST_FUNC executable_exists(const char *filename)
  67{
  68        char *path = xstrdup(getenv("PATH"));
  69        char *tmp = path;
  70        char *ret = find_executable(filename, &tmp);
  71        free(path);
  72        free(ret);
  73        return ret != NULL;
  74}
  75
  76#if ENABLE_FEATURE_PREFER_APPLETS
  77/* just like the real execvp, but try to launch an applet named 'file' first */
  78int FAST_FUNC BB_EXECVP(const char *file, char *const argv[])
  79{
  80        if (find_applet_by_name(file) >= 0)
  81                execvp(bb_busybox_exec_path, argv);
  82        return execvp(file, argv);
  83}
  84#endif
  85
  86void FAST_FUNC BB_EXECVP_or_die(char **argv)
  87{
  88        BB_EXECVP(argv[0], argv);
  89        /* SUSv3-mandated exit codes */
  90        xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
  91        bb_perror_msg_and_die("can't execute '%s'", argv[0]);
  92}
  93
  94/* Typical idiom for applets which exec *optional* PROG [ARGS] */
  95void FAST_FUNC exec_prog_or_SHELL(char **argv)
  96{
  97        if (argv[0]) {
  98                BB_EXECVP_or_die(argv);
  99        }
 100        run_shell(getenv("SHELL"), /*login:*/ 1, NULL, NULL);
 101}
 102