executable.c 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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. /* check if path points to an executable file;
  11. * return 1 if found;
  12. * return 0 otherwise;
  13. */
  14. int FAST_FUNC file_is_executable(const char *name)
  15. {
  16. struct stat s;
  17. return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
  18. }
  19. /* search (*PATHp) for an executable file;
  20. * return allocated string containing full path if found;
  21. * PATHp points to the component after the one where it was found
  22. * (or NULL if found in last component),
  23. * you may call find_executable again with this PATHp to continue
  24. * return NULL otherwise (PATHp is undefined)
  25. */
  26. char* FAST_FUNC find_executable(const char *name, const char **PATHp)
  27. {
  28. /* About empty components in $PATH:
  29. * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
  30. * 8.3 Other Environment Variables - PATH
  31. * A zero-length prefix is a legacy feature that indicates the current
  32. * working directory. It appears as two adjacent colons ( "::" ), as an
  33. * initial colon preceding the rest of the list, or as a trailing colon
  34. * following the rest of the list.
  35. */
  36. char *p = (char*) *PATHp;
  37. if (!p)
  38. return NULL;
  39. while (1) {
  40. const char *end = strchrnul(p, ':');
  41. int sz = end - p;
  42. if (sz != 0) {
  43. p = xasprintf("%.*s/%s", sz, p, name);
  44. } else {
  45. /* We have xxx::yyy in $PATH,
  46. * it means "use current dir" */
  47. p = xstrdup(name);
  48. // A bit of discrepancy wrt the path used if file is found here.
  49. // bash 5.2.15 "type" returns "./NAME".
  50. // GNU which v2.21 returns "/CUR/DIR/NAME".
  51. // With -a, both skip over all colons: xxx::::yyy is the same as xxx::yyy,
  52. // current dir is not tried the second time.
  53. }
  54. if (file_is_executable(p)) {
  55. *PATHp = (*end ? end+1 : NULL);
  56. return p;
  57. }
  58. free(p);
  59. if (*end == '\0')
  60. return NULL;
  61. p = (char *) end + 1;
  62. }
  63. }
  64. /* search $PATH for an executable file;
  65. * return 1 if found;
  66. * return 0 otherwise;
  67. */
  68. int FAST_FUNC executable_exists(const char *name)
  69. {
  70. const char *path = getenv("PATH");
  71. char *ret = find_executable(name, &path);
  72. free(ret);
  73. return ret != NULL;
  74. }
  75. #if ENABLE_FEATURE_PREFER_APPLETS
  76. /* just like the real execvp, but try to launch an applet named 'file' first */
  77. int FAST_FUNC BB_EXECVP(const char *file, char *const argv[])
  78. {
  79. if (find_applet_by_name(file) >= 0)
  80. execvp(bb_busybox_exec_path, argv);
  81. return execvp(file, argv);
  82. }
  83. #endif
  84. void FAST_FUNC BB_EXECVP_or_die(char **argv)
  85. {
  86. BB_EXECVP(argv[0], argv);
  87. /* SUSv3-mandated exit codes */
  88. xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
  89. bb_perror_msg_and_die("can't execute '%s'", argv[0]);
  90. }