logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/

which.c (1531B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include <limits.h> // PATH_MAX
  6. #include <stdbool.h>
  7. #include <stdio.h> // fprintf
  8. #include <stdlib.h> // getenv
  9. #include <string.h> // strtok
  10. #include <unistd.h> // access, getopt
  11. int
  12. main(int argc, char *argv[])
  13. {
  14. bool opt_a = false, opt_s = false;
  15. int missing = 0;
  16. char *path = getenv("PATH");
  17. if(path == NULL)
  18. {
  19. fputs("which: error: $PATH environment unset", stderr);
  20. return 1;
  21. }
  22. int c = -1;
  23. while((c = getopt(argc, argv, "as")) != -1)
  24. {
  25. switch(c)
  26. {
  27. case 'a':
  28. opt_a = true;
  29. break;
  30. case 's':
  31. opt_s = true;
  32. break;
  33. case '?':
  34. fprintf(stderr, "which: error: Unrecognised option: '-%c'\n", optopt);
  35. return 1;
  36. default:
  37. abort();
  38. }
  39. }
  40. argc -= optind;
  41. argv += optind;
  42. if(argc <= 0) return 1;
  43. for(int i = 0; i < argc; i++)
  44. {
  45. char *cmd = argv[i];
  46. bool found = false;
  47. char *state = NULL;
  48. char *hay = strdup(path);
  49. if(hay == NULL)
  50. {
  51. perror("which: error: Failed duplicating $PATH");
  52. return 1;
  53. }
  54. for(char *tok = strtok_r(hay, ":", &state); tok != NULL; tok = strtok_r(NULL, ":", &state))
  55. {
  56. char buf[PATH_MAX] = "";
  57. snprintf(buf, PATH_MAX, "%s/%s", tok, cmd);
  58. if(access(buf, X_OK) == 0)
  59. {
  60. if(!opt_s) puts(buf);
  61. found = true;
  62. if(!opt_a) break;
  63. }
  64. }
  65. if(!found) missing++;
  66. free(hay);
  67. }
  68. return missing;
  69. }