- minor shrinkage
[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 "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(const char const * 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;
30
31         if (argc <= 1 || **(argv + 1) == '-') {
32                 bb_show_usage();
33         }
34         argc--;
35
36         path_list = getenv("PATH");
37         if (path_list != NULL) {
38                 size_t path_len = strlen(path_list);
39                 char *new_list = NULL;
40                 count = 1;
41
42                 for (i = 0; i <= path_len; i++) {
43                         char *this_i = &path_list[i];
44                         if (*this_i == ':') {
45                                 /* ^::[^:] == \.: */
46                                 if (!i && (*(this_i + 1) == ':')) {
47                                         *this_i = '.';
48                                         continue;
49                                 }
50                                 *this_i = 0;
51                                 count++;
52                                 /* ^:[^:] == \.0 and [^:]::[^:] == 0\.0 and [^:]:$ == 0\.0 */
53                                 if (!i || (*(this_i + 1) == ':') || (i == path_len-1)) {
54                                         new_list = xrealloc(new_list, path_len += 1);
55                                         if (i) {
56                                                 memmove(&new_list[i+2], &path_list[i+1], path_len-i);
57                                                 new_list[i+1] = '.';
58                                                 memmove(new_list, path_list, i);
59                                         } else {
60                                                 memmove(&new_list[i+1], &path_list[i], path_len-i);
61                                                 new_list[i] = '.';
62                                         }
63                                         path_list = new_list;
64                                 }
65                         }
66                 }
67         } else {
68                 path_list = "/bin\0/sbin\0/usr/bin\0/usr/sbin\0/usr/local/bin";
69                 count = 5;
70         }
71
72         status = EXIT_SUCCESS;
73         while (argc-- > 0) {
74                 struct stat stat_b;
75                 char *buf;
76                 char *path_n;
77                 int found = 0;
78
79                 argv++;
80                 path_n = path_list;
81                 buf = *argv;
82
83                 /* if filename is either absolute or contains slashes,
84                  * stat it */
85                 if (strchr(buf, '/') != NULL && is_executable_file(buf, &stat_b)) {
86                         found++;
87                 } else {
88                         /* Couldn't access file and file doesn't contain slashes */
89                         for (i = 0; i < count; i++) {
90                                 buf = concat_path_file(path_n, *argv);
91                                 if (is_executable_file(buf, &stat_b)) {
92                                         found++;
93                                         break;
94                                 }
95                                 free(buf);
96                                 path_n += (strlen(path_n) + 1);
97                         }
98                 }
99                 if (found) {
100                         puts(buf);
101                 } else {
102                         status = EXIT_FAILURE;
103                 }
104         }
105         bb_fflush_stdout_and_exit(status);
106 }