enable login utils
[framework/base/util-linux-ng.git] / misc-utils / whereis.c
1 /*-
2  * Copyright (c) 1980 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /* *:aeb */
35
36 /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
37  * - added Native Language Support
38  */
39
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <dirent.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include "nls.h"
49 #include "c.h"
50
51 static char *bindirs[] = {
52         "/bin",
53         "/usr/bin",
54         "/sbin",
55         "/usr/sbin",
56         "/etc",
57         "/usr/etc",
58         "/lib",
59         "/usr/lib",
60         "/lib64",
61         "/usr/lib64",
62         "/usr/games",
63         "/usr/games/bin",
64         "/usr/games/lib",
65         "/usr/emacs/etc",
66         "/usr/lib/emacs/*/etc",
67         "/usr/TeX/bin",
68         "/usr/tex/bin",
69         "/usr/interviews/bin/LINUX",
70
71         "/usr/X11R6/bin",
72         "/usr/X386/bin",
73         "/usr/bin/X11",
74         "/usr/X11/bin",
75         "/usr/X11R5/bin",
76
77         "/usr/local/bin",
78         "/usr/local/sbin",
79         "/usr/local/etc",
80         "/usr/local/lib",
81         "/usr/local/games",
82         "/usr/local/games/bin",
83         "/usr/local/emacs/etc",
84         "/usr/local/TeX/bin",
85         "/usr/local/tex/bin",
86         "/usr/local/bin/X11",
87
88         "/usr/contrib",
89         "/usr/hosts",
90         "/usr/include",
91
92         "/usr/g++-include",
93
94         "/usr/ucb",
95         "/usr/old",
96         "/usr/new",
97         "/usr/local",
98         "/usr/libexec",
99         "/usr/share",
100
101         "/opt/*/bin",
102
103         0
104 };
105
106 static char *mandirs[] = {
107         "/usr/man/*",
108         "/usr/share/man/*",
109         "/usr/X386/man/*",
110         "/usr/X11/man/*",
111         "/usr/TeX/man/*",
112         "/usr/interviews/man/mann",
113         0
114 };
115
116 static char *srcdirs[] = {
117         "/usr/src/*",
118         "/usr/src/lib/libc/*",
119         "/usr/src/lib/libc/net/*",
120         "/usr/src/ucb/pascal",
121         "/usr/src/ucb/pascal/utilities",
122         "/usr/src/undoc",
123         0
124 };
125
126 static char sflag = 1, bflag = 1, mflag = 1, uflag;
127 static char **Sflag, **Bflag, **Mflag;
128 static int Scnt, Bcnt, Mcnt, count, print;
129
130 static void __attribute__ ((__noreturn__)) usage(FILE * out)
131 {
132         fputs(_("\nUsage:\n"), out);
133         fprintf(out,
134               _(" %s [options] file\n"), program_invocation_short_name);
135
136         fputs(_("\nOptions:\n"), out);
137         fputs(_(" -f <file>  define search scope\n"
138                 " -b         search only binaries\n"
139                 " -B <dirs>  define binaries lookup path\n"
140                 " -m         search only manual paths\n"
141                 " -M <dirs>  define man lookup path\n"
142                 " -s         search only sources path\n"
143                 " -S <dirs>  define sources lookup path\n"
144                 " -u         search from unusual enties\n"
145                 " -V         output version information and exit\n"
146                 " -h         display this help and exit\n\n"), out);
147
148         fputs(_("See how to use file and dirs arguments from whereis(1) manual.\n"), out);
149         exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
150 }
151
152 static int
153 itsit(char *cp, char *dp)
154 {
155         int i = strlen(dp);
156
157         if (dp[0] == 's' && dp[1] == '.' && itsit(cp, dp + 2))
158                 return 1;
159         if (!strcmp(dp + i - 2, ".Z"))
160                 i -= 2;
161         else if (!strcmp(dp + i - 3, ".gz"))
162                 i -= 3;
163         else if (!strcmp(dp + i - 4, ".bz2"))
164                 i -= 4;
165         while (*cp && *dp && *cp == *dp)
166                 cp++, dp++, i--;
167         if (*cp == 0 && *dp == 0)
168                 return 1;
169         while (isdigit(*dp))
170                 dp++;
171         if (*cp == 0 && *dp++ == '.') {
172                 --i;
173                 while (i > 0 && *dp)
174                         if (--i, *dp++ == '.')
175                                 return (*dp++ == 'C' && *dp++ == 0);
176                 return 1;
177         }
178         return 0;
179 }
180
181 static void
182 findin(char *dir, char *cp)
183 {
184         DIR *dirp;
185         struct dirent *dp;
186         char *d, *dd;
187         size_t l;
188         char dirbuf[1024];
189         struct stat statbuf;
190
191         dd = strchr(dir, '*');
192         if (!dd) {
193                 dirp = opendir(dir);
194                 if (dirp == NULL)
195                         return;
196                 while ((dp = readdir(dirp)) != NULL) {
197                         if (itsit(cp, dp->d_name)) {
198                                 count++;
199                                 if (print)
200                                         printf(" %s/%s", dir, dp->d_name);
201                         }
202                 }
203                 closedir(dirp);
204                 return;
205         }
206
207         l = strlen(dir);
208         if (l < sizeof(dirbuf)) {
209                 /* refuse excessively long names */
210                 strcpy(dirbuf, dir);
211                 d = strchr(dirbuf, '*');
212                 *d = 0;
213                 dirp = opendir(dirbuf);
214                 if (dirp == NULL)
215                         return;
216                 while ((dp = readdir(dirp)) != NULL) {
217                         if (!strcmp(dp->d_name, ".") ||
218                             !strcmp(dp->d_name, ".."))
219                                 continue;
220                         if (strlen(dp->d_name) + l > sizeof(dirbuf))
221                                 continue;
222                         sprintf(d, "%s", dp->d_name);
223                         if (stat(dirbuf, &statbuf))
224                                 continue;
225                         if (!S_ISDIR(statbuf.st_mode))
226                                 continue;
227                         strcat(d, dd + 1);
228                         findin(dirbuf, cp);
229                 }
230                 closedir(dirp);
231         }
232         return;
233
234 }
235
236 static void
237 findv(char **dirv, int dirc, char *cp)
238 {
239         while (dirc > 0)
240                 findin(*dirv++, cp), dirc--;
241 }
242
243 static void
244 looksrc(char *cp)
245 {
246         if (Sflag == 0)
247                 findv(srcdirs, ARRAY_SIZE(srcdirs)-1, cp);
248         else
249                 findv(Sflag, Scnt, cp);
250 }
251
252 static void
253 lookbin(char *cp)
254 {
255         if (Bflag == 0)
256                 findv(bindirs, ARRAY_SIZE(bindirs)-1, cp);
257         else
258                 findv(Bflag, Bcnt, cp);
259 }
260
261 static void
262 lookman(char *cp)
263 {
264         if (Mflag == 0)
265                 findv(mandirs, ARRAY_SIZE(mandirs)-1, cp);
266         else
267                 findv(Mflag, Mcnt, cp);
268 }
269
270 static void
271 getlist(int *argcp, char ***argvp, char ***flagp, int *cntp)
272 {
273         (*argvp)++;
274         *flagp = *argvp;
275         *cntp = 0;
276         for ((*argcp)--; *argcp > 0 && (*argvp)[0][0] != '-'; (*argcp)--)
277                 (*cntp)++, (*argvp)++;
278         (*argcp)++;
279         (*argvp)--;
280 }
281
282 static void
283 zerof()
284 {
285         if (sflag && bflag && mflag)
286                 sflag = bflag = mflag = 0;
287 }
288
289 static int
290 print_again(char *cp)
291 {
292         if (print)
293                 printf("%s:", cp);
294         if (sflag) {
295                 looksrc(cp);
296                 if (uflag && print == 0 && count != 1) {
297                         print = 1;
298                         return 1;
299                 }
300         }
301         count = 0;
302         if (bflag) {
303                 lookbin(cp);
304                 if (uflag && print == 0 && count != 1) {
305                         print = 1;
306                         return 1;
307                 }
308         }
309         count = 0;
310         if (mflag) {
311                 lookman(cp);
312                 if (uflag && print == 0 && count != 1) {
313                         print = 1;
314                         return 1;
315                 }
316         }
317         return 0;
318 }
319
320 static void
321 lookup(char *cp)
322 {
323         register char *dp;
324
325         for (dp = cp; *dp; dp++)
326                 continue;
327         for (; dp > cp; dp--) {
328                 if (*dp == '.') {
329                         *dp = 0;
330                         break;
331                 }
332         }
333         for (dp = cp; *dp; dp++)
334                 if (*dp == '/')
335                         cp = dp + 1;
336         if (uflag) {
337                 print = 0;
338                 count = 0;
339         } else
340                 print = 1;
341
342         while (print_again(cp))
343                 /* all in print_again() */ ;
344
345         if (print)
346                 printf("\n");
347 }
348
349 /*
350  * whereis name
351  * look for source, documentation and binaries
352  */
353 int
354 main(int argc, char **argv)
355 {
356         setlocale(LC_ALL, "");
357         bindtextdomain(PACKAGE, LOCALEDIR);
358         textdomain(PACKAGE);
359
360         argc--, argv++;
361         if (argc == 0)
362                 usage(stderr);
363
364         do
365                 if (argv[0][0] == '-') {
366                         register char *cp = argv[0] + 1;
367                         while (*cp) switch (*cp++) {
368
369                         case 'f':
370                                 break;
371
372                         case 'S':
373                                 getlist(&argc, &argv, &Sflag, &Scnt);
374                                 break;
375
376                         case 'B':
377                                 getlist(&argc, &argv, &Bflag, &Bcnt);
378                                 break;
379
380                         case 'M':
381                                 getlist(&argc, &argv, &Mflag, &Mcnt);
382                                 break;
383
384                         case 's':
385                                 zerof();
386                                 sflag++;
387                                 continue;
388
389                         case 'u':
390                                 uflag++;
391                                 continue;
392
393                         case 'b':
394                                 zerof();
395                                 bflag++;
396                                 continue;
397
398                         case 'm':
399                                 zerof();
400                                 mflag++;
401                                 continue;
402                         case 'V':
403                                 printf(_("%s from %s\n"),
404                                         program_invocation_short_name,
405                                         PACKAGE_STRING);
406                                 return EXIT_SUCCESS;
407                         case 'h':
408                                 usage(stdout);
409                         default:
410                                 usage(stderr);
411                         }
412                         argv++;
413                 } else
414                         lookup(*argv++);
415         while (--argc > 0);
416         return EXIT_SUCCESS;
417 }