Robert P. Day removed 8 gazillion occurrences of "extern" on function
[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, see the file LICENSE in this tarball.
8  *
9  * Based on which from debianutils
10  */
11
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include "busybox.h"
18
19 int which_main(int argc, char **argv)
20 {
21         int status = EXIT_SUCCESS;
22         size_t i, count;
23         char *path_list;
24
25         if (argc <= 1 || **(argv + 1) == '-') {
26                 bb_show_usage();
27         }
28         argc--;
29
30         path_list = getenv("PATH");
31         if (path_list != NULL) {
32                 size_t path_len = bb_strlen(path_list);
33                 char *new_list = NULL;
34                 count = 1;
35
36                 for (i = 0; i <= path_len; i++) {
37                         char *this_i = &path_list[i];
38                         if (*this_i == ':') {
39                                 /* ^::[^:] == \.: */
40                                 if (!i && (*(this_i + 1) == ':')) {
41                                         *this_i = '.';
42                                         continue;
43                                 }
44                                 *this_i = 0;
45                                 count++;
46                                 /* ^:[^:] == \.0 and [^:]::[^:] == 0\.0 and [^:]:$ == 0\.0 */
47                                 if (!i || (*(this_i + 1) == ':') || (i == path_len-1)) {
48                                         new_list = xrealloc(new_list, path_len += 1);
49                                         if (i) {
50                                                 memmove(&new_list[i+2], &path_list[i+1], path_len-i);
51                                                 new_list[i+1] = '.';
52                                                 memmove(new_list, path_list, i);
53                                         } else {
54                                                 memmove(&new_list[i+1], &path_list[i], path_len-i);
55                                                 new_list[i] = '.';
56                                         }
57                                         path_list = new_list;
58                                 }
59                         }
60                 }
61         } else {
62                 path_list = "/bin\0/sbin\0/usr/bin\0/usr/sbin\0/usr/local/bin";
63                 count = 5;
64         }
65
66         while (argc-- > 0) {
67                 struct stat stat_b;
68                 char *buf;
69                 char *path_n;
70                 char found = 0;
71 #define is_executable_file(a, b) (!access(a,X_OK) && !stat(a, &b) && \
72                 S_ISREG(b.st_mode))
73
74                 argv++;
75                 path_n = path_list;
76                 buf = *argv;
77
78                 /* if filename is either absolute or contains slashes,
79                  * stat it */
80                 if (strchr(buf, '/') != NULL && is_executable_file(buf, stat_b)) {
81                         found = 1;
82                 } else {
83                         /* Couldn't access file and file doesn't contain slashes */
84                         for (i = 0; i < count; i++) {
85                                 buf = concat_path_file(path_n, *argv);
86                                 if (is_executable_file(buf, stat_b)) {
87                                         found = 1;
88                                         break;
89                                 }
90                                 free(buf);
91                                 path_n += (bb_strlen(path_n) + 1);
92                         }
93                 }
94                 if (found) {
95                         puts(buf);
96                 } else {
97                         status = EXIT_FAILURE;
98                 }
99         }
100         bb_fflush_stdout_and_exit(status);
101 }
102
103 /*
104 Local Variables:
105 c-file-style: "linux"
106 c-basic-offset: 4
107 tab-width: 4
108 End:
109 */