1/* type.c, created from type.def. */ 2#line 23 "type.def" 3 4#line 49 "type.def" 5 6#include <config.h> 7 8#include "../bashtypes.h" 9#include "posixstat.h" 10 11#if defined (HAVE_UNISTD_H) 12# include <unistd.h> 13#endif 14 15#include <stdio.h> 16#include "../bashansi.h" 17#include "../bashintl.h" 18 19#include "../shell.h" 20#include "../findcmd.h" 21#include "../hashcmd.h" 22 23#if defined (ALIAS) 24#include "../alias.h" 25#endif /* ALIAS */ 26 27#include "common.h" 28#include "bashgetopt.h" 29 30extern int find_reserved_word __P((char *)); 31 32extern char *this_command_name; 33extern int expand_aliases, posixly_correct; 34 35/* For each word in LIST, find out what the shell is going to do with 36 it as a simple command. i.e., which file would this shell use to 37 execve, or if it is a builtin command, or an alias. Possible flag 38 arguments: 39 -t Returns the "type" of the object, one of 40 `alias', `keyword', `function', `builtin', 41 or `file'. 42 43 -p Returns the pathname of the file if -type is 44 a file. 45 46 -a Returns all occurrences of words, whether they 47 be a filename in the path, alias, function, 48 or builtin. 49 50 -f Suppress shell function lookup, like `command'. 51 52 -P Force a path search even in the presence of other 53 definitions. 54 55 Order of evaluation: 56 alias 57 keyword 58 function 59 builtin 60 file 61 */ 62 63int 64type_builtin (list) 65 WORD_LIST *list; 66{ 67 int dflags, successful_finds, opt; 68 WORD_LIST *this; 69 70 if (list == 0) 71 return (EXECUTION_SUCCESS); 72 73 dflags = CDESC_SHORTDESC; /* default */ 74 successful_finds = 0; 75 76 /* Handle the obsolescent `-type', `-path', and `-all' by prescanning 77 the arguments and converting those options to the form that 78 internal_getopt recognizes. Converts `--type', `--path', and `--all' 79 also. THIS SHOULD REALLY GO AWAY. */ 80 for (this = list; this && this->word->word[0] == '-'; this = this->next) 81 { 82 char *flag = &(this->word->word[1]); 83 84 if (STREQ (flag, "type") || STREQ (flag, "-type")) 85 { 86 this->word->word[1] = 't'; 87 this->word->word[2] = '\0'; 88 } 89 else if (STREQ (flag, "path") || STREQ (flag, "-path")) 90 { 91 this->word->word[1] = 'p'; 92 this->word->word[2] = '\0'; 93 } 94 else if (STREQ (flag, "all") || STREQ (flag, "-all")) 95 { 96 this->word->word[1] = 'a'; 97 this->word->word[2] = '\0'; 98 } 99 } 100 101 reset_internal_getopt (); 102 while ((opt = internal_getopt (list, "afptP")) != -1) 103 { 104 switch (opt) 105 { 106 case 'a': 107 dflags |= CDESC_ALL; 108 break; 109 case 'f': 110 dflags |= CDESC_NOFUNCS; 111 break; 112 case 'p': 113 dflags |= CDESC_PATH_ONLY; 114 dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC); 115 break; 116 case 't': 117 dflags |= CDESC_TYPE; 118 dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC); 119 break; 120 case 'P': /* shorthand for type -ap */ 121 dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH); 122 dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC); 123 break; 124 default: 125 builtin_usage (); 126 return (EX_USAGE); 127 } 128 } 129 list = loptend; 130 131 while (list) 132 { 133 int found; 134 135 found = describe_command (list->word->word, dflags); 136 137 if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0) 138 sh_notfound (list->word->word); 139 140 successful_finds += found; 141 list = list->next; 142 } 143 144 fflush (stdout); 145 146 return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); 147} 148 149/* 150 * Describe COMMAND as required by the type and command builtins. 151 * 152 * Behavior is controlled by DFLAGS. Flag values are 153 * CDESC_ALL print all descriptions of a command 154 * CDESC_SHORTDESC print the description for type and command -V 155 * CDESC_REUSABLE print in a format that may be reused as input 156 * CDESC_TYPE print the type for type -t 157 * CDESC_PATH_ONLY print the path for type -p 158 * CDESC_FORCE_PATH force a path search for type -P 159 * CDESC_NOFUNCS skip function lookup for type -f 160 * CDESC_ABSPATH convert to absolute path, no ./ prefix 161 * 162 * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or 163 * return after finding it once. 164 */ 165int 166describe_command (command, dflags) 167 char *command; 168 int dflags; 169{ 170 int found, i, found_file, f, all; 171 char *full_path, *x; 172 SHELL_VAR *func; 173#if defined (ALIAS) 174 alias_t *alias; 175#endif 176 177 all = (dflags & CDESC_ALL) != 0; 178 found = found_file = 0; 179 full_path = (char *)NULL; 180 181#if defined (ALIAS) 182 /* Command is an alias? */ 183 if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command))) 184 { 185 if (dflags & CDESC_TYPE) 186 puts ("alias"); 187 else if (dflags & CDESC_SHORTDESC) 188 printf (_("%s is aliased to `%s'\n"), command, alias->value); 189 else if (dflags & CDESC_REUSABLE) 190 { 191 x = sh_single_quote (alias->value); 192 printf ("alias %s=%s\n", command, x); 193 free (x); 194 } 195 196 found = 1; 197 198 if (all == 0) 199 return (1); 200 } 201#endif /* ALIAS */ 202 203 /* Command is a shell reserved word? */ 204 if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0) 205 { 206 if (dflags & CDESC_TYPE) 207 puts ("keyword"); 208 else if (dflags & CDESC_SHORTDESC) 209 printf (_("%s is a shell keyword\n"), command); 210 else if (dflags & CDESC_REUSABLE) 211 printf ("%s\n", command); 212 213 found = 1; 214 215 if (all == 0) 216 return (1); 217 } 218 219 /* Command is a function? */ 220 if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command))) 221 { 222 if (dflags & CDESC_TYPE) 223 puts ("function"); 224 else if (dflags & CDESC_SHORTDESC) 225 { 226#define PRETTY_PRINT_FUNC 1 227 char *result; 228 229 printf (_("%s is a function\n"), command); 230 231 /* We're blowing away THE_PRINTED_COMMAND here... */ 232 233 result = named_function_string (command, 234 (COMMAND *) function_cell (func), 235 PRETTY_PRINT_FUNC); 236 printf ("%s\n", result); 237#undef PRETTY_PRINT_FUNC 238 } 239 else if (dflags & CDESC_REUSABLE) 240 printf ("%s\n", command); 241 242 found = 1; 243 244 if (all == 0) 245 return (1); 246 } 247 248 /* Command is a builtin? */ 249 if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command)) 250 { 251 if (dflags & CDESC_TYPE) 252 puts ("builtin"); 253 else if (dflags & CDESC_SHORTDESC) 254 printf (_("%s is a shell builtin\n"), command); 255 else if (dflags & CDESC_REUSABLE) 256 printf ("%s\n", command); 257 258 found = 1; 259 260 if (all == 0) 261 return (1); 262 } 263 264 /* Command is a disk file? */ 265 /* If the command name given is already an absolute command, just 266 check to see if it is executable. */ 267 if (absolute_program (command)) 268 { 269 f = file_status (command); 270 if (f & FS_EXECABLE) 271 { 272 if (dflags & CDESC_TYPE) 273 puts ("file"); 274 else if (dflags & CDESC_SHORTDESC) 275 printf (_("%s is %s\n"), command, command); 276 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) 277 printf ("%s\n", command); 278 279 /* There's no use looking in the hash table or in $PATH, 280 because they're not consulted when an absolute program 281 name is supplied. */ 282 return (1); 283 } 284 } 285 286 /* If the user isn't doing "-a", then we might care about 287 whether the file is present in our hash table. */ 288 if (all == 0 || (dflags & CDESC_FORCE_PATH)) 289 { 290 if (full_path = phash_search (command)) 291 { 292 if (dflags & CDESC_TYPE) 293 puts ("file"); 294 else if (dflags & CDESC_SHORTDESC) 295 printf (_("%s is hashed (%s)\n"), command, full_path); 296 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) 297 printf ("%s\n", full_path); 298 299 free (full_path); 300 return (1); 301 } 302 } 303 304 /* Now search through $PATH. */ 305 while (1) 306 { 307 if (all == 0) 308 full_path = find_user_command (command); 309 else 310 full_path = 311 user_command_matches (command, FS_EXEC_ONLY, found_file); 312 /* XXX - should that be FS_EXEC_PREFERRED? */ 313 314 if (!full_path) 315 break; 316 317 /* If we found the command as itself by looking through $PATH, it 318 probably doesn't exist. Check whether or not the command is an 319 executable file. If it's not, don't report a match. This is 320 the default posix mode behavior */ 321 if (STREQ (full_path, command) || posixly_correct) 322 { 323 f = file_status (full_path); 324 if ((f & FS_EXECABLE) == 0) 325 { 326 free (full_path); 327 full_path = (char *)NULL; 328 if (all == 0) 329 break; 330 } 331 else if (ABSPATH (full_path)) 332 ; /* placeholder; don't need to do anything yet */ 333 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC)) 334 { 335 f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0); 336 full_path = sh_makepath ((char *)NULL, full_path, f); 337 } 338 } 339 /* If we require a full path and don't have one, make one */ 340 else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0) 341 full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT); 342 343 found_file++; 344 found = 1; 345 346 if (dflags & CDESC_TYPE) 347 puts ("file"); 348 else if (dflags & CDESC_SHORTDESC) 349 printf ("%s is %s\n", command, full_path); 350 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) 351 printf ("%s\n", full_path); 352 353 free (full_path); 354 full_path = (char *)NULL; 355 356 if (all == 0) 357 break; 358 } 359 360 return (found); 361} 362