Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/shell/ash.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/shell/ash.c
r3232 r3621 38 38 #define JOBS ENABLE_ASH_JOB_CONTROL 39 39 40 #include <paths.h>41 40 #include <setjmp.h> 42 41 #include <fnmatch.h> 43 42 #include <sys/times.h> 43 #include <sys/utsname.h> /* for setting $HOSTNAME */ 44 44 45 45 #include "busybox.h" /* for applet_names */ … … 143 143 //config: Enable support for test builtin in ash. 144 144 //config: 145 //config:config ASH_HELP 146 //config: bool "help builtin" 147 //config: default y 148 //config: depends on ASH 149 //config: help 150 //config: Enable help builtin in ash. 151 //config: 145 152 //config:config ASH_CMDCMD 146 153 //config: bool "'command' command to override shell builtins" … … 386 393 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) 387 394 395 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 396 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 397 388 398 static int isdigit_str9(const char *str) 389 399 { … … 527 537 } 528 538 539 /* Was called outcslow(c,FILE*), but c was always '\n' */ 529 540 static void 530 outcslow(int c,FILE *dest)541 newline_and_flush(FILE *dest) 531 542 { 532 543 INT_OFF; 533 putc( c, dest);544 putc('\n', dest); 534 545 fflush(dest); 535 546 INT_ON; … … 588 599 #define CTLENDVAR ((unsigned char)'\203') 589 600 #define CTLBACKQ ((unsigned char)'\204') 590 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */591 /* CTLBACKQ | CTLQUOTE == '\205' */592 601 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ 593 602 #define CTLENDARI ((unsigned char)'\207') … … 598 607 #define VSTYPE 0x0f /* type of variable substitution */ 599 608 #define VSNUL 0x10 /* colon--treat the empty string as unset */ 600 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */601 609 602 610 /* values of VSTYPE field */ … … 618 626 619 627 static const char dolatstr[] ALIGN1 = { 620 CTL VAR, VSNORMAL|VSQUOTE, '@', '=', '\0'628 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0' 621 629 }; 630 #define DOLATSTRLEN 6 622 631 623 632 #define NCMD 0 … … 855 864 case CTLESC: c = 'e'; goto backslash; 856 865 case CTLVAR: c = 'v'; goto backslash; 857 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;858 866 case CTLBACKQ: c = 'q'; goto backslash; 859 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;860 867 backslash: 861 868 putc('\\', tracefile); … … 1020 1027 break; 1021 1028 case CTLBACKQ: 1022 case CTLBACKQ|CTLQUOTE:1023 1029 putc('$', fp); 1024 1030 putc('(', fp); … … 1197 1203 } 1198 1204 vfprintf(stderr, msg, ap); 1199 outcslow('\n',stderr);1205 newline_and_flush(stderr); 1200 1206 } 1201 1207 … … 2009 2015 #endif 2010 2016 2011 /* math.h has these, otherwise define our private copies */2012 #if !ENABLE_SH_MATH_SUPPORT2013 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))2014 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))2015 /*2016 * Return the pointer to the first char which is not part of a legal variable name2017 * (a letter or underscore followed by letters, underscores, and digits).2018 */2019 static const char*2020 endofname(const char *name)2021 {2022 if (!is_name(*name))2023 return name;2024 while (*++name) {2025 if (!is_in_name(*name))2026 break;2027 }2028 return name;2029 }2030 #endif2031 2032 2017 /* 2033 2018 * Compares two strings up to the first = or '\0'. The first … … 2041 2026 2042 2027 while ((c = *p) == (d = *q)) { 2043 if ( !c|| c == '=')2028 if (c == '\0' || c == '=') 2044 2029 goto out; 2045 2030 p++; … … 2139 2124 } 2140 2125 2126 static void reinit_unicode_for_ash(void) 2127 { 2128 /* Unicode support should be activated even if LANG is set 2129 * _during_ shell execution, not only if it was set when 2130 * shell was started. Therefore, re-check LANG every time: 2131 */ 2132 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV 2133 || ENABLE_UNICODE_USING_LOCALE 2134 ) { 2135 const char *s = lookupvar("LC_ALL"); 2136 if (!s) s = lookupvar("LC_CTYPE"); 2137 if (!s) s = lookupvar("LANG"); 2138 reinit_unicode(s); 2139 } 2140 } 2141 2141 2142 /* 2142 2143 * Search the environment of a builtin command. … … 2242 2243 2243 2244 static void FAST_FUNC 2244 setvar 2(const char *name, const char *val)2245 setvar0(const char *name, const char *val) 2245 2246 { 2246 2247 setvar(name, val, 0); … … 2305 2306 INT_ON; 2306 2307 } else { 2307 setvar (s, 0, 0);2308 setvar0(s, NULL); 2308 2309 vp->flags &= ~VEXPORT; 2309 2310 } … … 2555 2556 USTPUTC('/', new); 2556 2557 } 2557 p = strtok( 0, "/");2558 p = strtok(NULL, "/"); 2558 2559 } 2559 2560 if (new > lim) … … 2750 2751 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) 2751 2752 #endif 2752 static const uint16_t S_I_T[] = {2753 static const uint16_t S_I_T[] ALIGN2 = { 2753 2754 #if ENABLE_ASH_ALIAS 2754 2755 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */ … … 2852 2853 #else /* !USE_SIT_FUNCTION */ 2853 2854 2854 static const uint8_t syntax_index_table[] = {2855 static const uint8_t syntax_index_table[] ALIGN1 = { 2855 2856 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ 2856 2857 /* 0 */ CWORD_CWORD_CWORD_CWORD, … … 3336 3337 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */ 3337 3338 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */ 3339 #define SHOW_STDERR 0x08 /* print to stderr (else stdout) */ 3338 3340 3339 3341 /* … … 3642 3644 if (is_number(p)) { 3643 3645 num = atoi(p); 3644 if (num < njobs) {3646 if (num <= njobs) { 3645 3647 jp = jobtab + num - 1; 3646 3648 if (jp->used) … … 3850 3852 for (ps = jp->ps + 1; ps < psend; ps++) 3851 3853 printf(" | %s", ps->ps_cmd); 3852 outcslow('\n',stdout);3854 newline_and_flush(stdout); 3853 3855 flush_stdout_stderr(); 3854 3856 } … … 3910 3912 3911 3913 static int 3912 sprint_status (char *s, int status, int sigonly)3914 sprint_status48(char *s, int status, int sigonly) 3913 3915 { 3914 3916 int col; … … 3917 3919 col = 0; 3918 3920 if (!WIFEXITED(status)) { 3919 #if JOBS 3920 if (WIFSTOPPED(status)) 3921 if (JOBS && WIFSTOPPED(status)) 3921 3922 st = WSTOPSIG(status); 3922 3923 else 3923 #endif3924 3924 st = WTERMSIG(status); 3925 3925 if (sigonly) { 3926 3926 if (st == SIGINT || st == SIGPIPE) 3927 3927 goto out; 3928 #if JOBS 3929 if (WIFSTOPPED(status)) 3928 if (JOBS && WIFSTOPPED(status)) 3930 3929 goto out; 3931 #endif3932 3930 } 3933 3931 st &= 0x7f; … … 3935 3933 col = fmtstr(s, 32, strsignal(st)); 3936 3934 if (WCOREDUMP(status)) { 3937 col += fmtstr(s + col, 16, " (core dumped)"); 3935 strcpy(s + col, " (core dumped)"); 3936 col += sizeof(" (core dumped)")-1; 3938 3937 } 3939 3938 } else if (!sigonly) { 3940 3939 st = WEXITSTATUS(status); 3941 if (st) 3942 col = fmtstr(s, 16, "Done(%d)", st); 3943 else 3944 col = fmtstr(s, 16, "Done"); 3940 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st); 3945 3941 } 3946 3942 out: … … 3955 3951 struct job *jp; 3956 3952 struct job *thisjob; 3957 int state;3958 3953 3959 3954 TRACE(("dowait(0x%x) called\n", wait_flags)); … … 3973 3968 thisjob = NULL; 3974 3969 for (jp = curjob; jp; jp = jp->prev_job) { 3970 int jobstate; 3975 3971 struct procstat *ps; 3976 3972 struct procstat *psend; 3977 3973 if (jp->state == JOBDONE) 3978 3974 continue; 3979 state = JOBDONE;3975 jobstate = JOBDONE; 3980 3976 ps = jp->ps; 3981 3977 psend = ps + jp->nprocs; … … 3989 3985 } 3990 3986 if (ps->ps_status == -1) 3991 state = JOBRUNNING;3987 jobstate = JOBRUNNING; 3992 3988 #if JOBS 3993 if ( state == JOBRUNNING)3989 if (jobstate == JOBRUNNING) 3994 3990 continue; 3995 3991 if (WIFSTOPPED(ps->ps_status)) { 3996 3992 jp->stopstatus = ps->ps_status; 3997 state = JOBSTOPPED;3993 jobstate = JOBSTOPPED; 3998 3994 } 3999 3995 #endif 4000 3996 } while (++ps < psend); 4001 if (thisjob) 4002 goto gotjob; 4003 } 3997 if (!thisjob) 3998 continue; 3999 4000 /* Found the job where one of its processes changed its state. 4001 * Is there at least one live and running process in this job? */ 4002 if (jobstate != JOBRUNNING) { 4003 /* No. All live processes in the job are stopped 4004 * (JOBSTOPPED) or there are no live processes (JOBDONE) 4005 */ 4006 thisjob->changed = 1; 4007 if (thisjob->state != jobstate) { 4008 TRACE(("Job %d: changing state from %d to %d\n", 4009 jobno(thisjob), thisjob->state, jobstate)); 4010 thisjob->state = jobstate; 4004 4011 #if JOBS 4005 if (!WIFSTOPPED(status)) 4006 #endif 4012 if (jobstate == JOBSTOPPED) 4013 set_curjob(thisjob, CUR_STOPPED); 4014 #endif 4015 } 4016 } 4017 goto out; 4018 } 4019 /* The process wasn't found in job list */ 4020 if (JOBS && !WIFSTOPPED(status)) 4007 4021 jobless--; 4008 goto out;4009 4010 gotjob:4011 if (state != JOBRUNNING) {4012 thisjob->changed = 1;4013 4014 if (thisjob->state != state) {4015 TRACE(("Job %d: changing state from %d to %d\n",4016 jobno(thisjob), thisjob->state, state));4017 thisjob->state = state;4018 #if JOBS4019 if (state == JOBSTOPPED) {4020 set_curjob(thisjob, CUR_STOPPED);4021 }4022 #endif4023 }4024 }4025 4026 4022 out: 4027 4023 INT_ON; … … 4031 4027 int len; 4032 4028 4033 len = sprint_status (s, status, 1);4029 len = sprint_status48(s, status, 1); 4034 4030 if (len) { 4035 4031 s[len] = '\n'; … … 4052 4048 #if JOBS 4053 4049 static void 4054 showjob( FILE *out,struct job *jp, int mode)4050 showjob(struct job *jp, int mode) 4055 4051 { 4056 4052 struct procstat *ps; … … 4058 4054 int col; 4059 4055 int indent_col; 4060 char s[80]; 4056 char s[16 + 16 + 48]; 4057 FILE *out = (mode & SHOW_STDERR ? stderr : stdout); 4061 4058 4062 4059 ps = jp->ps; … … 4088 4085 if (jp->state == JOBSTOPPED) 4089 4086 status = jp->stopstatus; 4090 col += sprint_status (s + col, status, 0);4087 col += sprint_status48(s + col, status, 0); 4091 4088 } 4092 4089 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ … … 4115 4112 ); 4116 4113 } while (++ps != psend); 4117 outcslow('\n',out);4114 newline_and_flush(out); 4118 4115 4119 4116 jp->changed = 0; … … 4130 4127 */ 4131 4128 static void 4132 showjobs( FILE *out,int mode)4129 showjobs(int mode) 4133 4130 { 4134 4131 struct job *jp; … … 4142 4139 for (jp = curjob; jp; jp = jp->prev_job) { 4143 4140 if (!(mode & SHOW_CHANGED) || jp->changed) { 4144 showjob( out,jp, mode);4141 showjob(jp, mode); 4145 4142 } 4146 4143 } … … 4163 4160 if (*argv) { 4164 4161 do 4165 showjob( stdout,getjob(*argv, 0), mode);4162 showjob(getjob(*argv, 0), mode); 4166 4163 while (*++argv); 4167 4164 } else { 4168 showjobs( stdout,mode);4165 showjobs(mode); 4169 4166 } 4170 4167 … … 4408 4405 else 4409 4406 str = "${"; 4410 if (!(subtype & VSQUOTE) == !(quoted & 1)) 4411 goto dostr; 4412 quoted ^= 1; 4413 c = '"'; 4414 break; 4407 goto dostr; 4415 4408 case CTLENDVAR: 4416 4409 str = "\"}" + !(quoted & 1); … … 4420 4413 case CTLBACKQ: 4421 4414 str = "$(...)"; 4422 goto dostr;4423 case CTLBACKQ+CTLQUOTE:4424 str = "\"$(...)\"";4425 4415 goto dostr; 4426 4416 #if ENABLE_SH_MATH_SUPPORT … … 4758 4748 */ 4759 4749 /* Save trap handler strings for trap builtin to print */ 4760 trap_ptr = memcpy(xmalloc(sizeof(trap)),trap, sizeof(trap));4750 trap_ptr = xmemdup(trap, sizeof(trap)); 4761 4751 /* Fall through into clearing traps */ 4762 4752 } … … 5419 5409 int i; 5420 5410 5421 if (--g_nullredirs >= 0 )5411 if (--g_nullredirs >= 0 || redirlist == NULL) 5422 5412 return; 5423 5413 INT_OFF; … … 5500 5490 5501 5491 math_state.lookupvar = lookupvar; 5502 math_state.setvar = setvar 2;5492 math_state.setvar = setvar0; 5503 5493 //math_state.endofname = endofname; 5504 5494 … … 5521 5511 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ 5522 5512 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 5523 #define EXP_ RECORD 0x20 /* need to record arguments for ifs breakup*/5513 #define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ 5524 5514 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 5525 5515 #define EXP_WORD 0x80 /* expand word in parameter expansion */ 5526 #define EXP_Q WORD 0x100 /* expand word in quoted parameter expansion*/5516 #define EXP_QUOTED 0x100 /* expand word in double quotes */ 5527 5517 /* 5528 5518 * rmescape() flags … … 5530 5520 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 5531 5521 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 5532 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */5533 5522 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 5534 5523 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 5524 #define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */ 5525 5526 /* Add CTLESC when necessary. */ 5527 #define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR) 5528 /* Do not skip NUL characters. */ 5529 #define QUOTES_KEEPNUL EXP_TILDE 5535 5530 5536 5531 /* … … 5574 5569 int len; 5575 5570 5576 expdest = makestrspace( 32, expdest);5577 len = fmtstr(expdest, 32, ARITH_FMT, num);5571 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest); 5572 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num); 5578 5573 STADJUST(len, expdest); 5579 5574 return len; … … 5597 5592 rmescapes(char *str, int flag) 5598 5593 { 5599 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; 5594 static const char qchars[] ALIGN1 = { 5595 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' }; 5600 5596 5601 5597 char *p, *q, *r; … … 5603 5599 unsigned protect_against_glob; 5604 5600 unsigned globbing; 5605 5606 p = strpbrk(str, qchars); 5601 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;) 5602 5603 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash)); 5607 5604 if (!p) 5608 5605 return str; … … 5631 5628 } 5632 5629 5633 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;5630 inquotes = 0; 5634 5631 globbing = flag & RMESCAPE_GLOB; 5635 5632 protect_against_glob = globbing; 5636 5633 while (*p) { 5637 5634 if ((unsigned char)*p == CTLQUOTEMARK) { 5638 // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 05639 // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?5640 5635 // Note: both inquotes and protect_against_glob only affect whether 5641 5636 // CTLESC,<ch> gets converted to <ch> or to \<ch> … … 5645 5640 continue; 5646 5641 } 5647 if (*p == '\\') { 5642 if ((unsigned char)*p == CTLESC) { 5643 p++; 5644 if (protect_against_glob) { 5645 *q++ = '\\'; 5646 } 5647 } else if (*p == '\\' && !inquotes) { 5648 5648 /* naked back slash */ 5649 5649 protect_against_glob = 0; 5650 5650 goto copy; 5651 5651 } 5652 if ((unsigned char)*p == CTLESC) { 5653 p++; 5654 if (protect_against_glob && inquotes && *p != '/') { 5655 *q++ = '\\'; 5656 } 5657 } 5652 #if ENABLE_ASH_BASH_COMPAT 5653 else if (*p == '/' && slash) { 5654 /* stop handling globbing and mark location of slash */ 5655 globbing = slash = 0; 5656 *p = CTLESC; 5657 } 5658 #endif 5658 5659 protect_against_glob = globbing; 5659 5660 copy: … … 5675 5676 */ 5676 5677 static char * 5677 preglob(const char *pattern, int quoted, int flag) 5678 { 5679 flag |= RMESCAPE_GLOB; 5680 if (quoted) { 5681 flag |= RMESCAPE_QUOTED; 5682 } 5683 return rmescapes((char *)pattern, flag); 5678 preglob(const char *pattern, int flag) 5679 { 5680 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB); 5684 5681 } 5685 5682 … … 5690 5687 memtodest(const char *p, size_t len, int syntax, int quotes) 5691 5688 { 5692 char *q = expdest; 5693 5694 q = makestrspace(quotes ? len * 2 : len, q); 5695 5696 while (len--) { 5689 char *q; 5690 5691 if (!len) 5692 return; 5693 5694 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest); 5695 5696 do { 5697 5697 unsigned char c = *p++; 5698 if (c == '\0') 5698 if (c) { 5699 int n = SIT(c, syntax); 5700 if ((quotes & QUOTES_ESC) && 5701 ((n == CCTL) || 5702 (((quotes & EXP_FULL) || syntax != BASESYNTAX) && 5703 n == CBACK))) 5704 USTPUTC(CTLESC, q); 5705 } else if (!(quotes & QUOTES_KEEPNUL)) 5699 5706 continue; 5700 if (quotes) {5701 int n = SIT(c, syntax);5702 if (n == CCTL || n == CBACK)5703 USTPUTC(CTLESC, q);5704 }5705 5707 USTPUTC(c, q); 5706 } 5708 } while (--len); 5707 5709 5708 5710 expdest = q; 5709 5711 } 5710 5712 5711 static void5713 static size_t 5712 5714 strtodest(const char *p, int syntax, int quotes) 5713 5715 { 5714 memtodest(p, strlen(p), syntax, quotes); 5716 size_t len = strlen(p); 5717 memtodest(p, len, syntax, quotes); 5718 return len; 5715 5719 } 5716 5720 … … 5785 5789 struct passwd *pw; 5786 5790 const char *home; 5787 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); 5788 int startloc; 5791 int quotes = flags & QUOTES_ESC; 5789 5792 5790 5793 name = p + 1; … … 5818 5821 goto lose; 5819 5822 *p = c; 5820 startloc = expdest - (char *)stackblock();5821 5823 strtodest(home, SQSYNTAX, quotes); 5822 recordregion(startloc, expdest - (char *)stackblock(), 0);5823 5824 return p; 5824 5825 lose: … … 5893 5894 */ 5894 5895 static void 5895 expbackq(union node *cmd, int quoted, int quotes)5896 expbackq(union node *cmd, int flag) 5896 5897 { 5897 5898 struct backcmd in; … … 5901 5902 char *dest; 5902 5903 int startloc; 5903 int syntax = quoted? DQSYNTAX : BASESYNTAX;5904 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; 5904 5905 struct stackmark smark; 5905 5906 … … 5917 5918 goto read; 5918 5919 for (;;) { 5919 memtodest(p, i, syntax, quotes);5920 memtodest(p, i, syntax, flag & QUOTES_ESC); 5920 5921 read: 5921 5922 if (in.fd < 0) 5922 5923 break; 5923 i = nonblock_immune_read(in.fd, buf, sizeof(buf) , /*loop_on_EINTR:*/ 1);5924 i = nonblock_immune_read(in.fd, buf, sizeof(buf)); 5924 5925 TRACE(("expbackq: read returns %d\n", i)); 5925 5926 if (i <= 0) … … 5941 5942 expdest = dest; 5942 5943 5943 if ( quoted == 0)5944 if (!(flag & EXP_QUOTED)) 5944 5945 recordregion(startloc, dest - (char *)stackblock(), 0); 5945 5946 TRACE(("evalbackq: size:%d:'%.*s'\n", … … 5955 5956 */ 5956 5957 static void 5957 expari(int quotes)5958 expari(int flag) 5958 5959 { 5959 5960 char *p, *start; 5960 5961 int begoff; 5961 int flag;5962 5962 int len; 5963 5963 … … 5997 5997 removerecordregions(begoff); 5998 5998 5999 flag = p[1];6000 6001 5999 expdest = p; 6002 6000 6003 if ( quotes)6004 rmescapes(p + 2, 0);6005 6006 len = cvtnum(ash_arith(p + 2));6007 6008 if ( flag != '"')6001 if (flag & QUOTES_ESC) 6002 rmescapes(p + 1, 0); 6003 6004 len = cvtnum(ash_arith(p + 1)); 6005 6006 if (!(flag & EXP_QUOTED)) 6009 6007 recordregion(begoff, begoff + len, 0); 6010 6008 } … … 6034 6032 CTLVAR, 6035 6033 CTLBACKQ, 6036 CTLBACKQ | CTLQUOTE,6037 6034 #if ENABLE_SH_MATH_SUPPORT 6038 6035 CTLENDARI, … … 6041 6038 }; 6042 6039 const char *reject = spclchars; 6043 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ 6044 int breakall = flags & EXP_WORD; 6040 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; 6045 6041 int inquotes; 6046 6042 size_t length; … … 6060 6056 tilde: 6061 6057 q = p; 6062 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))6063 q++;6064 6058 if (*q == '~') 6065 6059 p = exptilde(p, q, flags); … … 6118 6112 goto breakloop; 6119 6113 case CTLQUOTEMARK: 6114 inquotes ^= EXP_QUOTED; 6120 6115 /* "$@" syntax adherence hack */ 6121 if (!inquotes 6122 && memcmp(p, dolatstr, 4) == 0 6123 && ( p[4] == (char)CTLQUOTEMARK 6124 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) 6125 ) 6126 ) { 6127 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; 6116 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { 6117 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1; 6128 6118 goto start; 6129 6119 } 6130 inquotes = !inquotes;6131 6120 addquote: 6132 if ( quotes) {6121 if (flags & QUOTES_ESC) { 6133 6122 p--; 6134 6123 length++; … … 6139 6128 startloc++; 6140 6129 length++; 6130 6131 /* 6132 * Quoted parameter expansion pattern: remove quote 6133 * unless inside inner quotes or we have a literal 6134 * backslash. 6135 */ 6136 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) == 6137 EXP_QPAT && *p != '\\') 6138 break; 6139 6141 6140 goto addquote; 6142 6141 case CTLVAR: 6143 6142 TRACE(("argstr: evalvar('%s')\n", p)); 6144 p = evalvar(p, flags , var_str_list);6143 p = evalvar(p, flags | inquotes, var_str_list); 6145 6144 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); 6146 6145 goto start; 6147 6146 case CTLBACKQ: 6148 c = '\0'; 6149 case CTLBACKQ|CTLQUOTE: 6150 expbackq(argbackq->n, c, quotes); 6147 expbackq(argbackq->n, flags | inquotes); 6151 6148 argbackq = argbackq->next; 6152 6149 goto start; … … 6154 6151 case CTLENDARI: 6155 6152 p--; 6156 expari( quotes);6153 expari(flags | inquotes); 6157 6154 goto start; 6158 6155 #endif … … 6284 6281 } 6285 6282 6286 #if ENABLE_ASH_BASH_COMPAT6287 static char *6288 parse_sub_pattern(char *arg, int varflags)6289 {6290 char *idx, *repl = NULL;6291 unsigned char c;6292 6293 //char *org_arg = arg;6294 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);6295 idx = arg;6296 while (1) {6297 c = *arg;6298 if (!c)6299 break;6300 if (c == '/') {6301 /* Only the first '/' seen is our separator */6302 if (!repl) {6303 repl = idx + 1;6304 c = '\0';6305 }6306 }6307 *idx++ = c;6308 arg++;6309 /*6310 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}6311 * The result is a_\_z_c (not a\_\_z_c)!6312 *6313 * Enable debug prints in this function and you'll see:6314 * ash: arg:'\\b/_\\_z_' varflags:d6315 * ash: pattern:'\\b' repl:'_\_z_'6316 * That is, \\b is interpreted as \\b, but \\_ as \_!6317 * IOW: search pattern and replace string treat backslashes6318 * differently! That is the reason why we check repl below:6319 */6320 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))6321 arg++; /* skip both '\', not just first one */6322 }6323 *idx = c; /* NUL */6324 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);6325 6326 return repl;6327 }6328 #endif /* ENABLE_ASH_BASH_COMPAT */6329 6330 6283 static const char * 6331 6284 subevalvar(char *p, char *varname, int strloc, int subtype, 6332 int startloc, int varflags, int quotes, struct strlist *var_str_list)6285 int startloc, int varflags, int flag, struct strlist *var_str_list) 6333 6286 { 6334 6287 struct nodelist *saveargbackq = argbackq; 6288 int quotes = flag & QUOTES_ESC; 6335 6289 char *startp; 6336 6290 char *loc; 6337 6291 char *rmesc, *rmescend; 6338 6292 char *str; 6339 IF_ASH_BASH_COMPAT(c onst char *repl = NULL;)6293 IF_ASH_BASH_COMPAT(char *repl = NULL;) 6340 6294 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 6341 6295 int saveherefd = herefd; … … 6349 6303 6350 6304 herefd = -1; 6351 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, 6305 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? 6306 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0), 6352 6307 var_str_list); 6353 6308 STPUTC('\0', expdest); … … 6358 6313 switch (subtype) { 6359 6314 case VSASSIGN: 6360 setvar (varname, startp, 0);6315 setvar0(varname, startp); 6361 6316 amount = startp - expdest; 6362 6317 STADJUST(amount, expdest); … … 6406 6361 } 6407 6362 } 6408 if (pos >= orig_len) { 6363 if (pos < 0) { 6364 /* ${VAR:$((-n)):l} starts n chars from the end */ 6365 pos = orig_len + pos; 6366 } 6367 if ((unsigned)pos >= orig_len) { 6368 /* apart from obvious ${VAR:999999:l}, 6369 * covers ${VAR:$((-9999999)):l} - result is "" 6370 * (bash-compat) 6371 */ 6409 6372 pos = 0; 6410 6373 len = 0; … … 6453 6416 rmescend--; 6454 6417 str = (char *)stackblock() + strloc; 6455 preglob(str, varflags & VSQUOTE, 0); 6418 /* 6419 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} 6420 * The result is a_\_z_c (not a\_\_z_c)! 6421 * 6422 * The search pattern and replace string treat backslashes differently! 6423 * RMESCAPE_SLASH causes preglob to work differently on the pattern 6424 * and string. It's only used on the first call. 6425 */ 6426 preglob(str, IF_ASH_BASH_COMPAT( 6427 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? 6428 RMESCAPE_SLASH :) 0); 6456 6429 6457 6430 #if ENABLE_ASH_BASH_COMPAT … … 6461 6434 6462 6435 if (!repl) { 6463 repl = parse_sub_pattern(str, varflags);6464 //bb_error_msg("repl:'%s'", repl);6465 if (!repl)6436 if ((repl=strchr(str, CTLESC))) 6437 *repl++ = '\0'; 6438 else 6466 6439 repl = nullstr; 6467 6440 } 6441 //bb_error_msg("str:'%s' repl:'%s'", str, repl); 6468 6442 6469 6443 /* If there's no pattern to match, return the expansion unmolested */ … … 6598 6572 int num; 6599 6573 int i; 6600 int sepq = 0;6601 6574 ssize_t len = 0; 6575 int sep; 6576 int quoted = flags & EXP_QUOTED; 6602 6577 int subtype = varflags & VSTYPE; 6603 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);6604 int quote d = varflags & VSQUOTE;6578 int discard = subtype == VSPLUS || subtype == VSLENGTH; 6579 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; 6605 6580 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 6581 6582 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0; 6606 6583 6607 6584 switch (*name) { … … 6639 6616 case '@': { 6640 6617 char **ap; 6641 int sep;6618 char sepc; 6642 6619 6643 6620 if (quoted && (flags & EXP_FULL)) { … … 6649 6626 case '*': 6650 6627 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; 6651 i = SIT(sep, syntax);6652 if (quotes && (i == CCTL || i == CBACK))6653 sepq = 1;6654 6628 param: 6655 6629 ap = shellparam.p; 6630 sepc = sep; 6656 6631 if (!ap) 6657 6632 return -1; 6658 6633 while ((p = *ap++) != NULL) { 6659 size_t partlen; 6660 6661 partlen = strlen(p); 6662 len += partlen; 6663 6664 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 6665 memtodest(p, partlen, syntax, quotes); 6634 len += strtodest(p, syntax, quotes); 6666 6635 6667 6636 if (*ap && sep) { 6668 char *q;6669 6670 6637 len++; 6671 if (subtype == VSPLUS || subtype == VSLENGTH) { 6672 continue; 6673 } 6674 q = expdest; 6675 if (sepq) 6676 STPUTC(CTLESC, q); 6677 /* note: may put NUL despite sep != 0 6678 * (see sep = 1 << CHAR_BIT above) */ 6679 STPUTC(sep, q); 6680 expdest = q; 6638 memtodest(&sepc, 1, syntax, quotes); 6681 6639 } 6682 6640 } 6683 return len;6641 break; 6684 6642 } /* case '@' and '*' */ 6685 6643 case '0': … … 6730 6688 return -1; 6731 6689 6732 len = strlen(p); 6733 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 6734 memtodest(p, len, syntax, quotes); 6735 return len; 6736 } 6737 6738 if (subtype == VSPLUS || subtype == VSLENGTH) 6690 len = strtodest(p, syntax, quotes); 6691 #if ENABLE_UNICODE_SUPPORT 6692 if (subtype == VSLENGTH && len > 0) { 6693 reinit_unicode_for_ash(); 6694 if (unicode_status == UNICODE_ON) { 6695 STADJUST(-len, expdest); 6696 discard = 0; 6697 len = unicode_strlen(p); 6698 } 6699 } 6700 #endif 6701 break; 6702 } 6703 6704 if (discard) 6739 6705 STADJUST(-len, expdest); 6740 6706 return len; … … 6750 6716 char varflags; 6751 6717 char subtype; 6752 charquoted;6718 int quoted; 6753 6719 char easy; 6754 6720 char *var; … … 6759 6725 varflags = (unsigned char) *p++; 6760 6726 subtype = varflags & VSTYPE; 6761 quoted = varflags & VSQUOTE;6727 quoted = flags & EXP_QUOTED; 6762 6728 var = p; 6763 6729 easy = (!quoted || (*var == '@' && shellparam.nparam)); … … 6780 6746 argstr( 6781 6747 p, 6782 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),6748 flags | EXP_TILDE | EXP_WORD, 6783 6749 var_str_list 6784 6750 ); … … 6794 6760 if (subevalvar(p, var, /* strloc: */ 0, 6795 6761 subtype, startloc, varflags, 6796 /* quotes: */ 0,6762 /* quotes: */ flags & ~QUOTES_ESC, 6797 6763 var_str_list) 6798 6764 ) { … … 6851 6817 patloc = expdest - (char *)stackblock(); 6852 6818 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 6853 startloc, varflags, 6854 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), 6855 var_str_list) 6856 ) { 6819 startloc, varflags, flags, var_str_list)) { 6857 6820 int amount = expdest - ( 6858 6821 (char *)stackblock() + patloc - 1 … … 6873 6836 if (c == CTLESC) 6874 6837 p++; 6875 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {6838 else if (c == CTLBACKQ) { 6876 6839 if (varlen >= 0) 6877 6840 argbackq = argbackq->next; … … 7028 6991 int atend; 7029 6992 int matchdot; 6993 int esc; 7030 6994 7031 6995 metaflag = 0; 7032 6996 start = name; 7033 for (p = name; *p; p++) {6997 for (p = name; esc = 0, *p; p += esc + 1) { 7034 6998 if (*p == '*' || *p == '?') 7035 6999 metaflag = 1; … … 7048 7012 } 7049 7013 } 7050 } else if (*p == '\\') 7051 p++; 7052 else if (*p == '/') { 7053 if (metaflag) 7054 goto out; 7055 start = p + 1; 7056 } 7057 } 7058 out: 7014 } else { 7015 if (*p == '\\') 7016 esc++; 7017 if (p[esc] == '/') { 7018 if (metaflag) 7019 break; 7020 start = p + esc + 1; 7021 } 7022 } 7023 } 7059 7024 if (metaflag == 0) { /* we've reached the end of the file name */ 7060 7025 if (enddir != expdir) … … 7096 7061 } else { 7097 7062 atend = 0; 7098 *endname++ = '\0'; 7063 *endname = '\0'; 7064 endname += esc + 1; 7099 7065 } 7100 7066 matchdot = 0; … … 7121 7087 closedir(dirp); 7122 7088 if (!atend) 7123 endname[- 1] ='/';7089 endname[-esc - 1] = esc ? '\\' : '/'; 7124 7090 } 7125 7091 … … 7209 7175 7210 7176 INT_OFF; 7211 p = preglob(str->text, 0,RMESCAPE_ALLOC | RMESCAPE_HEAP);7177 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); 7212 7178 { 7213 7179 int i = strlen(str->text); … … 7299 7265 { 7300 7266 herefd = fd; 7301 expandarg(arg, (struct arglist *)NULL, 0);7267 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); 7302 7268 full_write(fd, stackblock(), expdest - (char *)stackblock()); 7303 7269 } … … 7309 7275 patmatch(char *pattern, const char *string) 7310 7276 { 7311 return pmatch(preglob(pattern, 0 , 0), string);7277 return pmatch(preglob(pattern, 0), string); 7312 7278 } 7313 7279 … … 7762 7728 builtinloc = idx_bltin; 7763 7729 } 7764 7765 #define TEOF 0 7766 #define TNL 1 7767 #define TREDIR 2 7768 #define TWORD 3 7769 #define TSEMI 4 7770 #define TBACKGND 5 7771 #define TAND 6 7772 #define TOR 7 7773 #define TPIPE 8 7774 #define TLP 9 7775 #define TRP 10 7776 #define TENDCASE 11 7777 #define TENDBQUOTE 12 7778 #define TNOT 13 7779 #define TCASE 14 7780 #define TDO 15 7781 #define TDONE 16 7782 #define TELIF 17 7783 #define TELSE 18 7784 #define TESAC 19 7785 #define TFI 20 7786 #define TFOR 21 7787 #define TIF 22 7788 #define TIN 23 7789 #define TTHEN 24 7790 #define TUNTIL 25 7791 #define TWHILE 26 7792 #define TBEGIN 27 7793 #define TEND 28 7730 enum { 7731 TEOF, 7732 TNL, 7733 TREDIR, 7734 TWORD, 7735 TSEMI, 7736 TBACKGND, 7737 TAND, 7738 TOR, 7739 TPIPE, 7740 TLP, 7741 TRP, 7742 TENDCASE, 7743 TENDBQUOTE, 7744 TNOT, 7745 TCASE, 7746 TDO, 7747 TDONE, 7748 TELIF, 7749 TELSE, 7750 TESAC, 7751 TFI, 7752 TFOR, 7753 #if ENABLE_ASH_BASH_COMPAT 7754 TFUNCTION, 7755 #endif 7756 TIF, 7757 TIN, 7758 TTHEN, 7759 TUNTIL, 7760 TWHILE, 7761 TBEGIN, 7762 TEND 7763 }; 7794 7764 typedef smallint token_id_t; 7795 7765 … … 7820 7790 "\1fi", 7821 7791 "\0for", 7792 #if ENABLE_ASH_BASH_COMPAT 7793 "\0function", 7794 #endif 7822 7795 "\0if", 7823 7796 "\0in", … … 7848 7821 */ 7849 7822 static int 7850 describe_command(char *command, int describe_command_verbose)7823 describe_command(char *command, const char *path, int describe_command_verbose) 7851 7824 { 7852 7825 struct cmdentry entry; … … 7855 7828 const struct alias *ap; 7856 7829 #endif 7857 const char *path = pathval(); 7830 7831 path = path ? path : pathval(); 7858 7832 7859 7833 if (describe_command_verbose) { … … 7955 7929 } 7956 7930 while (argv[i]) { 7957 err |= describe_command(argv[i++], verbose);7931 err |= describe_command(argv[i++], NULL, verbose); 7958 7932 } 7959 7933 return err; … … 7969 7943 VERIFY_VERBOSE = 2, 7970 7944 } verify = 0; 7945 const char *path = NULL; 7971 7946 7972 7947 while ((c = nextopt("pvV")) != '\0') … … 7979 7954 abort(); 7980 7955 #endif 7956 else 7957 path = bb_default_path; 7981 7958 /* Mimic bash: just "command -v" doesn't complain, it's a nop */ 7982 7959 if (verify && (*argptr != NULL)) { 7983 return describe_command(*argptr, verify - VERIFY_BRIEF);7960 return describe_command(*argptr, path, verify - VERIFY_BRIEF); 7984 7961 } 7985 7962 … … 8001 7978 #define EV_BACKCMD 04 /* command executing within back quotes */ 8002 7979 8003 static const uint8_t nodesize[N_NUMBER] = {7980 static const uint8_t nodesize[N_NUMBER] ALIGN1 = { 8004 7981 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), 8005 7982 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)), … … 8454 8431 (flags | ((is_or >> 1) - 1)) & EV_TESTED 8455 8432 ); 8456 if ( !exitstatus== is_or)8433 if ((!exitstatus) == is_or) 8457 8434 break; 8458 8435 if (!evalskip) { … … 8562 8539 arglist.lastp = &arglist.list; 8563 8540 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 8564 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);8541 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 8565 8542 /* XXX */ 8566 8543 if (evalskip) … … 8573 8550 flags &= EV_TESTED; 8574 8551 for (sp = arglist.list; sp; sp = sp->next) { 8575 setvar (n->nfor.var, sp->text, 0);8552 setvar0(n->nfor.var, sp->text); 8576 8553 evaltree(n->nfor.body, flags); 8577 8554 if (evalskip) { … … 8798 8775 /* note: ash and hush share this string */ 8799 8776 out1fmt("\n\n%s %s\n" 8800 "Enter 'help' for a list of built-in commands."8801 "\n \n",8777 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n") 8778 "\n", 8802 8779 bb_banner, 8803 8780 "built-in shell (ash)" … … 8914 8891 cp = *++argv; 8915 8892 if (!cp) 8916 return 0;8893 return NULL; 8917 8894 if (*cp++ != '-') 8918 8895 break; … … 8921 8898 break; 8922 8899 if (c == '-' && !*cp) { 8923 argv++; 8900 if (!*++argv) 8901 return NULL; 8924 8902 break; 8925 8903 } … … 8931 8909 default: 8932 8910 /* run 'typecmd' for other options */ 8933 return 0;8911 return NULL; 8934 8912 } 8935 8913 c = *cp++; … … 8944 8922 * value and flags are saved in a localvar structure. The saved values 8945 8923 * will be restored when the shell function returns. We handle the name 8946 * "-" as a special case. 8924 * "-" as a special case: it makes changes to "set +-options" local 8925 * (options will be restored on return from the function). 8947 8926 */ 8948 8927 static void … … 8952 8931 struct var **vpp; 8953 8932 struct var *vp; 8933 char *eq = strchr(name, '='); 8954 8934 8955 8935 INT_OFF; 8956 lvp = ckzalloc(sizeof(struct localvar)); 8936 /* Cater for duplicate "local". Examples: 8937 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x 8938 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x 8939 */ 8940 lvp = localvars; 8941 while (lvp) { 8942 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) { 8943 if (eq) 8944 setvareq(name, 0); 8945 /* else: 8946 * it's a duplicate "local VAR" declaration, do nothing 8947 */ 8948 return; 8949 } 8950 lvp = lvp->next; 8951 } 8952 8953 lvp = ckzalloc(sizeof(*lvp)); 8957 8954 if (LONE_DASH(name)) { 8958 8955 char *p; … … 8961 8958 vp = NULL; 8962 8959 } else { 8963 char *eq;8964 8965 8960 vpp = hashvar(name); 8966 8961 vp = *findvar(vpp, name); 8967 eq = strchr(name, '=');8968 8962 if (vp == NULL) { 8963 /* variable did not exist yet */ 8969 8964 if (eq) 8970 8965 setvareq(name, VSTRFIXED); … … 8976 8971 lvp->text = vp->var_text; 8977 8972 lvp->flags = vp->flags; 8973 /* make sure neither "struct var" nor string gets freed 8974 * during (un)setting: 8975 */ 8978 8976 vp->flags |= VSTRFIXED|VTEXTFIXED; 8979 8977 if (eq) 8980 8978 setvareq(name, 0); 8979 else 8980 /* "local VAR" unsets VAR: */ 8981 setvar0(name, NULL); 8981 8982 } 8982 8983 } … … 8994 8995 { 8995 8996 char *name; 8997 8998 if (!funcnest) 8999 ash_msg_and_raise_error("not in a function"); 8996 9000 8997 9001 argv = argptr; … … 9049 9053 static int getoptscmd(int, char **) FAST_FUNC; 9050 9054 #endif 9051 #if !ENABLE_FEATURE_SH_EXTRA_QUIET9055 #if ENABLE_ASH_HELP 9052 9056 static int helpcmd(int, char **) FAST_FUNC; 9057 #endif 9058 #if MAX_HISTORY 9059 static int historycmd(int, char **) FAST_FUNC; 9053 9060 #endif 9054 9061 #if ENABLE_SH_MATH_SUPPORT … … 9122 9129 #endif 9123 9130 { BUILTIN_NOSPEC "hash" , hashcmd }, 9124 #if !ENABLE_FEATURE_SH_EXTRA_QUIET9131 #if ENABLE_ASH_HELP 9125 9132 { BUILTIN_NOSPEC "help" , helpcmd }, 9133 #endif 9134 #if MAX_HISTORY 9135 { BUILTIN_NOSPEC "history" , historycmd }, 9126 9136 #endif 9127 9137 #if JOBS … … 9431 9441 int exit_status; 9432 9442 int i = exception_type; 9433 if (i == EXEXIT )9443 if (i == EXEXIT || i == EXEXEC) 9434 9444 goto raise; 9435 9445 exit_status = 2; … … 9454 9464 goto raise; 9455 9465 break; 9456 9457 9466 } /* switch */ 9458 9467 … … 9464 9473 * However I implemented that within libedit itself. 9465 9474 */ 9466 setvar ("_", lastarg, 0);9475 setvar0("_", lastarg); 9467 9476 } 9468 9477 popstackmark(&smark); … … 9650 9659 retry: 9651 9660 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 9652 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1 , /*loop_on_EINTR:*/ 1);9661 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 9653 9662 else { 9654 9663 int timeout = -1; … … 9666 9675 line_input_state->path_lookup = pathval(); 9667 9676 # endif 9668 /* Unicode support should be activated even if LANG is set 9669 * _during_ shell execution, not only if it was set when 9670 * shell was started. Therefore, re-check LANG every time: 9671 */ 9672 reinit_unicode(lookupvar("LANG")); 9677 reinit_unicode_for_ash(); 9673 9678 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); 9674 9679 if (nr == 0) { … … 9689 9694 # if ENABLE_ASH_IDLE_TIMEOUT 9690 9695 else if (errno == EAGAIN && timeout > 0) { 9691 p rintf("\007timed out waiting for input: auto-logout\n");9696 puts("\007timed out waiting for input: auto-logout"); 9692 9697 exitshell(); 9693 9698 } … … 9696 9701 } 9697 9702 #else 9698 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1 , /*loop_on_EINTR:*/ 1);9703 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 9699 9704 #endif 9700 9705 … … 10041 10046 #if ENABLE_ASH_MAIL 10042 10047 10043 #define MAXMBOXES 10 10044 10045 /* times of mailboxes */ 10046 static time_t mailtime[MAXMBOXES]; 10048 /* Hash of mtimes of mailboxes */ 10049 static unsigned mailtime_hash; 10047 10050 /* Set if MAIL or MAILPATH is changed. */ 10048 10051 static smallint mail_var_path_changed; … … 10060 10063 char *p; 10061 10064 char *q; 10062 time_t *mtp;10065 unsigned new_hash; 10063 10066 struct stackmark smark; 10064 10067 struct stat statb; … … 10066 10069 setstackmark(&smark); 10067 10070 mpath = mpathset() ? mpathval() : mailval(); 10068 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { 10071 new_hash = 0; 10072 for (;;) { 10069 10073 p = path_advance(&mpath, nullstr); 10070 10074 if (p == NULL) … … 10080 10084 q[-1] = '\0'; /* delete trailing '/' */ 10081 10085 if (stat(p, &statb) < 0) { 10082 *mtp = 0;10083 10086 continue; 10084 10087 } 10085 if (!mail_var_path_changed && statb.st_mtime != *mtp) {10086 fprintf(10087 stderr, "%s\n",10088 pathopt ? pathopt : "you have mail"10089 );10090 }10091 *mtp = statb.st_mtime;10088 /* Very simplistic "hash": just a sum of all mtimes */ 10089 new_hash += (unsigned)statb.st_mtime; 10090 } 10091 if (!mail_var_path_changed && mailtime_hash != new_hash) { 10092 if (mailtime_hash != 0) 10093 out2str("you have mail\n"); 10094 mailtime_hash = new_hash; 10092 10095 } 10093 10096 mail_var_path_changed = 0; … … 10361 10364 int done = 0; 10362 10365 int err = 0; 10363 char s [12];10366 char sbuf[2]; 10364 10367 char **optnext; 10368 10369 sbuf[1] = '\0'; 10365 10370 10366 10371 if (*param_optind < 1) … … 10390 10395 if (*q == '\0') { 10391 10396 if (optstr[0] == ':') { 10392 s [0] = c;10393 s[1] = '\0';10394 err |= setvarsafe("OPTARG", s , 0);10397 sbuf[0] = c; 10398 /*sbuf[1] = '\0'; - already is */ 10399 err |= setvarsafe("OPTARG", sbuf, 0); 10395 10400 } else { 10396 10401 fprintf(stderr, "Illegal option -%c\n", c); … … 10407 10412 if (*p == '\0' && (p = *optnext) == NULL) { 10408 10413 if (optstr[0] == ':') { 10409 s [0] = c;10410 s[1] = '\0';10411 err |= setvarsafe("OPTARG", s , 0);10414 sbuf[0] = c; 10415 /*sbuf[1] = '\0'; - already is */ 10416 err |= setvarsafe("OPTARG", sbuf, 0); 10412 10417 c = ':'; 10413 10418 } else { … … 10428 10433 *optoff = p ? p - *(optnext - 1) : -1; 10429 10434 *param_optind = optnext - optfirst + 1; 10430 fmtstr(s, sizeof(s), "%d", *param_optind); 10431 err |= setvarsafe("OPTIND", s, VNOFUNC); 10432 s[0] = c; 10433 s[1] = '\0'; 10434 err |= setvarsafe(optvar, s, 0); 10435 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC); 10436 sbuf[0] = c; 10437 /*sbuf[1] = '\0'; - already is */ 10438 err |= setvarsafe(optvar, sbuf, 0); 10435 10439 if (err) { 10436 10440 *param_optind = 1; … … 10485 10489 10486 10490 static smallint tokpushback; /* last token pushed back */ 10487 static smallint parsebackquote; /* nonzero if we are inside backquotes */10488 10491 static smallint quoteflag; /* set if (part of) last token was quoted */ 10489 10492 static token_id_t lasttoken; /* last token read (integer id Txxx) */ … … 10530 10533 static union node *parse_command(void); 10531 10534 static void parseheredoc(void); 10532 static charpeektoken(void);10535 static int peektoken(void); 10533 10536 static int readtoken(void); 10534 10537 … … 10539 10542 int tok; 10540 10543 10541 checkkwd = CHKNL | CHKKWD | CHKALIAS;10542 if (nlflag == 2 && peektoken())10543 return NULL;10544 10544 n1 = NULL; 10545 10545 for (;;) { 10546 switch (peektoken()) { 10547 case TNL: 10548 if (!(nlflag & 1)) 10549 break; 10550 parseheredoc(); 10551 return n1; 10552 10553 case TEOF: 10554 if (!n1 && (nlflag & 1)) 10555 n1 = NODE_EOF; 10556 parseheredoc(); 10557 return n1; 10558 } 10559 10560 checkkwd = CHKNL | CHKKWD | CHKALIAS; 10561 if (nlflag == 2 && tokname_array[peektoken()][0]) 10562 return n1; 10563 nlflag |= 2; 10564 10546 10565 n2 = andor(); 10547 10566 tok = readtoken(); … … 10569 10588 } 10570 10589 switch (tok) { 10590 case TNL: 10591 case TEOF: 10592 tokpushback = 1; 10593 /* fall through */ 10571 10594 case TBACKGND: 10572 10595 case TSEMI: 10573 tok = readtoken();10574 /* fall through */10575 case TNL:10576 if (tok == TNL) {10577 parseheredoc();10578 if (nlflag == 1)10579 return n1;10580 } else {10581 tokpushback = 1;10582 }10583 checkkwd = CHKNL | CHKKWD | CHKALIAS;10584 if (peektoken())10585 return n1;10586 10596 break; 10587 case TEOF:10588 if (heredoclist)10589 parseheredoc();10590 else10591 pungetc(); /* push back EOF on input */10592 return n1;10593 10597 default: 10594 if ( nlflag == 1)10598 if ((nlflag & 1)) 10595 10599 raise_error_unexpected_syntax(-1); 10596 10600 tokpushback = 1; … … 10767 10771 #if ENABLE_ASH_BASH_COMPAT 10768 10772 smallint double_brackets_flag = 0; 10773 smallint function_flag = 0; 10769 10774 #endif 10770 10775 … … 10783 10788 switch (t) { 10784 10789 #if ENABLE_ASH_BASH_COMPAT 10790 case TFUNCTION: 10791 if (peektoken() != TWORD) 10792 raise_error_unexpected_syntax(TWORD); 10793 function_flag = 1; 10794 break; 10785 10795 case TAND: /* "&&" */ 10786 10796 case TOR: /* "||" */ … … 10811 10821 savecheckkwd = 0; 10812 10822 } 10823 #if ENABLE_ASH_BASH_COMPAT 10824 if (function_flag) { 10825 checkkwd = CHKNL | CHKKWD; 10826 switch (peektoken()) { 10827 case TBEGIN: 10828 case TIF: 10829 case TCASE: 10830 case TUNTIL: 10831 case TWHILE: 10832 case TFOR: 10833 goto do_func; 10834 case TLP: 10835 function_flag = 0; 10836 break; 10837 case TWORD: 10838 if (strcmp("[[", wordtext) == 0) 10839 goto do_func; 10840 /* fall through */ 10841 default: 10842 raise_error_unexpected_syntax(-1); 10843 } 10844 } 10845 #endif 10813 10846 break; 10814 10847 case TREDIR: … … 10818 10851 break; 10819 10852 case TLP: 10853 IF_ASH_BASH_COMPAT(do_func:) 10820 10854 if (args && app == &args->narg.next 10821 10855 && !vars && !redir … … 10825 10859 10826 10860 /* We have a function */ 10827 if ( readtoken() != TRP)10861 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP) 10828 10862 raise_error_unexpected_syntax(TRP); 10829 10863 name = n->narg.text; … … 10838 10872 return n; 10839 10873 } 10874 IF_ASH_BASH_COMPAT(function_flag = 0;) 10840 10875 /* fall through */ 10841 10876 default: … … 10920 10955 n1->type = NFOR; 10921 10956 n1->nfor.var = wordtext; 10922 checkkwd = CHK KWD | CHKALIAS;10957 checkkwd = CHKNL | CHKKWD | CHKALIAS; 10923 10958 if (readtoken() == TIN) { 10924 10959 app = ≈ … … 10947 10982 * that the original Bourne shell only allowed NL). 10948 10983 */ 10949 if (lasttoken != T NL && lasttoken != TSEMI)10984 if (lasttoken != TSEMI) 10950 10985 tokpushback = 1; 10951 10986 } … … 10966 11001 n2->narg.text = wordtext; 10967 11002 n2->narg.backquote = backquotelist; 10968 do { 10969 checkkwd = CHKKWD | CHKALIAS; 10970 } while (readtoken() == TNL); 10971 if (lasttoken != TIN) 11003 checkkwd = CHKNL | CHKKWD | CHKALIAS; 11004 if (readtoken() != TIN) 10972 11005 raise_error_unexpected_syntax(TIN); 10973 11006 cpp = &n1->ncase.cases; … … 11020 11053 t = TEND; 11021 11054 break; 11055 IF_ASH_BASH_COMPAT(case TFUNCTION:) 11022 11056 case TWORD: 11023 11057 case TREDIR: … … 11138 11172 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) 11139 11173 11140 #if __GNUC__11141 /* Avoid longjmp clobbering */11142 (void) &out;11143 (void) "ef;11144 (void) &dblquote;11145 (void) &varnest;11146 (void) &arinest;11147 (void) &parenlevel;11148 (void) &dqvarnest;11149 (void) &oldstyle;11150 (void) &prevsyntax;11151 (void) &syntax;11152 #endif11153 11174 startlinno = g_parsefile->linno; 11154 11175 bqlist = NULL; … … 11220 11241 && (c != '"' || eofmark != NULL) 11221 11242 ) { 11222 USTPUTC(CTLESC, out);11223 11243 USTPUTC('\\', out); 11224 11244 } 11225 if (SIT(c, SQSYNTAX) == CCTL) 11226 USTPUTC(CTLESC, out); 11245 USTPUTC(CTLESC, out); 11227 11246 USTPUTC(c, out); 11228 11247 quotef = 1; … … 11242 11261 case CENDQUOTE: 11243 11262 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) 11244 if (eofmark != NULL && arinest == 0 11245 && varnest == 0 11246 ) { 11263 if (eofmark != NULL && varnest == 0) { 11247 11264 USTPUTC(c, out); 11248 11265 } else { … … 11278 11295 } else { 11279 11296 if (pgetc() == ')') { 11297 c = CTLENDARI; 11280 11298 if (--arinest == 0) { 11281 11299 syntax = prevsyntax; 11282 dblquote = (syntax == DQSYNTAX);11283 c = CTLENDARI;11284 11300 } 11285 11301 } else { … … 11323 11339 raise_error_syntax("missing '))'"); 11324 11340 #endif 11325 if (syntax != BASESYNTAX && !parsebackquote &&eofmark == NULL)11341 if (syntax != BASESYNTAX && eofmark == NULL) 11326 11342 raise_error_syntax("unterminated quoted string"); 11327 11343 if (varnest != 0) { … … 11485 11501 ) { 11486 11502 #if ENABLE_ASH_BASH_COMPAT 11487 if ( c == '\'')11503 if (syntax != DQSYNTAX && c == '\'') 11488 11504 bash_dollar_squote = 1; 11489 11505 else … … 11600 11616 pungetc(); 11601 11617 } 11602 if (dblquote || arinest)11603 flags |= VSQUOTE;11604 11618 ((unsigned char *)stackblock())[typeloc] = subtype | flags; 11605 11619 if (subtype != VSNORMAL) { 11606 11620 varnest++; 11607 if (dblquote || arinest) {11621 if (dblquote) { 11608 11622 dqvarnest++; 11609 11623 } … … 11621 11635 parsebackq: { 11622 11636 struct nodelist **nlpp; 11623 smallint savepbq;11624 11637 union node *n; 11625 char *volatile str; 11626 struct jmploc jmploc; 11627 struct jmploc *volatile savehandler; 11638 char *str; 11628 11639 size_t savelen; 11629 11640 smallint saveprompt = 0; 11630 11641 11631 #ifdef __GNUC__11632 (void) &saveprompt;11633 #endif11634 savepbq = parsebackquote;11635 if (setjmp(jmploc.loc)) {11636 free(str);11637 parsebackquote = 0;11638 exception_handler = savehandler;11639 longjmp(exception_handler->loc, 1);11640 }11641 INT_OFF;11642 11642 str = NULL; 11643 11643 savelen = out - (char *)stackblock(); 11644 11644 if (savelen > 0) { 11645 str = ckmalloc(savelen);11645 str = alloca(savelen); 11646 11646 memcpy(str, stackblock(), savelen); 11647 11647 } 11648 savehandler = exception_handler;11649 exception_handler = &jmploc;11650 INT_ON;11651 11648 if (oldstyle) { 11652 11649 /* We must read until the closing backquote, giving special … … 11719 11716 *nlpp = stzalloc(sizeof(**nlpp)); 11720 11717 /* (*nlpp)->next = NULL; - stzalloc did it */ 11721 parsebackquote = oldstyle;11722 11718 11723 11719 if (oldstyle) { … … 11748 11744 memcpy(out, str, savelen); 11749 11745 STADJUST(savelen, out); 11750 INT_OFF; 11751 free(str); 11752 str = NULL; 11753 INT_ON; 11754 } 11755 parsebackquote = savepbq; 11756 exception_handler = savehandler; 11757 if (arinest || dblquote) 11758 USTPUTC(CTLBACKQ | CTLQUOTE, out); 11759 else 11760 USTPUTC(CTLBACKQ, out); 11746 } 11747 USTPUTC(CTLBACKQ, out); 11761 11748 if (oldstyle) 11762 11749 goto parsebackq_oldreturn; … … 11772 11759 prevsyntax = syntax; 11773 11760 syntax = ARISYNTAX; 11774 USTPUTC(CTLARI, out); 11775 if (dblquote) 11776 USTPUTC('"', out); 11777 else 11778 USTPUTC(' ', out); 11779 } else { 11780 /* 11781 * we collapse embedded arithmetic expansion to 11782 * parenthesis, which should be equivalent 11783 */ 11784 USTPUTC('(', out); 11785 } 11761 } 11762 USTPUTC(CTLARI, out); 11786 11763 goto parsearith_return; 11787 11764 } 11788 11765 #endif 11789 11790 11766 } /* end of readtoken */ 11791 11767 … … 11958 11934 { 11959 11935 int t; 11936 int kwd = checkkwd; 11960 11937 #if DEBUG 11961 11938 smallint alreadyseen = tokpushback; … … 11971 11948 * eat newlines 11972 11949 */ 11973 if ( checkkwd & CHKNL) {11950 if (kwd & CHKNL) { 11974 11951 while (t == TNL) { 11975 11952 parseheredoc(); … … 11985 11962 * check for keywords 11986 11963 */ 11987 if ( checkkwd & CHKKWD) {11964 if (kwd & CHKKWD) { 11988 11965 const char *const *pp; 11989 11966 … … 12019 11996 } 12020 11997 12021 static char11998 static int 12022 11999 peektoken(void) 12023 12000 { … … 12026 12003 t = readtoken(); 12027 12004 tokpushback = 1; 12028 return t okname_array[t][0];12005 return t; 12029 12006 } 12030 12007 … … 12036 12013 parsecmd(int interact) 12037 12014 { 12038 int t;12039 12040 12015 tokpushback = 0; 12016 checkkwd = 0; 12017 heredoclist = 0; 12041 12018 doprompt = interact; 12042 12019 setprompt_if(doprompt, doprompt); 12043 12020 needprompt = 0; 12044 t = readtoken();12045 if (t == TEOF)12046 return NODE_EOF;12047 if (t == TNL)12048 return NULL;12049 tokpushback = 1;12050 12021 return list(1); 12051 12022 } … … 12098 12069 n.narg.backquote = backquotelist; 12099 12070 12100 expandarg(&n, NULL, 0);12071 expandarg(&n, NULL, EXP_QUOTED); 12101 12072 return stackblock(); 12102 12073 } … … 12180 12151 #if JOBS 12181 12152 if (doing_jobctl) 12182 showjobs( stderr, SHOW_CHANGED);12153 showjobs(SHOW_CHANGED|SHOW_STDERR); 12183 12154 #endif 12184 12155 inter = 0; … … 12277 12248 exitstatus = 0; 12278 12249 12250 /* This aborts if file isn't found, which is POSIXly correct. 12251 * bash returns exitcode 1 instead. 12252 */ 12279 12253 fullname = find_dot_file(argv[1]); 12280 12281 12254 argv += 2; 12282 12255 argc -= 2; … … 12288 12261 }; 12289 12262 12263 /* This aborts if file can't be opened, which is POSIXly correct. 12264 * bash returns exitcode 1 instead. 12265 */ 12290 12266 setinputfile(fullname, INPUT_PUSH_FILE); 12291 12267 commandname = fullname; … … 12595 12571 /* ============ Builtins */ 12596 12572 12597 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 12598 /* 12599 * Lists available builtins 12600 */ 12573 #if ENABLE_ASH_HELP 12601 12574 static int FAST_FUNC 12602 12575 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) … … 12616 12589 } 12617 12590 } 12618 # if ENABLE_FEATURE_SH_STANDALONE12591 # if ENABLE_FEATURE_SH_STANDALONE 12619 12592 { 12620 12593 const char *a = applet_names; … … 12625 12598 col = 0; 12626 12599 } 12627 a += strlen(a) + 1; 12628 } 12629 } 12630 #endif 12600 while (*a++ != '\0') 12601 continue; 12602 } 12603 } 12604 # endif 12631 12605 out1fmt("\n\n"); 12632 12606 return EXIT_SUCCESS; 12633 12607 } 12634 #endif /* FEATURE_SH_EXTRA_QUIET */ 12608 #endif 12609 12610 #if MAX_HISTORY 12611 static int FAST_FUNC 12612 historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12613 { 12614 show_history(line_input_state); 12615 return EXIT_SUCCESS; 12616 } 12617 #endif 12635 12618 12636 12619 /* … … 12749 12732 struct tms buf; 12750 12733 12751 clk_tck = sysconf(_SC_CLK_TCK);12734 clk_tck = bb_clk_tck(); 12752 12735 times(&buf); 12753 12736 … … 12844 12827 */ 12845 12828 INT_OFF; 12846 r = shell_builtin_read(setvar 2,12829 r = shell_builtin_read(setvar0, 12847 12830 argptr, 12848 12831 bltinlookup("IFS"), /* can be NULL */ … … 12862 12845 12863 12846 static int FAST_FUNC 12864 umaskcmd(int argc UNUSED_PARAM, char **argv) 12865 { 12866 static const char permuser[3] ALIGN1 = "ugo"; 12867 static const char permmode[3] ALIGN1 = "rwx"; 12868 static const short permmask[] ALIGN2 = { 12869 S_IRUSR, S_IWUSR, S_IXUSR, 12870 S_IRGRP, S_IWGRP, S_IXGRP, 12871 S_IROTH, S_IWOTH, S_IXOTH 12872 }; 12873 12874 /* TODO: use bb_parse_mode() instead */ 12875 12876 char *ap; 12847 umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12848 { 12849 static const char permuser[3] ALIGN1 = "ogu"; 12850 12877 12851 mode_t mask; 12878 int i;12879 12852 int symbolic_mode = 0; 12880 12853 … … 12888 12861 INT_ON; 12889 12862 12890 ap = *argptr; 12891 if (ap == NULL) { 12863 if (*argptr == NULL) { 12892 12864 if (symbolic_mode) { 12893 char buf[ 18];12865 char buf[sizeof(",u=rwx,g=rwx,o=rwx")]; 12894 12866 char *p = buf; 12895 12896 for (i = 0; i < 3; i++) { 12897 int j; 12898 12867 int i; 12868 12869 i = 2; 12870 for (;;) { 12871 *p++ = ','; 12899 12872 *p++ = permuser[i]; 12900 12873 *p++ = '='; 12901 for (j = 0; j < 3; j++) { 12902 if ((mask & permmask[3 * i + j]) == 0) { 12903 *p++ = permmode[j]; 12904 } 12905 } 12906 *p++ = ','; 12874 /* mask is 0..0uuugggooo. i=2 selects uuu bits */ 12875 if (!(mask & 0400)) *p++ = 'r'; 12876 if (!(mask & 0200)) *p++ = 'w'; 12877 if (!(mask & 0100)) *p++ = 'x'; 12878 mask <<= 3; 12879 if (--i < 0) 12880 break; 12907 12881 } 12908 * --p = 0;12909 puts(buf );12882 *p = '\0'; 12883 puts(buf + 1); 12910 12884 } else { 12911 out1fmt("% .4o\n", mask);12885 out1fmt("%04o\n", mask); 12912 12886 } 12913 12887 } else { 12914 if (isdigit((unsigned char) *ap)) { 12915 mask = 0; 12916 do { 12917 if (*ap >= '8' || *ap < '0') 12918 ash_msg_and_raise_error(msg_illnum, argv[1]); 12919 mask = (mask << 3) + (*ap - '0'); 12920 } while (*++ap != '\0'); 12921 umask(mask); 12922 } else { 12923 mask = ~mask & 0777; 12924 if (!bb_parse_mode(ap, &mask)) { 12925 ash_msg_and_raise_error("illegal mode: %s", ap); 12926 } 12927 umask(~mask & 0777); 12928 } 12888 char *modestr = *argptr; 12889 /* numeric umasks are taken as-is */ 12890 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ 12891 if (!isdigit(modestr[0])) 12892 mask ^= 0777; 12893 mask = bb_parse_mode(modestr, mask); 12894 if ((unsigned)mask > 0777) { 12895 ash_msg_and_raise_error("illegal mode: %s", modestr); 12896 } 12897 if (!isdigit(modestr[0])) 12898 mask ^= 0777; 12899 umask(mask); 12929 12900 } 12930 12901 return 0; … … 13005 12976 } 13006 12977 13007 setvar("PPID", utoa(getppid()), 0); 13008 12978 setvar0("PPID", utoa(getppid())); 12979 #if ENABLE_ASH_BASH_COMPAT 12980 p = lookupvar("SHLVL"); 12981 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); 12982 if (!lookupvar("HOSTNAME")) { 12983 struct utsname uts; 12984 uname(&uts); 12985 setvar0("HOSTNAME", uts.nodename); 12986 } 12987 #endif 13009 12988 p = lookupvar("PWD"); 13010 12989 if (p) { … … 13185 13164 } 13186 13165 if (e == EXINT) { 13187 outcslow('\n',stderr);13166 newline_and_flush(stderr); 13188 13167 } 13189 13168 … … 13210 13189 procargs(argv); 13211 13190 13212 #if ENABLE_FEATURE_EDITING_SAVEHISTORY13213 if (iflag) {13214 const char *hp = lookupvar("HISTFILE");13215 if (!hp) {13216 hp = lookupvar("HOME");13217 if (hp) {13218 char *defhp = concat_path_file(hp, ".ash_history");13219 setvar("HISTFILE", defhp, 0);13220 free(defhp);13221 }13222 }13223 }13224 #endif13225 13191 if (argv[0] && argv[0][0] == '-') 13226 13192 isloginsh = 1; 13227 13193 if (isloginsh) { 13194 const char *hp; 13195 13228 13196 state = 1; 13229 13197 read_profile("/etc/profile"); 13230 13198 state1: 13231 13199 state = 2; 13232 read_profile(".profile"); 13200 hp = lookupvar("HOME"); 13201 if (hp) { 13202 hp = concat_path_file(hp, ".profile"); 13203 read_profile(hp); 13204 free((char*)hp); 13205 } 13233 13206 } 13234 13207 state2: … … 13262 13235 if (iflag) { 13263 13236 const char *hp = lookupvar("HISTFILE"); 13237 if (!hp) { 13238 hp = lookupvar("HOME"); 13239 if (hp) { 13240 hp = concat_path_file(hp, ".ash_history"); 13241 setvar0("HISTFILE", hp); 13242 free((char*)hp); 13243 hp = lookupvar("HISTFILE"); 13244 } 13245 } 13264 13246 if (hp) 13265 13247 line_input_state->hist_file = hp;
Note:
See TracChangeset
for help on using the changeset viewer.