which: -84 bytes
[oweals/busybox.git] / debianutils / which.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Which implementation for busybox
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8  *
9  * Based on which from debianutils
10  */
11
12 #include "busybox.h"
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18
19
20 static int is_executable_file(char *a, struct stat *b)
21 {
22         return (!access(a,X_OK) && !stat(a, b) && S_ISREG(b->st_mode));
23 }
24
25 int which_main(int argc, char **argv)
26 {
27         int status;
28         size_t i, count;
29         char *path_list, *p;
30
31         if (argc <= 1 || argv[1][0] == '-') {
32                 bb_show_usage();
33         }
34         argc--;
35
36         path_list = getenv("PATH");
37         if (path_list != NULL) {
38                 count = 1;
39                 p = path_list;
40                 while ((p = strchr(p, ':')) != NULL) {
41                         *p++ = 0;
42                         count++;
43                 }
44         } else {
45                 path_list = "/bin\0/sbin\0/usr/bin\0/usr/sbin\0/usr/local/bin";
46                 count = 5;
47         }
48
49         status = EXIT_SUCCESS;
50         while (argc-- > 0) {
51                 struct stat stat_b;
52                 char *buf;
53
54                 argv++;
55                 buf = argv[0];
56
57                 /* If filename is either absolute or contains slashes,
58                  * stat it */
59                 if (strchr(buf, '/')) {
60                         if (is_executable_file(buf, &stat_b)) {
61                                 puts(buf);
62                                 goto next;
63                         }
64                 } else {
65                         /* File doesn't contain slashes */
66                         p = path_list;
67                         for (i = 0; i < count; i++) {
68                                 /* Empty component in PATH is treated as . */
69                                 buf = concat_path_file(p[0] ? p : ".", argv[0]);
70                                 if (is_executable_file(buf, &stat_b)) {
71                                         puts(buf);
72                                         free(buf);
73                                         goto next;
74                                 }
75                                 free(buf);
76                                 p += strlen(p) + 1;
77                         }
78                 }
79                 status = EXIT_FAILURE;
80  next:          /* nothing */;
81         }
82         bb_fflush_stdout_and_exit(status);
83 }