]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is type.def, from which is created type.c. |
2 | It implements the builtin "type" in Bash. | |
3 | ||
ac50fbac | 4 | Copyright (C) 1987-2011 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
3185942a JA |
8 | Bash is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation, either version 3 of the License, or | |
11 | (at your option) any later version. | |
726f6388 | 12 | |
3185942a JA |
13 | Bash is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
726f6388 | 17 | |
3185942a JA |
18 | You should have received a copy of the GNU General Public License |
19 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
726f6388 JA |
20 | |
21 | $PRODUCES type.c | |
22 | ||
23 | $BUILTIN type | |
24 | $FUNCTION type_builtin | |
7117c2d2 | 25 | $SHORT_DOC type [-afptP] name [name ...] |
3185942a JA |
26 | Display information about command type. |
27 | ||
726f6388 JA |
28 | For each NAME, indicate how it would be interpreted if used as a |
29 | command name. | |
30 | ||
3185942a JA |
31 | Options: |
32 | -a display all locations containing an executable named NAME; | |
33 | includes aliases, builtins, and functions, if and only if | |
34 | the `-p' option is not also used | |
35 | -f suppress shell function lookup | |
36 | -P force a PATH search for each NAME, even if it is an alias, | |
37 | builtin, or function, and returns the name of the disk file | |
38 | that would be executed | |
39 | -p returns either the name of the disk file that would be executed, | |
40 | or nothing if `type -t NAME' would not return `file'. | |
41 | -t output a single word which is one of `alias', `keyword', | |
42 | `function', `builtin', `file' or `', if NAME is an alias, shell | |
43 | reserved word, shell function, shell builtin, disk file, or not | |
44 | found, respectively | |
45 | ||
46 | Arguments: | |
47 | NAME Command name to be interpreted. | |
48 | ||
49 | Exit Status: | |
50 | Returns success if all of the NAMEs are found; fails if any are not found. | |
726f6388 JA |
51 | $END |
52 | ||
ccc6cda3 JA |
53 | #include <config.h> |
54 | ||
55 | #include "../bashtypes.h" | |
bb70624e | 56 | #include "posixstat.h" |
ccc6cda3 JA |
57 | |
58 | #if defined (HAVE_UNISTD_H) | |
59 | # include <unistd.h> | |
60 | #endif | |
61 | ||
62 | #include <stdio.h> | |
63 | #include "../bashansi.h" | |
b80f6443 | 64 | #include "../bashintl.h" |
ccc6cda3 | 65 | |
726f6388 | 66 | #include "../shell.h" |
cce855bc | 67 | #include "../findcmd.h" |
d166f048 | 68 | #include "../hashcmd.h" |
726f6388 JA |
69 | |
70 | #if defined (ALIAS) | |
71 | #include "../alias.h" | |
72 | #endif /* ALIAS */ | |
73 | ||
74 | #include "common.h" | |
b72432fd | 75 | #include "bashgetopt.h" |
726f6388 | 76 | |
f73dda09 | 77 | extern int find_reserved_word __P((char *)); |
726f6388 | 78 | |
bb70624e | 79 | extern char *this_command_name; |
95732b49 | 80 | extern int expand_aliases, posixly_correct; |
bb70624e | 81 | |
726f6388 JA |
82 | /* For each word in LIST, find out what the shell is going to do with |
83 | it as a simple command. i.e., which file would this shell use to | |
84 | execve, or if it is a builtin command, or an alias. Possible flag | |
85 | arguments: | |
b72432fd | 86 | -t Returns the "type" of the object, one of |
726f6388 JA |
87 | `alias', `keyword', `function', `builtin', |
88 | or `file'. | |
89 | ||
b72432fd | 90 | -p Returns the pathname of the file if -type is |
726f6388 JA |
91 | a file. |
92 | ||
b72432fd | 93 | -a Returns all occurrences of words, whether they |
726f6388 JA |
94 | be a filename in the path, alias, function, |
95 | or builtin. | |
7117c2d2 JA |
96 | |
97 | -f Suppress shell function lookup, like `command'. | |
98 | ||
99 | -P Force a path search even in the presence of other | |
100 | definitions. | |
101 | ||
726f6388 JA |
102 | Order of evaluation: |
103 | alias | |
104 | keyword | |
105 | function | |
106 | builtin | |
107 | file | |
108 | */ | |
b72432fd | 109 | |
ccc6cda3 | 110 | int |
726f6388 JA |
111 | type_builtin (list) |
112 | WORD_LIST *list; | |
113 | { | |
3185942a | 114 | int dflags, any_failed, opt; |
7117c2d2 | 115 | WORD_LIST *this; |
726f6388 | 116 | |
ccc6cda3 JA |
117 | if (list == 0) |
118 | return (EXECUTION_SUCCESS); | |
119 | ||
7117c2d2 | 120 | dflags = CDESC_SHORTDESC; /* default */ |
3185942a | 121 | any_failed = 0; |
726f6388 | 122 | |
b72432fd | 123 | /* Handle the obsolescent `-type', `-path', and `-all' by prescanning |
7117c2d2 JA |
124 | the arguments and converting those options to the form that |
125 | internal_getopt recognizes. Converts `--type', `--path', and `--all' | |
126 | also. THIS SHOULD REALLY GO AWAY. */ | |
127 | for (this = list; this && this->word->word[0] == '-'; this = this->next) | |
726f6388 | 128 | { |
b72432fd | 129 | char *flag = &(this->word->word[1]); |
726f6388 | 130 | |
b72432fd | 131 | if (STREQ (flag, "type") || STREQ (flag, "-type")) |
726f6388 | 132 | { |
7117c2d2 JA |
133 | this->word->word[1] = 't'; |
134 | this->word->word[2] = '\0'; | |
726f6388 | 135 | } |
b72432fd | 136 | else if (STREQ (flag, "path") || STREQ (flag, "-path")) |
726f6388 | 137 | { |
7117c2d2 JA |
138 | this->word->word[1] = 'p'; |
139 | this->word->word[2] = '\0'; | |
726f6388 | 140 | } |
b72432fd | 141 | else if (STREQ (flag, "all") || STREQ (flag, "-all")) |
726f6388 | 142 | { |
7117c2d2 JA |
143 | this->word->word[1] = 'a'; |
144 | this->word->word[2] = '\0'; | |
b72432fd JA |
145 | } |
146 | } | |
147 | ||
148 | reset_internal_getopt (); | |
7117c2d2 | 149 | while ((opt = internal_getopt (list, "afptP")) != -1) |
b72432fd JA |
150 | { |
151 | switch (opt) | |
152 | { | |
7117c2d2 JA |
153 | case 'a': |
154 | dflags |= CDESC_ALL; | |
155 | break; | |
156 | case 'f': | |
157 | dflags |= CDESC_NOFUNCS; | |
b72432fd JA |
158 | break; |
159 | case 'p': | |
7117c2d2 JA |
160 | dflags |= CDESC_PATH_ONLY; |
161 | dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC); | |
b72432fd | 162 | break; |
7117c2d2 JA |
163 | case 't': |
164 | dflags |= CDESC_TYPE; | |
165 | dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC); | |
166 | break; | |
167 | case 'P': /* shorthand for type -ap */ | |
168 | dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH); | |
169 | dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC); | |
b72432fd JA |
170 | break; |
171 | default: | |
ccc6cda3 | 172 | builtin_usage (); |
726f6388 JA |
173 | return (EX_USAGE); |
174 | } | |
726f6388 | 175 | } |
b72432fd | 176 | list = loptend; |
726f6388 | 177 | |
726f6388 JA |
178 | while (list) |
179 | { | |
180 | int found; | |
181 | ||
7117c2d2 | 182 | found = describe_command (list->word->word, dflags); |
726f6388 | 183 | |
7117c2d2 JA |
184 | if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0) |
185 | sh_notfound (list->word->word); | |
726f6388 | 186 | |
3185942a | 187 | any_failed += found == 0; |
726f6388 JA |
188 | list = list->next; |
189 | } | |
190 | ||
3185942a JA |
191 | opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; |
192 | return (sh_chkwrite (opt)); | |
726f6388 JA |
193 | } |
194 | ||
195 | /* | |
7117c2d2 | 196 | * Describe COMMAND as required by the type and command builtins. |
726f6388 | 197 | * |
7117c2d2 JA |
198 | * Behavior is controlled by DFLAGS. Flag values are |
199 | * CDESC_ALL print all descriptions of a command | |
200 | * CDESC_SHORTDESC print the description for type and command -V | |
201 | * CDESC_REUSABLE print in a format that may be reused as input | |
202 | * CDESC_TYPE print the type for type -t | |
203 | * CDESC_PATH_ONLY print the path for type -p | |
204 | * CDESC_FORCE_PATH force a path search for type -P | |
205 | * CDESC_NOFUNCS skip function lookup for type -f | |
95732b49 | 206 | * CDESC_ABSPATH convert to absolute path, no ./ prefix |
726f6388 | 207 | * |
7117c2d2 | 208 | * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or |
726f6388 JA |
209 | * return after finding it once. |
210 | */ | |
ccc6cda3 | 211 | int |
7117c2d2 | 212 | describe_command (command, dflags) |
726f6388 | 213 | char *command; |
7117c2d2 | 214 | int dflags; |
726f6388 | 215 | { |
7117c2d2 | 216 | int found, i, found_file, f, all; |
f73dda09 | 217 | char *full_path, *x; |
726f6388 | 218 | SHELL_VAR *func; |
ccc6cda3 JA |
219 | #if defined (ALIAS) |
220 | alias_t *alias; | |
221 | #endif | |
222 | ||
7117c2d2 | 223 | all = (dflags & CDESC_ALL) != 0; |
ccc6cda3 JA |
224 | found = found_file = 0; |
225 | full_path = (char *)NULL; | |
726f6388 JA |
226 | |
227 | #if defined (ALIAS) | |
228 | /* Command is an alias? */ | |
b80f6443 | 229 | if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command))) |
726f6388 | 230 | { |
7117c2d2 | 231 | if (dflags & CDESC_TYPE) |
ccc6cda3 | 232 | puts ("alias"); |
7117c2d2 | 233 | else if (dflags & CDESC_SHORTDESC) |
b80f6443 | 234 | printf (_("%s is aliased to `%s'\n"), command, alias->value); |
7117c2d2 | 235 | else if (dflags & CDESC_REUSABLE) |
726f6388 | 236 | { |
28ef6c31 | 237 | x = sh_single_quote (alias->value); |
726f6388 JA |
238 | printf ("alias %s=%s\n", command, x); |
239 | free (x); | |
240 | } | |
241 | ||
242 | found = 1; | |
243 | ||
b72432fd | 244 | if (all == 0) |
726f6388 JA |
245 | return (1); |
246 | } | |
247 | #endif /* ALIAS */ | |
248 | ||
249 | /* Command is a shell reserved word? */ | |
7117c2d2 | 250 | if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0) |
726f6388 | 251 | { |
7117c2d2 | 252 | if (dflags & CDESC_TYPE) |
ccc6cda3 | 253 | puts ("keyword"); |
7117c2d2 | 254 | else if (dflags & CDESC_SHORTDESC) |
b80f6443 | 255 | printf (_("%s is a shell keyword\n"), command); |
7117c2d2 | 256 | else if (dflags & CDESC_REUSABLE) |
726f6388 JA |
257 | printf ("%s\n", command); |
258 | ||
259 | found = 1; | |
260 | ||
b72432fd | 261 | if (all == 0) |
726f6388 JA |
262 | return (1); |
263 | } | |
264 | ||
265 | /* Command is a function? */ | |
7117c2d2 | 266 | if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command))) |
726f6388 | 267 | { |
7117c2d2 | 268 | if (dflags & CDESC_TYPE) |
ccc6cda3 | 269 | puts ("function"); |
7117c2d2 | 270 | else if (dflags & CDESC_SHORTDESC) |
726f6388 | 271 | { |
726f6388 JA |
272 | char *result; |
273 | ||
b80f6443 | 274 | printf (_("%s is a function\n"), command); |
726f6388 JA |
275 | |
276 | /* We're blowing away THE_PRINTED_COMMAND here... */ | |
277 | ||
3185942a | 278 | result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL); |
726f6388 | 279 | printf ("%s\n", result); |
726f6388 | 280 | } |
7117c2d2 | 281 | else if (dflags & CDESC_REUSABLE) |
726f6388 JA |
282 | printf ("%s\n", command); |
283 | ||
284 | found = 1; | |
285 | ||
b72432fd | 286 | if (all == 0) |
726f6388 JA |
287 | return (1); |
288 | } | |
289 | ||
290 | /* Command is a builtin? */ | |
7117c2d2 | 291 | if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command)) |
726f6388 | 292 | { |
7117c2d2 | 293 | if (dflags & CDESC_TYPE) |
ccc6cda3 | 294 | puts ("builtin"); |
7117c2d2 | 295 | else if (dflags & CDESC_SHORTDESC) |
b80f6443 | 296 | printf (_("%s is a shell builtin\n"), command); |
7117c2d2 | 297 | else if (dflags & CDESC_REUSABLE) |
726f6388 JA |
298 | printf ("%s\n", command); |
299 | ||
300 | found = 1; | |
301 | ||
b72432fd | 302 | if (all == 0) |
726f6388 JA |
303 | return (1); |
304 | } | |
305 | ||
306 | /* Command is a disk file? */ | |
307 | /* If the command name given is already an absolute command, just | |
308 | check to see if it is executable. */ | |
309 | if (absolute_program (command)) | |
310 | { | |
bb70624e | 311 | f = file_status (command); |
726f6388 | 312 | if (f & FS_EXECABLE) |
28ef6c31 | 313 | { |
7117c2d2 | 314 | if (dflags & CDESC_TYPE) |
ccc6cda3 | 315 | puts ("file"); |
7117c2d2 | 316 | else if (dflags & CDESC_SHORTDESC) |
b80f6443 | 317 | printf (_("%s is %s\n"), command, command); |
7117c2d2 | 318 | else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) |
726f6388 JA |
319 | printf ("%s\n", command); |
320 | ||
321 | /* There's no use looking in the hash table or in $PATH, | |
322 | because they're not consulted when an absolute program | |
323 | name is supplied. */ | |
324 | return (1); | |
28ef6c31 | 325 | } |
726f6388 JA |
326 | } |
327 | ||
b72432fd | 328 | /* If the user isn't doing "-a", then we might care about |
726f6388 | 329 | whether the file is present in our hash table. */ |
7117c2d2 | 330 | if (all == 0 || (dflags & CDESC_FORCE_PATH)) |
726f6388 | 331 | { |
7117c2d2 | 332 | if (full_path = phash_search (command)) |
726f6388 | 333 | { |
7117c2d2 | 334 | if (dflags & CDESC_TYPE) |
ccc6cda3 | 335 | puts ("file"); |
7117c2d2 | 336 | else if (dflags & CDESC_SHORTDESC) |
b80f6443 | 337 | printf (_("%s is hashed (%s)\n"), command, full_path); |
7117c2d2 | 338 | else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) |
726f6388 JA |
339 | printf ("%s\n", full_path); |
340 | ||
d166f048 | 341 | free (full_path); |
726f6388 JA |
342 | return (1); |
343 | } | |
344 | } | |
345 | ||
346 | /* Now search through $PATH. */ | |
347 | while (1) | |
348 | { | |
b72432fd | 349 | if (all == 0) |
726f6388 JA |
350 | full_path = find_user_command (command); |
351 | else | |
352 | full_path = | |
353 | user_command_matches (command, FS_EXEC_ONLY, found_file); | |
354 | /* XXX - should that be FS_EXEC_PREFERRED? */ | |
355 | ||
ac50fbac | 356 | if (full_path == 0) |
726f6388 JA |
357 | break; |
358 | ||
bb70624e JA |
359 | /* If we found the command as itself by looking through $PATH, it |
360 | probably doesn't exist. Check whether or not the command is an | |
95732b49 JA |
361 | executable file. If it's not, don't report a match. This is |
362 | the default posix mode behavior */ | |
363 | if (STREQ (full_path, command) || posixly_correct) | |
bb70624e JA |
364 | { |
365 | f = file_status (full_path); | |
366 | if ((f & FS_EXECABLE) == 0) | |
367 | { | |
368 | free (full_path); | |
369 | full_path = (char *)NULL; | |
370 | if (all == 0) | |
371 | break; | |
372 | } | |
95732b49 JA |
373 | else if (ABSPATH (full_path)) |
374 | ; /* placeholder; don't need to do anything yet */ | |
7117c2d2 | 375 | else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC)) |
95732b49 JA |
376 | { |
377 | f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0); | |
ac50fbac CR |
378 | x = sh_makepath ((char *)NULL, full_path, f); |
379 | free (full_path); | |
380 | full_path = x; | |
95732b49 | 381 | } |
bb70624e | 382 | } |
95732b49 JA |
383 | /* If we require a full path and don't have one, make one */ |
384 | else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0) | |
385 | full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT); | |
bb70624e | 386 | |
726f6388 JA |
387 | found_file++; |
388 | found = 1; | |
389 | ||
7117c2d2 | 390 | if (dflags & CDESC_TYPE) |
ccc6cda3 | 391 | puts ("file"); |
7117c2d2 | 392 | else if (dflags & CDESC_SHORTDESC) |
3185942a | 393 | printf (_("%s is %s\n"), command, full_path); |
7117c2d2 | 394 | else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) |
726f6388 JA |
395 | printf ("%s\n", full_path); |
396 | ||
397 | free (full_path); | |
398 | full_path = (char *)NULL; | |
399 | ||
b72432fd | 400 | if (all == 0) |
726f6388 JA |
401 | break; |
402 | } | |
403 | ||
404 | return (found); | |
405 | } |