| 1 | /* Copyright (C) 1987-2005 Free Software Foundation, Inc.
|
|---|
| 2 |
|
|---|
| 3 | This file is part of GNU Bash, the Bourne Again SHell.
|
|---|
| 4 |
|
|---|
| 5 | Bash is free software; you can redistribute it and/or modify it under
|
|---|
| 6 | the terms of the GNU General Public License as published by the Free
|
|---|
| 7 | Software Foundation; either version 2, or (at your option) any later
|
|---|
| 8 | version.
|
|---|
| 9 |
|
|---|
| 10 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
|---|
| 11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|---|
| 12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|---|
| 13 | for more details.
|
|---|
| 14 |
|
|---|
| 15 | You should have received a copy of the GNU General Public License along
|
|---|
| 16 | with Bash; see the file COPYING. If not, write to the Free Software
|
|---|
| 17 | Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
|---|
| 18 |
|
|---|
| 19 | #include <config.h>
|
|---|
| 20 |
|
|---|
| 21 | #if defined (HAVE_UNISTD_H)
|
|---|
| 22 | # ifdef _MINIX
|
|---|
| 23 | # include <sys/types.h>
|
|---|
| 24 | # endif
|
|---|
| 25 | # include <unistd.h>
|
|---|
| 26 | #endif
|
|---|
| 27 |
|
|---|
| 28 | #include <stdio.h>
|
|---|
| 29 | #include <chartypes.h>
|
|---|
| 30 | #include "../bashtypes.h"
|
|---|
| 31 | #include "posixstat.h"
|
|---|
| 32 | #include <signal.h>
|
|---|
| 33 |
|
|---|
| 34 | #include <errno.h>
|
|---|
| 35 |
|
|---|
| 36 | #if defined (PREFER_STDARG)
|
|---|
| 37 | # include <stdarg.h>
|
|---|
| 38 | #else
|
|---|
| 39 | # include <varargs.h>
|
|---|
| 40 | #endif
|
|---|
| 41 |
|
|---|
| 42 | #include "../bashansi.h"
|
|---|
| 43 | #include "../bashintl.h"
|
|---|
| 44 |
|
|---|
| 45 | #include "../shell.h"
|
|---|
| 46 | #include "maxpath.h"
|
|---|
| 47 | #include "../flags.h"
|
|---|
| 48 | #include "../jobs.h"
|
|---|
| 49 | #include "../builtins.h"
|
|---|
| 50 | #include "../input.h"
|
|---|
| 51 | #include "../execute_cmd.h"
|
|---|
| 52 | #include "../trap.h"
|
|---|
| 53 | #include "bashgetopt.h"
|
|---|
| 54 | #include "common.h"
|
|---|
| 55 | #include "builtext.h"
|
|---|
| 56 | #include <tilde/tilde.h>
|
|---|
| 57 |
|
|---|
| 58 | #if defined (HISTORY)
|
|---|
| 59 | # include "../bashhist.h"
|
|---|
| 60 | #endif
|
|---|
| 61 |
|
|---|
| 62 | #if !defined (errno)
|
|---|
| 63 | extern int errno;
|
|---|
| 64 | #endif /* !errno */
|
|---|
| 65 |
|
|---|
| 66 | extern int indirection_level, subshell_environment;
|
|---|
| 67 | extern int line_number;
|
|---|
| 68 | extern int last_command_exit_value;
|
|---|
| 69 | extern int running_trap;
|
|---|
| 70 | extern int posixly_correct;
|
|---|
| 71 | extern char *this_command_name, *shell_name;
|
|---|
| 72 | extern char *bash_getcwd_errstr;
|
|---|
| 73 |
|
|---|
| 74 | /* Used by some builtins and the mainline code. */
|
|---|
| 75 | sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
|
|---|
| 76 | sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
|
|---|
| 77 |
|
|---|
| 78 | /* **************************************************************** */
|
|---|
| 79 | /* */
|
|---|
| 80 | /* Error reporting, usage, and option processing */
|
|---|
| 81 | /* */
|
|---|
| 82 | /* **************************************************************** */
|
|---|
| 83 |
|
|---|
| 84 | /* This is a lot like report_error (), but it is for shell builtins
|
|---|
| 85 | instead of shell control structures, and it won't ever exit the
|
|---|
| 86 | shell. */
|
|---|
| 87 | void
|
|---|
| 88 | #if defined (PREFER_STDARG)
|
|---|
| 89 | builtin_error (const char *format, ...)
|
|---|
| 90 | #else
|
|---|
| 91 | builtin_error (format, va_alist)
|
|---|
| 92 | const char *format;
|
|---|
| 93 | va_dcl
|
|---|
| 94 | #endif
|
|---|
| 95 | {
|
|---|
| 96 | va_list args;
|
|---|
| 97 | char *name;
|
|---|
| 98 |
|
|---|
| 99 | name = get_name_for_error ();
|
|---|
| 100 | fprintf (stderr, "%s: ", name);
|
|---|
| 101 |
|
|---|
| 102 | if (interactive_shell == 0)
|
|---|
| 103 | fprintf (stderr, "line %d: ", executing_line_number ());
|
|---|
| 104 |
|
|---|
| 105 | if (this_command_name && *this_command_name)
|
|---|
| 106 | fprintf (stderr, "%s: ", this_command_name);
|
|---|
| 107 |
|
|---|
| 108 | SH_VA_START (args, format);
|
|---|
| 109 |
|
|---|
| 110 | vfprintf (stderr, format, args);
|
|---|
| 111 | va_end (args);
|
|---|
| 112 | fprintf (stderr, "\n");
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | /* Print a usage summary for the currently-executing builtin command. */
|
|---|
| 116 | void
|
|---|
| 117 | builtin_usage ()
|
|---|
| 118 | {
|
|---|
| 119 | if (this_command_name && *this_command_name)
|
|---|
| 120 | fprintf (stderr, "%s: usage: ", this_command_name);
|
|---|
| 121 | fprintf (stderr, "%s\n", current_builtin->short_doc);
|
|---|
| 122 | fflush (stderr);
|
|---|
| 123 | }
|
|---|
| 124 |
|
|---|
| 125 | /* Return if LIST is NULL else barf and jump to top_level. Used by some
|
|---|
| 126 | builtins that do not accept arguments. */
|
|---|
| 127 | void
|
|---|
| 128 | no_args (list)
|
|---|
| 129 | WORD_LIST *list;
|
|---|
| 130 | {
|
|---|
| 131 | if (list)
|
|---|
| 132 | {
|
|---|
| 133 | builtin_error (_("too many arguments"));
|
|---|
| 134 | jump_to_top_level (DISCARD);
|
|---|
| 135 | }
|
|---|
| 136 | }
|
|---|
| 137 |
|
|---|
| 138 | /* Check that no options were given to the currently-executing builtin,
|
|---|
| 139 | and return 0 if there were options. */
|
|---|
| 140 | int
|
|---|
| 141 | no_options (list)
|
|---|
| 142 | WORD_LIST *list;
|
|---|
| 143 | {
|
|---|
| 144 | reset_internal_getopt ();
|
|---|
| 145 | if (internal_getopt (list, "") != -1)
|
|---|
| 146 | {
|
|---|
| 147 | builtin_usage ();
|
|---|
| 148 | return (1);
|
|---|
| 149 | }
|
|---|
| 150 | return (0);
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|
| 153 | void
|
|---|
| 154 | sh_needarg (s)
|
|---|
| 155 | char *s;
|
|---|
| 156 | {
|
|---|
| 157 | builtin_error (_("%s: option requires an argument"), s);
|
|---|
| 158 | }
|
|---|
| 159 |
|
|---|
| 160 | void
|
|---|
| 161 | sh_neednumarg (s)
|
|---|
| 162 | char *s;
|
|---|
| 163 | {
|
|---|
| 164 | builtin_error (_("%s: numeric argument required"), s);
|
|---|
| 165 | }
|
|---|
| 166 |
|
|---|
| 167 | void
|
|---|
| 168 | sh_notfound (s)
|
|---|
| 169 | char *s;
|
|---|
| 170 | {
|
|---|
| 171 | builtin_error (_("%s: not found"), s);
|
|---|
| 172 | }
|
|---|
| 173 |
|
|---|
| 174 | /* Function called when one of the builtin commands detects an invalid
|
|---|
| 175 | option. */
|
|---|
| 176 | void
|
|---|
| 177 | sh_invalidopt (s)
|
|---|
| 178 | char *s;
|
|---|
| 179 | {
|
|---|
| 180 | builtin_error (_("%s: invalid option"), s);
|
|---|
| 181 | }
|
|---|
| 182 |
|
|---|
| 183 | void
|
|---|
| 184 | sh_invalidoptname (s)
|
|---|
| 185 | char *s;
|
|---|
| 186 | {
|
|---|
| 187 | builtin_error (_("%s: invalid option name"), s);
|
|---|
| 188 | }
|
|---|
| 189 |
|
|---|
| 190 | void
|
|---|
| 191 | sh_invalidid (s)
|
|---|
| 192 | char *s;
|
|---|
| 193 | {
|
|---|
| 194 | builtin_error (_("`%s': not a valid identifier"), s);
|
|---|
| 195 | }
|
|---|
| 196 |
|
|---|
| 197 | void
|
|---|
| 198 | sh_invalidnum (s)
|
|---|
| 199 | char *s;
|
|---|
| 200 | {
|
|---|
| 201 | builtin_error (_("%s: invalid number"), s);
|
|---|
| 202 | }
|
|---|
| 203 |
|
|---|
| 204 | void
|
|---|
| 205 | sh_invalidsig (s)
|
|---|
| 206 | char *s;
|
|---|
| 207 | {
|
|---|
| 208 | builtin_error (_("%s: invalid signal specification"), s);
|
|---|
| 209 | }
|
|---|
| 210 |
|
|---|
| 211 | void
|
|---|
| 212 | sh_badpid (s)
|
|---|
| 213 | char *s;
|
|---|
| 214 | {
|
|---|
| 215 | builtin_error (_("`%s': not a pid or valid job spec"), s);
|
|---|
| 216 | }
|
|---|
| 217 |
|
|---|
| 218 | void
|
|---|
| 219 | sh_readonly (s)
|
|---|
| 220 | const char *s;
|
|---|
| 221 | {
|
|---|
| 222 | builtin_error (_("%s: readonly variable"), s);
|
|---|
| 223 | }
|
|---|
| 224 |
|
|---|
| 225 | void
|
|---|
| 226 | sh_erange (s, desc)
|
|---|
| 227 | char *s, *desc;
|
|---|
| 228 | {
|
|---|
| 229 | if (s)
|
|---|
| 230 | builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument"));
|
|---|
| 231 | else
|
|---|
| 232 | builtin_error (_("%s out of range"), desc ? desc : _("argument"));
|
|---|
| 233 | }
|
|---|
| 234 |
|
|---|
| 235 | #if defined (JOB_CONTROL)
|
|---|
| 236 | void
|
|---|
| 237 | sh_badjob (s)
|
|---|
| 238 | char *s;
|
|---|
| 239 | {
|
|---|
| 240 | builtin_error (_("%s: no such job"), s);
|
|---|
| 241 | }
|
|---|
| 242 |
|
|---|
| 243 | void
|
|---|
| 244 | sh_nojobs (s)
|
|---|
| 245 | char *s;
|
|---|
| 246 | {
|
|---|
| 247 | if (s)
|
|---|
| 248 | builtin_error (_("%s: no job control"), s);
|
|---|
| 249 | else
|
|---|
| 250 | builtin_error (_("no job control"));
|
|---|
| 251 | }
|
|---|
| 252 | #endif
|
|---|
| 253 |
|
|---|
| 254 | #if defined (RESTRICTED_SHELL)
|
|---|
| 255 | void
|
|---|
| 256 | sh_restricted (s)
|
|---|
| 257 | char *s;
|
|---|
| 258 | {
|
|---|
| 259 | if (s)
|
|---|
| 260 | builtin_error (_("%s: restricted"), s);
|
|---|
| 261 | else
|
|---|
| 262 | builtin_error (_("restricted"));
|
|---|
| 263 | }
|
|---|
| 264 | #endif
|
|---|
| 265 |
|
|---|
| 266 | void
|
|---|
| 267 | sh_notbuiltin (s)
|
|---|
| 268 | char *s;
|
|---|
| 269 | {
|
|---|
| 270 | builtin_error (_("%s: not a shell builtin"), s);
|
|---|
| 271 | }
|
|---|
| 272 |
|
|---|
| 273 | void
|
|---|
| 274 | sh_wrerror ()
|
|---|
| 275 | {
|
|---|
| 276 | builtin_error (_("write error: %s"), strerror (errno));
|
|---|
| 277 | }
|
|---|
| 278 |
|
|---|
| 279 | /* **************************************************************** */
|
|---|
| 280 | /* */
|
|---|
| 281 | /* Shell positional parameter manipulation */
|
|---|
| 282 | /* */
|
|---|
| 283 | /* **************************************************************** */
|
|---|
| 284 |
|
|---|
| 285 | /* Convert a WORD_LIST into a C-style argv. Return the number of elements
|
|---|
| 286 | in the list in *IP, if IP is non-null. A convenience function for
|
|---|
| 287 | loadable builtins; also used by `test'. */
|
|---|
| 288 | char **
|
|---|
| 289 | make_builtin_argv (list, ip)
|
|---|
| 290 | WORD_LIST *list;
|
|---|
| 291 | int *ip;
|
|---|
| 292 | {
|
|---|
| 293 | char **argv;
|
|---|
| 294 |
|
|---|
| 295 | argv = strvec_from_word_list (list, 0, 1, ip);
|
|---|
| 296 | argv[0] = this_command_name;
|
|---|
| 297 | return argv;
|
|---|
| 298 | }
|
|---|
| 299 |
|
|---|
| 300 | /* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
|
|---|
| 301 | non-zero, then discard whatever the existing arguments are, else
|
|---|
| 302 | only discard the ones that are to be replaced. */
|
|---|
| 303 | void
|
|---|
| 304 | remember_args (list, destructive)
|
|---|
| 305 | WORD_LIST *list;
|
|---|
| 306 | int destructive;
|
|---|
| 307 | {
|
|---|
| 308 | register int i;
|
|---|
| 309 |
|
|---|
| 310 | for (i = 1; i < 10; i++)
|
|---|
| 311 | {
|
|---|
| 312 | if ((destructive || list) && dollar_vars[i])
|
|---|
| 313 | {
|
|---|
| 314 | free (dollar_vars[i]);
|
|---|
| 315 | dollar_vars[i] = (char *)NULL;
|
|---|
| 316 | }
|
|---|
| 317 |
|
|---|
| 318 | if (list)
|
|---|
| 319 | {
|
|---|
| 320 | dollar_vars[i] = savestring (list->word->word);
|
|---|
| 321 | list = list->next;
|
|---|
| 322 | }
|
|---|
| 323 | }
|
|---|
| 324 |
|
|---|
| 325 | /* If arguments remain, assign them to REST_OF_ARGS.
|
|---|
| 326 | Note that copy_word_list (NULL) returns NULL, and
|
|---|
| 327 | that dispose_words (NULL) does nothing. */
|
|---|
| 328 | if (destructive || list)
|
|---|
| 329 | {
|
|---|
| 330 | dispose_words (rest_of_args);
|
|---|
| 331 | rest_of_args = copy_word_list (list);
|
|---|
| 332 | }
|
|---|
| 333 |
|
|---|
| 334 | if (destructive)
|
|---|
| 335 | set_dollar_vars_changed ();
|
|---|
| 336 | }
|
|---|
| 337 |
|
|---|
| 338 | static int changed_dollar_vars;
|
|---|
| 339 |
|
|---|
| 340 | /* Have the dollar variables been reset to new values since we last
|
|---|
| 341 | checked? */
|
|---|
| 342 | int
|
|---|
| 343 | dollar_vars_changed ()
|
|---|
| 344 | {
|
|---|
| 345 | return (changed_dollar_vars);
|
|---|
| 346 | }
|
|---|
| 347 |
|
|---|
| 348 | void
|
|---|
| 349 | set_dollar_vars_unchanged ()
|
|---|
| 350 | {
|
|---|
| 351 | changed_dollar_vars = 0;
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | void
|
|---|
| 355 | set_dollar_vars_changed ()
|
|---|
| 356 | {
|
|---|
| 357 | if (variable_context)
|
|---|
| 358 | changed_dollar_vars |= ARGS_FUNC;
|
|---|
| 359 | else if (this_shell_builtin == set_builtin)
|
|---|
| 360 | changed_dollar_vars |= ARGS_SETBLTIN;
|
|---|
| 361 | else
|
|---|
| 362 | changed_dollar_vars |= ARGS_INVOC;
|
|---|
| 363 | }
|
|---|
| 364 |
|
|---|
| 365 | /* **************************************************************** */
|
|---|
| 366 | /* */
|
|---|
| 367 | /* Validating numeric input and arguments */
|
|---|
| 368 | /* */
|
|---|
| 369 | /* **************************************************************** */
|
|---|
| 370 |
|
|---|
| 371 | /* Read a numeric arg for this_command_name, the name of the shell builtin
|
|---|
| 372 | that wants it. LIST is the word list that the arg is to come from.
|
|---|
| 373 | Accept only the numeric argument; report an error if other arguments
|
|---|
| 374 | follow. If FATAL is true, call throw_to_top_level, which exits the
|
|---|
| 375 | shell; if not, call jump_to_top_level (DISCARD), which aborts the
|
|---|
| 376 | current command. */
|
|---|
| 377 | intmax_t
|
|---|
| 378 | get_numeric_arg (list, fatal)
|
|---|
| 379 | WORD_LIST *list;
|
|---|
| 380 | int fatal;
|
|---|
| 381 | {
|
|---|
| 382 | intmax_t count = 1;
|
|---|
| 383 |
|
|---|
| 384 | if (list && list->word && ISOPTION (list->word->word, '-'))
|
|---|
| 385 | list = list->next;
|
|---|
| 386 |
|
|---|
| 387 | if (list)
|
|---|
| 388 | {
|
|---|
| 389 | register char *arg;
|
|---|
| 390 |
|
|---|
| 391 | arg = list->word->word;
|
|---|
| 392 | if (arg == 0 || (legal_number (arg, &count) == 0))
|
|---|
| 393 | {
|
|---|
| 394 | sh_neednumarg (list->word->word);
|
|---|
| 395 | if (fatal)
|
|---|
| 396 | throw_to_top_level ();
|
|---|
| 397 | else
|
|---|
| 398 | jump_to_top_level (DISCARD);
|
|---|
| 399 | }
|
|---|
| 400 | no_args (list->next);
|
|---|
| 401 | }
|
|---|
| 402 |
|
|---|
| 403 | return (count);
|
|---|
| 404 | }
|
|---|
| 405 |
|
|---|
| 406 | /* Get an eight-bit status value from LIST */
|
|---|
| 407 | int
|
|---|
| 408 | get_exitstat (list)
|
|---|
| 409 | WORD_LIST *list;
|
|---|
| 410 | {
|
|---|
| 411 | int status;
|
|---|
| 412 | intmax_t sval;
|
|---|
| 413 | char *arg;
|
|---|
| 414 |
|
|---|
| 415 | if (list && list->word && ISOPTION (list->word->word, '-'))
|
|---|
| 416 | list = list->next;
|
|---|
| 417 |
|
|---|
| 418 | if (list == 0)
|
|---|
| 419 | return (last_command_exit_value);
|
|---|
| 420 |
|
|---|
| 421 | arg = list->word->word;
|
|---|
| 422 | if (arg == 0 || legal_number (arg, &sval) == 0)
|
|---|
| 423 | {
|
|---|
| 424 | sh_neednumarg (list->word->word ? list->word->word : "`'");
|
|---|
| 425 | return 255;
|
|---|
| 426 | }
|
|---|
| 427 | no_args (list->next);
|
|---|
| 428 |
|
|---|
| 429 | status = sval & 255;
|
|---|
| 430 | return status;
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 | /* Return the octal number parsed from STRING, or -1 to indicate
|
|---|
| 434 | that the string contained a bad number. */
|
|---|
| 435 | int
|
|---|
| 436 | read_octal (string)
|
|---|
| 437 | char *string;
|
|---|
| 438 | {
|
|---|
| 439 | int result, digits;
|
|---|
| 440 |
|
|---|
| 441 | result = digits = 0;
|
|---|
| 442 | while (*string && ISOCTAL (*string))
|
|---|
| 443 | {
|
|---|
| 444 | digits++;
|
|---|
| 445 | result = (result * 8) + (*string++ - '0');
|
|---|
| 446 | if (result > 0777)
|
|---|
| 447 | return -1;
|
|---|
| 448 | }
|
|---|
| 449 |
|
|---|
| 450 | if (digits == 0 || *string)
|
|---|
| 451 | result = -1;
|
|---|
| 452 |
|
|---|
| 453 | return (result);
|
|---|
| 454 | }
|
|---|
| 455 |
|
|---|
| 456 | /* **************************************************************** */
|
|---|
| 457 | /* */
|
|---|
| 458 | /* Manipulating the current working directory */
|
|---|
| 459 | /* */
|
|---|
| 460 | /* **************************************************************** */
|
|---|
| 461 |
|
|---|
| 462 | /* Return a consed string which is the current working directory.
|
|---|
| 463 | FOR_WHOM is the name of the caller for error printing. */
|
|---|
| 464 | char *the_current_working_directory = (char *)NULL;
|
|---|
| 465 |
|
|---|
| 466 | char *
|
|---|
| 467 | get_working_directory (for_whom)
|
|---|
| 468 | char *for_whom;
|
|---|
| 469 | {
|
|---|
| 470 | char *directory;
|
|---|
| 471 | size_t dsize;
|
|---|
| 472 |
|
|---|
| 473 | if (no_symbolic_links)
|
|---|
| 474 | {
|
|---|
| 475 | FREE (the_current_working_directory);
|
|---|
| 476 | the_current_working_directory = (char *)NULL;
|
|---|
| 477 | }
|
|---|
| 478 |
|
|---|
| 479 | if (the_current_working_directory == 0)
|
|---|
| 480 | {
|
|---|
| 481 | the_current_working_directory = getcwd (0, 0);
|
|---|
| 482 | if (the_current_working_directory == 0)
|
|---|
| 483 | {
|
|---|
| 484 | fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
|
|---|
| 485 | (for_whom && *for_whom) ? for_whom : get_name_for_error (),
|
|---|
| 486 | _(bash_getcwd_errstr), strerror (errno));
|
|---|
| 487 | return (char *)NULL;
|
|---|
| 488 | }
|
|---|
| 489 | }
|
|---|
| 490 |
|
|---|
| 491 | return (savestring (the_current_working_directory));
|
|---|
| 492 | }
|
|---|
| 493 |
|
|---|
| 494 | /* Make NAME our internal idea of the current working directory. */
|
|---|
| 495 | void
|
|---|
| 496 | set_working_directory (name)
|
|---|
| 497 | char *name;
|
|---|
| 498 | {
|
|---|
| 499 | FREE (the_current_working_directory);
|
|---|
| 500 | the_current_working_directory = savestring (name);
|
|---|
| 501 | }
|
|---|
| 502 |
|
|---|
| 503 | /* **************************************************************** */
|
|---|
| 504 | /* */
|
|---|
| 505 | /* Job control support functions */
|
|---|
| 506 | /* */
|
|---|
| 507 | /* **************************************************************** */
|
|---|
| 508 |
|
|---|
| 509 | #if defined (JOB_CONTROL)
|
|---|
| 510 | int
|
|---|
| 511 | get_job_by_name (name, flags)
|
|---|
| 512 | const char *name;
|
|---|
| 513 | int flags;
|
|---|
| 514 | {
|
|---|
| 515 | register int i, wl, cl, match, job;
|
|---|
| 516 | register PROCESS *p;
|
|---|
| 517 | register JOB *j;
|
|---|
| 518 |
|
|---|
| 519 | job = NO_JOB;
|
|---|
| 520 | wl = strlen (name);
|
|---|
| 521 | for (i = js.j_jobslots - 1; i >= 0; i--)
|
|---|
| 522 | {
|
|---|
| 523 | j = get_job_by_jid (i);
|
|---|
| 524 | if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
|
|---|
| 525 | continue;
|
|---|
| 526 |
|
|---|
| 527 | p = j->pipe;
|
|---|
| 528 | do
|
|---|
| 529 | {
|
|---|
| 530 | if (flags & JM_EXACT)
|
|---|
| 531 | {
|
|---|
| 532 | cl = strlen (p->command);
|
|---|
| 533 | match = STREQN (p->command, name, cl);
|
|---|
| 534 | }
|
|---|
| 535 | else if (flags & JM_SUBSTRING)
|
|---|
| 536 | match = strindex (p->command, name) != (char *)0;
|
|---|
| 537 | else
|
|---|
| 538 | match = STREQN (p->command, name, wl);
|
|---|
| 539 |
|
|---|
| 540 | if (match == 0)
|
|---|
| 541 | {
|
|---|
| 542 | p = p->next;
|
|---|
| 543 | continue;
|
|---|
| 544 | }
|
|---|
| 545 | else if (flags & JM_FIRSTMATCH)
|
|---|
| 546 | return i; /* return first match */
|
|---|
| 547 | else if (job != NO_JOB)
|
|---|
| 548 | {
|
|---|
| 549 | if (this_shell_builtin)
|
|---|
| 550 | builtin_error (_("%s: ambiguous job spec"), name);
|
|---|
| 551 | else
|
|---|
| 552 | report_error (_("%s: ambiguous job spec"), name);
|
|---|
| 553 | return (DUP_JOB);
|
|---|
| 554 | }
|
|---|
| 555 | else
|
|---|
| 556 | job = i;
|
|---|
| 557 | }
|
|---|
| 558 | while (p != j->pipe);
|
|---|
| 559 | }
|
|---|
| 560 |
|
|---|
| 561 | return (job);
|
|---|
| 562 | }
|
|---|
| 563 |
|
|---|
| 564 | /* Return the job spec found in LIST. */
|
|---|
| 565 | int
|
|---|
| 566 | get_job_spec (list)
|
|---|
| 567 | WORD_LIST *list;
|
|---|
| 568 | {
|
|---|
| 569 | register char *word;
|
|---|
| 570 | int job, jflags;
|
|---|
| 571 |
|
|---|
| 572 | if (list == 0)
|
|---|
| 573 | return (js.j_current);
|
|---|
| 574 |
|
|---|
| 575 | word = list->word->word;
|
|---|
| 576 |
|
|---|
| 577 | if (*word == '\0')
|
|---|
| 578 | return (NO_JOB);
|
|---|
| 579 |
|
|---|
| 580 | if (*word == '%')
|
|---|
| 581 | word++;
|
|---|
| 582 |
|
|---|
| 583 | if (DIGIT (*word) && all_digits (word))
|
|---|
| 584 | {
|
|---|
| 585 | job = atoi (word);
|
|---|
| 586 | return (job > js.j_jobslots ? NO_JOB : job - 1);
|
|---|
| 587 | }
|
|---|
| 588 |
|
|---|
| 589 | jflags = 0;
|
|---|
| 590 | switch (*word)
|
|---|
| 591 | {
|
|---|
| 592 | case 0:
|
|---|
| 593 | case '%':
|
|---|
| 594 | case '+':
|
|---|
| 595 | return (js.j_current);
|
|---|
| 596 |
|
|---|
| 597 | case '-':
|
|---|
| 598 | return (js.j_previous);
|
|---|
| 599 |
|
|---|
| 600 | case '?': /* Substring search requested. */
|
|---|
| 601 | jflags |= JM_SUBSTRING;
|
|---|
| 602 | word++;
|
|---|
| 603 | /* FALLTHROUGH */
|
|---|
| 604 |
|
|---|
| 605 | default:
|
|---|
| 606 | return get_job_by_name (word, jflags);
|
|---|
| 607 | }
|
|---|
| 608 | }
|
|---|
| 609 | #endif /* JOB_CONTROL */
|
|---|
| 610 |
|
|---|
| 611 | /*
|
|---|
| 612 | * NOTE: `kill' calls this function with forcecols == 0
|
|---|
| 613 | */
|
|---|
| 614 | int
|
|---|
| 615 | display_signal_list (list, forcecols)
|
|---|
| 616 | WORD_LIST *list;
|
|---|
| 617 | int forcecols;
|
|---|
| 618 | {
|
|---|
| 619 | register int i, column;
|
|---|
| 620 | char *name;
|
|---|
| 621 | int result, signum, dflags;
|
|---|
| 622 | intmax_t lsignum;
|
|---|
| 623 |
|
|---|
| 624 | result = EXECUTION_SUCCESS;
|
|---|
| 625 | if (!list)
|
|---|
| 626 | {
|
|---|
| 627 | for (i = 1, column = 0; i < NSIG; i++)
|
|---|
| 628 | {
|
|---|
| 629 | name = signal_name (i);
|
|---|
| 630 | if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
|
|---|
| 631 | continue;
|
|---|
| 632 |
|
|---|
| 633 | if (posixly_correct && !forcecols)
|
|---|
| 634 | {
|
|---|
| 635 | /* This is for the kill builtin. POSIX.2 says the signal names
|
|---|
| 636 | are displayed without the `SIG' prefix. */
|
|---|
| 637 | if (STREQN (name, "SIG", 3))
|
|---|
| 638 | name += 3;
|
|---|
| 639 | printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
|
|---|
| 640 | }
|
|---|
| 641 | else
|
|---|
| 642 | {
|
|---|
| 643 | printf ("%2d) %s", i, name);
|
|---|
| 644 |
|
|---|
| 645 | if (++column < 4)
|
|---|
| 646 | printf ("\t");
|
|---|
| 647 | else
|
|---|
| 648 | {
|
|---|
| 649 | printf ("\n");
|
|---|
| 650 | column = 0;
|
|---|
| 651 | }
|
|---|
| 652 | }
|
|---|
| 653 | }
|
|---|
| 654 |
|
|---|
| 655 | if ((posixly_correct && !forcecols) || column != 0)
|
|---|
| 656 | printf ("\n");
|
|---|
| 657 | return result;
|
|---|
| 658 | }
|
|---|
| 659 |
|
|---|
| 660 | /* List individual signal names or numbers. */
|
|---|
| 661 | while (list)
|
|---|
| 662 | {
|
|---|
| 663 | if (legal_number (list->word->word, &lsignum))
|
|---|
| 664 | {
|
|---|
| 665 | /* This is specified by Posix.2 so that exit statuses can be
|
|---|
| 666 | mapped into signal numbers. */
|
|---|
| 667 | if (lsignum > 128)
|
|---|
| 668 | lsignum -= 128;
|
|---|
| 669 | if (lsignum < 0 || lsignum >= NSIG)
|
|---|
| 670 | {
|
|---|
| 671 | sh_invalidsig (list->word->word);
|
|---|
| 672 | result = EXECUTION_FAILURE;
|
|---|
| 673 | list = list->next;
|
|---|
| 674 | continue;
|
|---|
| 675 | }
|
|---|
| 676 |
|
|---|
| 677 | signum = lsignum;
|
|---|
| 678 | name = signal_name (signum);
|
|---|
| 679 | if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
|
|---|
| 680 | {
|
|---|
| 681 | list = list->next;
|
|---|
| 682 | continue;
|
|---|
| 683 | }
|
|---|
| 684 | #if defined (JOB_CONTROL)
|
|---|
| 685 | /* POSIX.2 says that `kill -l signum' prints the signal name without
|
|---|
| 686 | the `SIG' prefix. */
|
|---|
| 687 | printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
|
|---|
| 688 | #else
|
|---|
| 689 | printf ("%s\n", name);
|
|---|
| 690 | #endif
|
|---|
| 691 | }
|
|---|
| 692 | else
|
|---|
| 693 | {
|
|---|
| 694 | dflags = DSIG_NOCASE;
|
|---|
| 695 | if (posixly_correct == 0 || this_shell_builtin != kill_builtin)
|
|---|
| 696 | dflags |= DSIG_SIGPREFIX;
|
|---|
| 697 | signum = decode_signal (list->word->word, dflags);
|
|---|
| 698 | if (signum == NO_SIG)
|
|---|
| 699 | {
|
|---|
| 700 | sh_invalidsig (list->word->word);
|
|---|
| 701 | result = EXECUTION_FAILURE;
|
|---|
| 702 | list = list->next;
|
|---|
| 703 | continue;
|
|---|
| 704 | }
|
|---|
| 705 | printf ("%d\n", signum);
|
|---|
| 706 | }
|
|---|
| 707 | list = list->next;
|
|---|
| 708 | }
|
|---|
| 709 | return (result);
|
|---|
| 710 | }
|
|---|
| 711 |
|
|---|
| 712 | /* **************************************************************** */
|
|---|
| 713 | /* */
|
|---|
| 714 | /* Finding builtin commands and their functions */
|
|---|
| 715 | /* */
|
|---|
| 716 | /* **************************************************************** */
|
|---|
| 717 |
|
|---|
| 718 | /* Perform a binary search and return the address of the builtin function
|
|---|
| 719 | whose name is NAME. If the function couldn't be found, or the builtin
|
|---|
| 720 | is disabled or has no function associated with it, return NULL.
|
|---|
| 721 | Return the address of the builtin.
|
|---|
| 722 | DISABLED_OKAY means find it even if the builtin is disabled. */
|
|---|
| 723 | struct builtin *
|
|---|
| 724 | builtin_address_internal (name, disabled_okay)
|
|---|
| 725 | char *name;
|
|---|
| 726 | int disabled_okay;
|
|---|
| 727 | {
|
|---|
| 728 | int hi, lo, mid, j;
|
|---|
| 729 |
|
|---|
| 730 | hi = num_shell_builtins - 1;
|
|---|
| 731 | lo = 0;
|
|---|
| 732 |
|
|---|
| 733 | while (lo <= hi)
|
|---|
| 734 | {
|
|---|
| 735 | mid = (lo + hi) / 2;
|
|---|
| 736 |
|
|---|
| 737 | j = shell_builtins[mid].name[0] - name[0];
|
|---|
| 738 |
|
|---|
| 739 | if (j == 0)
|
|---|
| 740 | j = strcmp (shell_builtins[mid].name, name);
|
|---|
| 741 |
|
|---|
| 742 | if (j == 0)
|
|---|
| 743 | {
|
|---|
| 744 | /* It must have a function pointer. It must be enabled, or we
|
|---|
| 745 | must have explicitly allowed disabled functions to be found,
|
|---|
| 746 | and it must not have been deleted. */
|
|---|
| 747 | if (shell_builtins[mid].function &&
|
|---|
| 748 | ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
|
|---|
| 749 | ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
|
|---|
| 750 | return (&shell_builtins[mid]);
|
|---|
| 751 | else
|
|---|
| 752 | return ((struct builtin *)NULL);
|
|---|
| 753 | }
|
|---|
| 754 | if (j > 0)
|
|---|
| 755 | hi = mid - 1;
|
|---|
| 756 | else
|
|---|
| 757 | lo = mid + 1;
|
|---|
| 758 | }
|
|---|
| 759 | return ((struct builtin *)NULL);
|
|---|
| 760 | }
|
|---|
| 761 |
|
|---|
| 762 | /* Return the pointer to the function implementing builtin command NAME. */
|
|---|
| 763 | sh_builtin_func_t *
|
|---|
| 764 | find_shell_builtin (name)
|
|---|
| 765 | char *name;
|
|---|
| 766 | {
|
|---|
| 767 | current_builtin = builtin_address_internal (name, 0);
|
|---|
| 768 | return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
|
|---|
| 769 | }
|
|---|
| 770 |
|
|---|
| 771 | /* Return the address of builtin with NAME, whether it is enabled or not. */
|
|---|
| 772 | sh_builtin_func_t *
|
|---|
| 773 | builtin_address (name)
|
|---|
| 774 | char *name;
|
|---|
| 775 | {
|
|---|
| 776 | current_builtin = builtin_address_internal (name, 1);
|
|---|
| 777 | return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
|
|---|
| 778 | }
|
|---|
| 779 |
|
|---|
| 780 | /* Return the function implementing the builtin NAME, but only if it is a
|
|---|
| 781 | POSIX.2 special builtin. */
|
|---|
| 782 | sh_builtin_func_t *
|
|---|
| 783 | find_special_builtin (name)
|
|---|
| 784 | char *name;
|
|---|
| 785 | {
|
|---|
| 786 | current_builtin = builtin_address_internal (name, 0);
|
|---|
| 787 | return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
|
|---|
| 788 | current_builtin->function :
|
|---|
| 789 | (sh_builtin_func_t *)NULL);
|
|---|
| 790 | }
|
|---|
| 791 |
|
|---|
| 792 | static int
|
|---|
| 793 | shell_builtin_compare (sbp1, sbp2)
|
|---|
| 794 | struct builtin *sbp1, *sbp2;
|
|---|
| 795 | {
|
|---|
| 796 | int result;
|
|---|
| 797 |
|
|---|
| 798 | if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
|
|---|
| 799 | result = strcmp (sbp1->name, sbp2->name);
|
|---|
| 800 |
|
|---|
| 801 | return (result);
|
|---|
| 802 | }
|
|---|
| 803 |
|
|---|
| 804 | /* Sort the table of shell builtins so that the binary search will work
|
|---|
| 805 | in find_shell_builtin. */
|
|---|
| 806 | void
|
|---|
| 807 | initialize_shell_builtins ()
|
|---|
| 808 | {
|
|---|
| 809 | qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
|
|---|
| 810 | (QSFUNC *)shell_builtin_compare);
|
|---|
| 811 | }
|
|---|