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