]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/whereis.c
Merge branch 'meson-more-build-options' of https://github.com/jwillikers/util-linux
[thirdparty/util-linux.git] / misc-utils / whereis.c
CommitLineData
6dbe3af9
KZ
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.
9db54a7e
SK
32 *
33 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c 34 * - added Native Language Support
9db54a7e 35 * 2011-08-12 Davidlohr Bueso <dave@gnu.org>
f51be859 36 * - added $PATH lookup
9db54a7e
SK
37 *
38 * Copyright (C) 2013 Karel Zak <kzak@redhat.com>
39 * 2013 Sami Kerola <kerolasa@iki.fi>
f51be859
DB
40 */
41
6dbe3af9 42#include <sys/param.h>
7574f09b 43#include <sys/types.h>
2b6fc908 44#include <sys/stat.h>
7574f09b 45#include <dirent.h>
6dbe3af9 46#include <stdio.h>
66ee8158 47#include <stdlib.h>
fd6b7a7f 48#include <string.h>
6dbe3af9 49#include <ctype.h>
9db54a7e 50#include <assert.h>
d9b022bd
KZ
51#ifdef HAVE_FNMATCH
52# include <fnmatch.h>
53#endif
f51be859
DB
54
55#include "xalloc.h"
7eda085c 56#include "nls.h"
58513363 57#include "c.h"
c05a80ca 58#include "closestream.h"
f84559ee 59#include "canonicalize.h"
6dbe3af9 60
3635f53c
KZ
61#include "debug.h"
62
2ba641e5 63static UL_DEBUG_DEFINE_MASK(whereis);
819d9a29 64UL_DEBUG_DEFINE_MASKNAMES(whereis) = UL_DEBUG_EMPTY_MASKNAMES;
3635f53c
KZ
65
66#define WHEREIS_DEBUG_INIT (1 << 1)
67#define WHEREIS_DEBUG_PATH (1 << 2)
68#define WHEREIS_DEBUG_ENV (1 << 3)
69#define WHEREIS_DEBUG_ARGV (1 << 4)
70#define WHEREIS_DEBUG_SEARCH (1 << 5)
71#define WHEREIS_DEBUG_STATIC (1 << 6)
72#define WHEREIS_DEBUG_LIST (1 << 7)
73#define WHEREIS_DEBUG_ALL 0xFFFF
74
75#define DBG(m, x) __UL_DBG(whereis, WHEREIS_DEBUG_, m, x)
76#define ON_DBG(m, x) __UL_DBG_CALL(whereis, WHEREIS_DEBUG_, m, x)
9db54a7e 77
6d00cfb2
KZ
78#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(whereis)
79#include "debugobj.h"
80
d9b022bd
KZ
81static char uflag;
82static char use_glob;
9db54a7e
SK
83
84/* supported types */
85enum {
86 BIN_DIR = (1 << 1),
87 MAN_DIR = (1 << 2),
88 SRC_DIR = (1 << 3),
89
90 ALL_DIRS = BIN_DIR | MAN_DIR | SRC_DIR
91};
92
93/* directories */
94struct wh_dirlist {
95 int type;
96 dev_t st_dev;
97 ino_t st_ino;
98 char *path;
99
100 struct wh_dirlist *next;
101};
102
103static const char *bindirs[] = {
30ad62d0 104 "/usr/bin",
30ad62d0 105 "/usr/sbin",
9ed21178
KZ
106 "/bin",
107 "/sbin",
c9ab7387
AH
108#if defined(MULTIARCHTRIPLET)
109 "/lib/" MULTIARCHTRIPLET,
110 "/usr/lib/" MULTIARCHTRIPLET,
111 "/usr/local/lib/" MULTIARCHTRIPLET,
112#endif
f84559ee 113 "/usr/lib",
74b7c01f 114 "/usr/lib32",
f84559ee 115 "/usr/lib64",
30ad62d0
SK
116 "/etc",
117 "/usr/etc",
118 "/lib",
74b7c01f 119 "/lib32",
30ad62d0 120 "/lib64",
30ad62d0
SK
121 "/usr/games",
122 "/usr/games/bin",
123 "/usr/games/lib",
124 "/usr/emacs/etc",
125 "/usr/lib/emacs/*/etc",
126 "/usr/TeX/bin",
127 "/usr/tex/bin",
128 "/usr/interviews/bin/LINUX",
129
130 "/usr/X11R6/bin",
131 "/usr/X386/bin",
132 "/usr/bin/X11",
133 "/usr/X11/bin",
134 "/usr/X11R5/bin",
135
136 "/usr/local/bin",
137 "/usr/local/sbin",
138 "/usr/local/etc",
139 "/usr/local/lib",
140 "/usr/local/games",
141 "/usr/local/games/bin",
142 "/usr/local/emacs/etc",
143 "/usr/local/TeX/bin",
144 "/usr/local/tex/bin",
145 "/usr/local/bin/X11",
146
147 "/usr/contrib",
148 "/usr/hosts",
149 "/usr/include",
150
151 "/usr/g++-include",
152
153 "/usr/ucb",
154 "/usr/old",
155 "/usr/new",
156 "/usr/local",
157 "/usr/libexec",
158 "/usr/share",
159
160 "/opt/*/bin",
9db54a7e 161 NULL
6dbe3af9 162};
2b6fc908 163
9db54a7e 164static const char *mandirs[] = {
2b6fc908 165 "/usr/man/*",
66ee8158 166 "/usr/share/man/*",
2b6fc908
KZ
167 "/usr/X386/man/*",
168 "/usr/X11/man/*",
169 "/usr/TeX/man/*",
6dbe3af9 170 "/usr/interviews/man/mann",
db0ccb76 171 "/usr/share/info",
9db54a7e 172 NULL
6dbe3af9 173};
2b6fc908 174
9db54a7e 175static const char *srcdirs[] = {
2b6fc908
KZ
176 "/usr/src/*",
177 "/usr/src/lib/libc/*",
178 "/usr/src/lib/libc/net/*",
6dbe3af9
KZ
179 "/usr/src/ucb/pascal",
180 "/usr/src/ucb/pascal/utilities",
181 "/usr/src/undoc",
9db54a7e 182 NULL
6dbe3af9
KZ
183};
184
3635f53c
KZ
185static void whereis_init_debug(void)
186{
a15dca2f 187 __UL_INIT_DEBUG_FROM_ENV(whereis, WHEREIS_DEBUG_, 0, WHEREIS_DEBUG);
3635f53c
KZ
188}
189
190static const char *whereis_type_to_name(int type)
191{
192 switch (type) {
193 case BIN_DIR: return "bin";
194 case MAN_DIR: return "man";
195 case SRC_DIR: return "src";
196 default: return "???";
197 }
198}
9db54a7e 199
5aaa966d 200static void __attribute__((__noreturn__)) usage(void)
58513363 201{
5aaa966d
RM
202 FILE *out = stdout;
203
ec3bc7aa 204 fputs(USAGE_HEADER, out);
bde76c04 205 fprintf(out, _(" %s [options] [-BMS <dir>... -f] <name>\n"), program_invocation_short_name);
ec3bc7aa 206
451dbcfa
BS
207 fputs(USAGE_SEPARATOR, out);
208 fputs(_("Locate the binary, source, and manual-page files for a command.\n"), out);
209
ec3bc7aa
SK
210 fputs(USAGE_OPTIONS, out);
211 fputs(_(" -b search only for binaries\n"), out);
212 fputs(_(" -B <dirs> define binaries lookup path\n"), out);
db0ccb76
KZ
213 fputs(_(" -m search only for manuals and infos\n"), out);
214 fputs(_(" -M <dirs> define man and info lookup path\n"), out);
ec3bc7aa
SK
215 fputs(_(" -s search only for sources\n"), out);
216 fputs(_(" -S <dirs> define sources lookup path\n"), out);
217 fputs(_(" -f terminate <dirs> argument list\n"), out);
218 fputs(_(" -u search for unusual entries\n"), out);
d9b022bd 219 fputs(_(" -g interpret name as glob (pathnames pattern)\n"), out);
ec3bc7aa 220 fputs(_(" -l output effective lookup paths\n"), out);
ec3bc7aa 221
5aaa966d 222 fputs(USAGE_SEPARATOR, out);
bad4c729
MY
223 fprintf(out, USAGE_HELP_OPTIONS(16));
224 fprintf(out, USAGE_MAN_TAIL("whereis(1)"));
5aaa966d 225 exit(EXIT_SUCCESS);
58513363
SK
226}
227
9db54a7e 228static void dirlist_add_dir(struct wh_dirlist **ls0, int type, const char *dir)
30ad62d0 229{
9db54a7e
SK
230 struct stat st;
231 struct wh_dirlist *prev = NULL, *ls = *ls0;
32ae96ae 232
9db54a7e
SK
233 if (access(dir, R_OK) != 0)
234 return;
235 if (stat(dir, &st) != 0 || !S_ISDIR(st.st_mode))
236 return;
3635f53c 237
9db54a7e
SK
238 while (ls) {
239 if (ls->st_ino == st.st_ino &&
240 ls->st_dev == st.st_dev &&
241 ls->type == type) {
3635f53c 242 DBG(LIST, ul_debugobj(*ls0, " ignore (already in list): %s", dir));
0b542a94 243 return;
0b542a94 244 }
9db54a7e
SK
245 prev = ls;
246 ls = ls->next;
0b542a94 247 }
6dbe3af9 248
9db54a7e
SK
249
250 ls = xcalloc(1, sizeof(*ls));
251 ls->st_ino = st.st_ino;
252 ls->st_dev = st.st_dev;
253 ls->type = type;
f84559ee 254 ls->path = canonicalize_path(dir);
9db54a7e
SK
255
256 if (!*ls0)
257 *ls0 = ls; /* first in the list */
258 else {
259 assert(prev);
260 prev->next = ls; /* add to the end of the list */
0b542a94 261 }
3635f53c
KZ
262
263 DBG(LIST, ul_debugobj(*ls0, " add dir: %s", ls->path));
0b542a94 264}
6dbe3af9 265
9db54a7e
SK
266/* special case for '*' in the paths */
267static void dirlist_add_subdir(struct wh_dirlist **ls, int type, const char *dir)
f51be859 268{
9db54a7e
SK
269 char buf[PATH_MAX], *d;
270 DIR *dirp;
271 struct dirent *dp;
a2761af4
KZ
272 char *postfix;
273 size_t len;
f51be859 274
a2761af4
KZ
275 postfix = strchr(dir, '*');
276 if (!postfix)
277 goto ignore;
f51be859 278
a2761af4
KZ
279 /* copy begin of the path to the buffer (part before '*') */
280 len = (postfix - dir) + 1;
281 xstrncpy(buf, dir, len);
282
283 /* remember place where to append subdirs */
284 d = buf + len - 1;
285
286 /* skip '*' */
287 postfix++;
288 if (!*postfix)
289 postfix = NULL;
f51be859 290
a2761af4 291 /* open parental dir t scan */
9db54a7e
SK
292 dirp = opendir(buf);
293 if (!dirp)
a2761af4 294 goto ignore;
9db54a7e 295
a2761af4
KZ
296 DBG(LIST, ul_debugobj(*ls, " scanning subdirs: %s [%s<subdir>%s]",
297 dir, buf, postfix ? postfix : ""));
9db54a7e
SK
298
299 while ((dp = readdir(dirp)) != NULL) {
300 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
301 continue;
a2761af4
KZ
302 if (postfix)
303 snprintf(d, PATH_MAX - len, "%s%s", dp->d_name, postfix);
304 else
305 snprintf(d, PATH_MAX - len, "%s", dp->d_name);
306
9db54a7e
SK
307 dirlist_add_dir(ls, type, buf);
308 }
309 closedir(dirp);
310 return;
a2761af4
KZ
311ignore:
312 DBG(LIST, ul_debugobj(*ls, " ignore path: %s", dir));
f51be859
DB
313}
314
9db54a7e
SK
315static void construct_dirlist_from_env(const char *env,
316 struct wh_dirlist **ls,
317 int type)
f51be859 318{
9db54a7e 319 char *key = NULL, *tok = NULL, *pathcp, *path = getenv(env);
f51be859
DB
320
321 if (!path)
322 return;
323 pathcp = xstrdup(path);
324
3635f53c
KZ
325 DBG(ENV, ul_debugobj(*ls, "construct %s dirlist from: %s",
326 whereis_type_to_name(type), path));
f51be859 327
9db54a7e
SK
328 for (tok = strtok_r(pathcp, ":", &key); tok;
329 tok = strtok_r(NULL, ":", &key))
330 dirlist_add_dir(ls, type, tok);
f51be859 331
f51be859
DB
332 free(pathcp);
333}
334
9db54a7e
SK
335static void construct_dirlist_from_argv(struct wh_dirlist **ls,
336 int *idx,
337 int argc,
338 char *argv[],
339 int type)
f51be859 340{
3635f53c 341 int i;
9db54a7e 342
3635f53c
KZ
343 DBG(ARGV, ul_debugobj(*ls, "construct %s dirlist from argv[%d..]",
344 whereis_type_to_name(type), *idx));
345
346 for (i = *idx; i < argc; i++) {
347 if (*argv[i] == '-') /* end of the list */
348 break;
349
350 DBG(ARGV, ul_debugobj(*ls, " using argv[%d]: %s", *idx, argv[*idx]));
351 dirlist_add_dir(ls, type, argv[i]);
352 *idx = i;
9db54a7e 353 }
f51be859
DB
354}
355
9db54a7e
SK
356static void construct_dirlist(struct wh_dirlist **ls,
357 int type,
358 const char **paths)
0b542a94 359{
9db54a7e 360 size_t i;
f51be859 361
3635f53c
KZ
362 DBG(STATIC, ul_debugobj(*ls, "construct %s dirlist from static array",
363 whereis_type_to_name(type)));
6dbe3af9 364
9db54a7e
SK
365 for (i = 0; paths[i]; i++) {
366 if (!strchr(paths[i], '*'))
367 dirlist_add_dir(ls, type, paths[i]);
368 else
369 dirlist_add_subdir(ls, type, paths[i]);
370 }
0b542a94 371}
6dbe3af9 372
9db54a7e 373static void free_dirlist(struct wh_dirlist **ls0, int type)
0b542a94 374{
9db54a7e 375 struct wh_dirlist *prev = NULL, *next, *ls = *ls0;
6dbe3af9 376
9db54a7e 377 *ls0 = NULL;
6dbe3af9 378
3635f53c 379 DBG(LIST, ul_debugobj(*ls0, "free dirlist"));
9db54a7e
SK
380
381 while (ls) {
382 if (ls->type & type) {
383 next = ls->next;
3635f53c 384 DBG(LIST, ul_debugobj(*ls0, " free: %s", ls->path));
9db54a7e
SK
385 free(ls->path);
386 free(ls);
387 ls = next;
388 if (prev)
389 prev->next = ls;
390 } else {
391 if (!prev)
392 *ls0 = ls; /* first unremoved */
393 prev = ls;
394 ls = ls->next;
395 }
396 }
6dbe3af9
KZ
397}
398
9db54a7e 399
653f672a 400static int filename_equal(const char *cp, const char *dp, int type)
6dbe3af9 401{
d9b022bd 402 size_t i;
9db54a7e 403
db0ccb76 404 DBG(SEARCH, ul_debug("compare '%s' and '%s'", cp, dp));
9db54a7e 405
d9b022bd
KZ
406#ifdef HAVE_FNMATCH
407 if (use_glob)
408 return fnmatch(cp, dp, 0) == 0;
409#endif
653f672a
SN
410 if (type & SRC_DIR &&
411 dp[0] == 's' && dp[1] == '.' && filename_equal(cp, dp + 2, type))
9db54a7e 412 return 1;
d9b022bd
KZ
413
414 i = strlen(dp);
415
653f672a
SN
416 if (type & MAN_DIR) {
417 if (i > 1 && !strcmp(dp + i - 2, ".Z"))
418 i -= 2;
419 else if (i > 2 && !strcmp(dp + i - 3, ".gz"))
420 i -= 3;
421 else if (i > 2 && !strcmp(dp + i - 3, ".xz"))
422 i -= 3;
423 else if (i > 3 && !strcmp(dp + i - 4, ".bz2"))
424 i -= 4;
425 else if (i > 3 && !strcmp(dp + i - 4, ".zst"))
426 i -= 4;
427 }
9db54a7e
SK
428 while (*cp && *dp && *cp == *dp)
429 cp++, dp++, i--;
430 if (*cp == 0 && *dp == 0)
431 return 1;
653f672a 432 if (!(type & BIN_DIR) && *cp == 0 && *dp++ == '.') {
9db54a7e
SK
433 --i;
434 while (i > 0 && *dp)
435 if (--i, *dp++ == '.')
436 return (*dp++ == 'C' && *dp++ == 0);
437 return 1;
438 }
439 return 0;
6dbe3af9 440}
fd6b7a7f 441
653f672a
SN
442static void findin(const char *dir, const char *pattern, int *count,
443 char **wait, int type)
12b80642 444{
9db54a7e
SK
445 DIR *dirp;
446 struct dirent *dp;
447
448 dirp = opendir(dir);
449 if (dirp == NULL)
450 return;
451
3635f53c 452 DBG(SEARCH, ul_debug("find '%s' in '%s'", pattern, dir));
9db54a7e
SK
453
454 while ((dp = readdir(dirp)) != NULL) {
653f672a 455 if (!filename_equal(pattern, dp->d_name, type))
9db54a7e
SK
456 continue;
457
458 if (uflag && *count == 0)
459 xasprintf(wait, "%s/%s", dir, dp->d_name);
460
461 else if (uflag && *count == 1 && *wait) {
462 printf("%s: %s %s/%s", pattern, *wait, dir, dp->d_name);
463 free(*wait);
464 *wait = NULL;
465 } else
466 printf(" %s/%s", dir, dp->d_name);
467 ++(*count);
12b80642 468 }
9db54a7e 469 closedir(dirp);
12b80642
SK
470}
471
9db54a7e 472static void lookup(const char *pattern, struct wh_dirlist *ls, int want)
30ad62d0 473{
9db54a7e
SK
474 char patbuf[PATH_MAX];
475 int count = 0;
476 char *wait = NULL, *p;
477
9db54a7e
SK
478 /* canonicalize pattern -- remove path suffix etc. */
479 p = strrchr(pattern, '/');
480 p = p ? p + 1 : (char *) pattern;
aa75c5eb 481 xstrncpy(patbuf, p, PATH_MAX);
3635f53c
KZ
482
483 DBG(SEARCH, ul_debug("lookup dirs for '%s' (%s), want: %s %s %s",
484 patbuf, pattern,
485 want & BIN_DIR ? "bin" : "",
7468a8d1 486 want & MAN_DIR ? "man" : "",
3635f53c 487 want & SRC_DIR ? "src" : ""));
9db54a7e
SK
488
489 if (!uflag)
490 /* if -u not specified then we always print the pattern */
491 printf("%s:", patbuf);
492
493 for (; ls; ls = ls->next) {
494 if ((ls->type & want) && ls->path)
653f672a 495 findin(ls->path, patbuf, &count, &wait, ls->type);
6dbe3af9 496 }
9db54a7e
SK
497
498 free(wait);
499
7508d991 500 if (!uflag || count > 1)
9db54a7e 501 putchar('\n');
6dbe3af9
KZ
502}
503
3bfb9636
SK
504static void list_dirlist(struct wh_dirlist *ls)
505{
506 while (ls) {
507 if (ls->path) {
508 switch (ls->type) {
509 case BIN_DIR:
510 printf("bin: ");
511 break;
512 case MAN_DIR:
513 printf("man: ");
514 break;
515 case SRC_DIR:
516 printf("src: ");
517 break;
518 default:
519 abort();
520 }
521 printf("%s\n", ls->path);
522 }
523 ls = ls->next;
524 }
525}
526
9db54a7e 527int main(int argc, char **argv)
30ad62d0 528{
9db54a7e
SK
529 struct wh_dirlist *ls = NULL;
530 int want = ALL_DIRS;
a3d29ee0 531 int i, want_resetable = 0, opt_f_missing = 0;
9db54a7e 532
0b542a94
DB
533 setlocale(LC_ALL, "");
534 bindtextdomain(PACKAGE, LOCALEDIR);
535 textdomain(PACKAGE);
2c308875 536 close_stdout_atexit();
6dbe3af9 537
5aaa966d
RM
538 if (argc <= 1) {
539 warnx(_("not enough arguments"));
540 errtryhelp(EXIT_FAILURE);
541 } else {
542 /* first arg may be one of our standard longopts */
543 if (!strcmp(argv[1], "--help"))
544 usage();
2c308875
KZ
545 if (!strcmp(argv[1], "--version"))
546 print_version(EXIT_SUCCESS);
5aaa966d 547 }
6dbe3af9 548
3635f53c
KZ
549 whereis_init_debug();
550
9db54a7e
SK
551 construct_dirlist(&ls, BIN_DIR, bindirs);
552 construct_dirlist_from_env("PATH", &ls, BIN_DIR);
553
554 construct_dirlist(&ls, MAN_DIR, mandirs);
ccec32a1
SK
555 construct_dirlist_from_env("MANPATH", &ls, MAN_DIR);
556
9db54a7e
SK
557 construct_dirlist(&ls, SRC_DIR, srcdirs);
558
559 for (i = 1; i < argc; i++) {
560 const char *arg = argv[i];
3635f53c
KZ
561 int arg_i = i;
562
563 DBG(ARGV, ul_debug("argv[%d]: %s", i, arg));
6dbe3af9 564
9db54a7e
SK
565 if (*arg != '-') {
566 lookup(arg, ls, want);
f4802c90
KZ
567 /*
568 * The lookup mask ("want") is cumulative and it's
11026083 569 * resettable only when it has been already used.
9db54a7e 570 *
f4802c90
KZ
571 * whereis -b -m foo :'foo' mask=BIN|MAN
572 * whereis -b foo bar :'foo' and 'bar' mask=BIN|MAN
573 * whereis -b foo -m bar :'foo' mask=BIN; 'bar' mask=MAN
9db54a7e 574 */
f4802c90
KZ
575 want_resetable = 1;
576 continue;
3635f53c 577 }
9db54a7e
SK
578
579 for (++arg; arg && *arg; arg++) {
3635f53c
KZ
580 DBG(ARGV, ul_debug(" arg: %s", arg));
581
9db54a7e 582 switch (*arg) {
0b542a94 583 case 'f':
a3d29ee0 584 opt_f_missing = 0;
0b542a94 585 break;
9db54a7e
SK
586 case 'u':
587 uflag = 1;
a3d29ee0 588 opt_f_missing = 0;
0b542a94 589 break;
0b542a94 590 case 'B':
5aaa966d
RM
591 if (*(arg + 1)) {
592 warnx(_("bad usage"));
593 errtryhelp(EXIT_FAILURE);
594 }
9db54a7e
SK
595 i++;
596 free_dirlist(&ls, BIN_DIR);
597 construct_dirlist_from_argv(
598 &ls, &i, argc, argv, BIN_DIR);
a3d29ee0 599 opt_f_missing = 1;
0b542a94 600 break;
0b542a94 601 case 'M':
5aaa966d
RM
602 if (*(arg + 1)) {
603 warnx(_("bad usage"));
604 errtryhelp(EXIT_FAILURE);
605 }
9db54a7e
SK
606 i++;
607 free_dirlist(&ls, MAN_DIR);
608 construct_dirlist_from_argv(
609 &ls, &i, argc, argv, MAN_DIR);
a3d29ee0 610 opt_f_missing = 1;
9db54a7e
SK
611 break;
612 case 'S':
5aaa966d
RM
613 if (*(arg + 1)) {
614 warnx(_("bad usage"));
615 errtryhelp(EXIT_FAILURE);
616 }
9db54a7e
SK
617 i++;
618 free_dirlist(&ls, SRC_DIR);
619 construct_dirlist_from_argv(
620 &ls, &i, argc, argv, SRC_DIR);
a3d29ee0 621 opt_f_missing = 1;
0b542a94 622 break;
0b542a94 623 case 'b':
f4802c90
KZ
624 if (want_resetable) {
625 want = ALL_DIRS;
626 want_resetable = 0;
627 }
9db54a7e 628 want = want == ALL_DIRS ? BIN_DIR : want | BIN_DIR;
a3d29ee0 629 opt_f_missing = 0;
9db54a7e 630 break;
0b542a94 631 case 'm':
f4802c90
KZ
632 if (want_resetable) {
633 want = ALL_DIRS;
634 want_resetable = 0;
635 }
9db54a7e 636 want = want == ALL_DIRS ? MAN_DIR : want | MAN_DIR;
a3d29ee0 637 opt_f_missing = 0;
9db54a7e
SK
638 break;
639 case 's':
f4802c90
KZ
640 if (want_resetable) {
641 want = ALL_DIRS;
642 want_resetable = 0;
643 }
9db54a7e 644 want = want == ALL_DIRS ? SRC_DIR : want | SRC_DIR;
a3d29ee0 645 opt_f_missing = 0;
9db54a7e 646 break;
3bfb9636
SK
647 case 'l':
648 list_dirlist(ls);
649 break;
d9b022bd
KZ
650 case 'g':
651 use_glob = 1;
652 break;
2c308875 653
0b542a94 654 case 'V':
2c308875 655 print_version(EXIT_SUCCESS);
0b542a94 656 case 'h':
5aaa966d 657 usage();
0b542a94 658 default:
5aaa966d
RM
659 warnx(_("bad usage"));
660 errtryhelp(EXIT_FAILURE);
0b542a94 661 }
3635f53c 662
6e834d67 663 if (arg_i < i) /* moved to the next argv[] item */
3635f53c 664 break;
4ff826f6 665 }
9db54a7e 666 }
f51be859 667
9db54a7e 668 free_dirlist(&ls, ALL_DIRS);
a3d29ee0
SK
669 if (opt_f_missing)
670 errx(EXIT_FAILURE, _("option -f is missing"));
0b542a94 671 return EXIT_SUCCESS;
6dbe3af9 672}