aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c152
1 files changed, 110 insertions, 42 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 6a572cbc3..ac1ae05fc 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -215,6 +215,9 @@
215#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT 215#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
216#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT 216#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
217#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT 217#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
218#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
219#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
220#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
218 221
219#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 222#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
220/* Bionic at least up to version 24 has no glob() */ 223/* Bionic at least up to version 24 has no glob() */
@@ -452,7 +455,7 @@ struct globals_misc {
452#define S_DFL 1 /* default signal handling (SIG_DFL) */ 455#define S_DFL 1 /* default signal handling (SIG_DFL) */
453#define S_CATCH 2 /* signal is caught */ 456#define S_CATCH 2 /* signal is caught */
454#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 457#define S_IGN 3 /* signal is ignored (SIG_IGN) */
455#define S_HARD_IGN 4 /* signal is ignored permanently */ 458#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
456 459
457 /* indicates specified signal received */ 460 /* indicates specified signal received */
458 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 461 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
@@ -1313,6 +1316,10 @@ struct strpush {
1313 int unget; 1316 int unget;
1314}; 1317};
1315 1318
1319/*
1320 * The parsefile structure pointed to by the global variable parsefile
1321 * contains information about the current file being read.
1322 */
1316struct parsefile { 1323struct parsefile {
1317 struct parsefile *prev; /* preceding file on stack */ 1324 struct parsefile *prev; /* preceding file on stack */
1318 int linno; /* current line */ 1325 int linno; /* current line */
@@ -1986,10 +1993,6 @@ nextopt(const char *optstring)
1986 1993
1987/* ============ Shell variables */ 1994/* ============ Shell variables */
1988 1995
1989/*
1990 * The parsefile structure pointed to by the global variable parsefile
1991 * contains information about the current file being read.
1992 */
1993struct shparam { 1996struct shparam {
1994 int nparam; /* # of positional parameters (without $0) */ 1997 int nparam; /* # of positional parameters (without $0) */
1995#if ENABLE_ASH_GETOPTS 1998#if ENABLE_ASH_GETOPTS
@@ -2183,7 +2186,9 @@ extern struct globals_var *const ash_ptr_to_globals_var;
2183static void FAST_FUNC 2186static void FAST_FUNC
2184getoptsreset(const char *value) 2187getoptsreset(const char *value)
2185{ 2188{
2186 shellparam.optind = number(value) ?: 1; 2189 shellparam.optind = 1;
2190 if (is_number(value))
2191 shellparam.optind = number(value) ?: 1;
2187 shellparam.optoff = -1; 2192 shellparam.optoff = -1;
2188} 2193}
2189#endif 2194#endif
@@ -3751,9 +3756,12 @@ setsignal(int signo)
3751#endif 3756#endif
3752 } 3757 }
3753 } 3758 }
3754//TODO: if !rootshell, we reset SIGQUIT to DFL, 3759 /* if !rootshell, we reset SIGQUIT to DFL,
3755//whereas we have to restore it to what shell got on entry 3760 * whereas we have to restore it to what shell got on entry.
3756//from the parent. See comment above 3761 * This is handled by the fact that if signal was IGNored on entry,
3762 * then cur_act is S_HARD_IGN and we never change its sigaction
3763 * (see code below).
3764 */
3757 3765
3758 if (signo == SIGCHLD) 3766 if (signo == SIGCHLD)
3759 new_act = S_CATCH; 3767 new_act = S_CATCH;
@@ -3777,10 +3785,18 @@ setsignal(int signo)
3777 cur_act = S_IGN; /* don't hard ignore these */ 3785 cur_act = S_IGN; /* don't hard ignore these */
3778 } 3786 }
3779 } 3787 }
3788 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3789 /* installing SIG_DFL over SIG_DFL is a no-op */
3790 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3791 *t = S_DFL;
3792 return;
3793 }
3780 } 3794 }
3781 if (cur_act == S_HARD_IGN || cur_act == new_act) 3795 if (cur_act == S_HARD_IGN || cur_act == new_act)
3782 return; 3796 return;
3783 3797
3798 *t = new_act;
3799
3784 act.sa_handler = SIG_DFL; 3800 act.sa_handler = SIG_DFL;
3785 switch (new_act) { 3801 switch (new_act) {
3786 case S_CATCH: 3802 case S_CATCH:
@@ -3790,16 +3806,13 @@ setsignal(int signo)
3790 act.sa_handler = SIG_IGN; 3806 act.sa_handler = SIG_IGN;
3791 break; 3807 break;
3792 } 3808 }
3793
3794 /* flags and mask matter only if !DFL and !IGN, but we do it 3809 /* flags and mask matter only if !DFL and !IGN, but we do it
3795 * for all cases for more deterministic behavior: 3810 * for all cases for more deterministic behavior:
3796 */ 3811 */
3797 act.sa_flags = 0; 3812 act.sa_flags = 0; //TODO: why not SA_RESTART?
3798 sigfillset(&act.sa_mask); 3813 sigfillset(&act.sa_mask);
3799 3814
3800 sigaction_set(signo, &act); 3815 sigaction_set(signo, &act);
3801
3802 *t = new_act;
3803} 3816}
3804#else 3817#else
3805#define setsignal(s) 3818#define setsignal(s)
@@ -5915,12 +5928,10 @@ static void
5915redirect(union node *redir, int flags) 5928redirect(union node *redir, int flags)
5916{ 5929{
5917 struct redirtab *sv; 5930 struct redirtab *sv;
5918 int sv_pos;
5919 5931
5920 if (!redir) 5932 if (!redir)
5921 return; 5933 return;
5922 5934
5923 sv_pos = 0;
5924 sv = NULL; 5935 sv = NULL;
5925 INT_OFF; 5936 INT_OFF;
5926 if (flags & REDIR_PUSH) 5937 if (flags & REDIR_PUSH)
@@ -8076,8 +8087,9 @@ static int
8076patmatch(char *pattern, const char *string) 8087patmatch(char *pattern, const char *string)
8077{ 8088{
8078 char *p = preglob(pattern, 0); 8089 char *p = preglob(pattern, 0);
8079 //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string); 8090 int r = pmatch(p, string);
8080 return pmatch(p, string); 8091 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
8092 return r;
8081} 8093}
8082 8094
8083/* 8095/*
@@ -8179,7 +8191,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c
8179 while (*envp) 8191 while (*envp)
8180 putenv(*envp++); 8192 putenv(*envp++);
8181 popredir(/*drop:*/ 1); 8193 popredir(/*drop:*/ 1);
8182 run_applet_no_and_exit(applet_no, cmd, argv); 8194 run_noexec_applet_and_exit(applet_no, cmd, argv);
8183 } 8195 }
8184 /* re-exec ourselves with the new arguments */ 8196 /* re-exec ourselves with the new arguments */
8185 execve(bb_busybox_exec_path, argv, envp); 8197 execve(bb_busybox_exec_path, argv, envp);
@@ -10250,6 +10262,15 @@ evalcommand(union node *cmd, int flags)
10250 expredir(cmd->ncmd.redirect); 10262 expredir(cmd->ncmd.redirect);
10251 redir_stop = pushredir(cmd->ncmd.redirect); 10263 redir_stop = pushredir(cmd->ncmd.redirect);
10252 preverrout_fd = 2; 10264 preverrout_fd = 2;
10265 if (BASH_XTRACEFD && xflag) {
10266 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10267 * we do not emulate this. We only use its value.
10268 */
10269 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10270 if (xtracefd && is_number(xtracefd))
10271 preverrout_fd = atoi(xtracefd);
10272
10273 }
10253 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 10274 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10254 10275
10255 path = vpath.var_text; 10276 path = vpath.var_text;
@@ -10383,12 +10404,30 @@ evalcommand(union node *cmd, int flags)
10383#endif 10404#endif
10384 ) { 10405 ) {
10385 listsetvar(varlist.list, VEXPORT|VSTACK); 10406 listsetvar(varlist.list, VEXPORT|VSTACK);
10386 /* run <applet>_main() */ 10407 /*
10408 * Run <applet>_main().
10409 * Signals (^C) can't interrupt here.
10410 * Otherwise we can mangle stdio or malloc internal state.
10411 * This makes applets which can run for a long time
10412 * and/or wait for user input ineligible for NOFORK:
10413 * for example, "yes" or "rm" (rm -i waits for input).
10414 */
10415 INT_OFF;
10387 status = run_nofork_applet(applet_no, argv); 10416 status = run_nofork_applet(applet_no, argv);
10417 /*
10418 * Try enabling NOFORK for "yes" applet.
10419 * ^C _will_ stop it (write returns EINTR),
10420 * but this causes stdout FILE to be stuck
10421 * and needing clearerr(). What if other applets
10422 * also can get EINTRs? Do we need to switch
10423 * our signals to SA_RESTART?
10424 */
10425 /*clearerr(stdout);*/
10426 INT_ON;
10388 break; 10427 break;
10389 } 10428 }
10390#endif 10429#endif
10391 /* Can we avoid forking off? For example, very last command 10430 /* Can we avoid forking? For example, very last command
10392 * in a script or a subshell does not need forking, 10431 * in a script or a subshell does not need forking,
10393 * we can just exec it. 10432 * we can just exec it.
10394 */ 10433 */
@@ -10674,8 +10713,8 @@ preadfd(void)
10674 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 10713 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10675 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 10714 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10676 else { 10715 else {
10677 int timeout = -1;
10678# if ENABLE_ASH_IDLE_TIMEOUT 10716# if ENABLE_ASH_IDLE_TIMEOUT
10717 int timeout = -1;
10679 if (iflag) { 10718 if (iflag) {
10680 const char *tmout_var = lookupvar("TMOUT"); 10719 const char *tmout_var = lookupvar("TMOUT");
10681 if (tmout_var) { 10720 if (tmout_var) {
@@ -10684,12 +10723,13 @@ preadfd(void)
10684 timeout = -1; 10723 timeout = -1;
10685 } 10724 }
10686 } 10725 }
10726 line_input_state->timeout = timeout;
10687# endif 10727# endif
10688# if ENABLE_FEATURE_TAB_COMPLETION 10728# if ENABLE_FEATURE_TAB_COMPLETION
10689 line_input_state->path_lookup = pathval(); 10729 line_input_state->path_lookup = pathval();
10690# endif 10730# endif
10691 reinit_unicode_for_ash(); 10731 reinit_unicode_for_ash();
10692 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); 10732 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10693 if (nr == 0) { 10733 if (nr == 0) {
10694 /* ^C pressed, "convert" to SIGINT */ 10734 /* ^C pressed, "convert" to SIGINT */
10695 write(STDOUT_FILENO, "^C", 2); 10735 write(STDOUT_FILENO, "^C", 2);
@@ -11399,6 +11439,7 @@ getopts(char *optstr, char *optvar, char **optfirst)
11399 p = *optnext; 11439 p = *optnext;
11400 if (p == NULL || *p != '-' || *++p == '\0') { 11440 if (p == NULL || *p != '-' || *++p == '\0') {
11401 atend: 11441 atend:
11442 unsetvar("OPTARG");
11402 p = NULL; 11443 p = NULL;
11403 done = 1; 11444 done = 1;
11404 goto out; 11445 goto out;
@@ -11411,7 +11452,11 @@ getopts(char *optstr, char *optvar, char **optfirst)
11411 c = *p++; 11452 c = *p++;
11412 for (q = optstr; *q != c;) { 11453 for (q = optstr; *q != c;) {
11413 if (*q == '\0') { 11454 if (*q == '\0') {
11414 if (optstr[0] == ':') { 11455 /* OPTERR is a bashism */
11456 const char *cp = lookupvar("OPTERR");
11457 if ((cp && LONE_CHAR(cp, '0'))
11458 || (optstr[0] == ':')
11459 ) {
11415 sbuf[0] = c; 11460 sbuf[0] = c;
11416 /*sbuf[1] = '\0'; - already is */ 11461 /*sbuf[1] = '\0'; - already is */
11417 setvar0("OPTARG", sbuf); 11462 setvar0("OPTARG", sbuf);
@@ -11428,7 +11473,11 @@ getopts(char *optstr, char *optvar, char **optfirst)
11428 11473
11429 if (*++q == ':') { 11474 if (*++q == ':') {
11430 if (*p == '\0' && (p = *optnext) == NULL) { 11475 if (*p == '\0' && (p = *optnext) == NULL) {
11431 if (optstr[0] == ':') { 11476 /* OPTERR is a bashism */
11477 const char *cp = lookupvar("OPTERR");
11478 if ((cp && LONE_CHAR(cp, '0'))
11479 || (optstr[0] == ':')
11480 ) {
11432 sbuf[0] = c; 11481 sbuf[0] = c;
11433 /*sbuf[1] = '\0'; - already is */ 11482 /*sbuf[1] = '\0'; - already is */
11434 setvar0("OPTARG", sbuf); 11483 setvar0("OPTARG", sbuf);
@@ -12571,7 +12620,7 @@ parsesub: {
12571 STPUTC(c, out); 12620 STPUTC(c, out);
12572 c = pgetc_eatbnl(); 12621 c = pgetc_eatbnl();
12573 } while (isdigit(c)); 12622 } while (isdigit(c));
12574 } else if (is_special(c)) { 12623 } else {
12575 /* $[{[#]]<specialchar>[}] */ 12624 /* $[{[#]]<specialchar>[}] */
12576 int cc = c; 12625 int cc = c;
12577 12626
@@ -12589,10 +12638,16 @@ parsesub: {
12589 cc = '#'; 12638 cc = '#';
12590 } 12639 }
12591 } 12640 }
12641
12642 if (!is_special(cc)) {
12643 if (subtype == VSLENGTH)
12644 subtype = 0;
12645 goto badsub;
12646 }
12647
12592 USTPUTC(cc, out); 12648 USTPUTC(cc, out);
12593 } else {
12594 goto badsub;
12595 } 12649 }
12650
12596 if (c != '}' && subtype == VSLENGTH) { 12651 if (c != '}' && subtype == VSLENGTH) {
12597 /* ${#VAR didn't end with } */ 12652 /* ${#VAR didn't end with } */
12598 goto badsub; 12653 goto badsub;
@@ -13850,21 +13905,23 @@ static const unsigned char timescmd_str[] ALIGN1 = {
13850static int FAST_FUNC 13905static int FAST_FUNC
13851timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 13906timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13852{ 13907{
13853 unsigned long clk_tck, s, t; 13908 unsigned clk_tck;
13854 const unsigned char *p; 13909 const unsigned char *p;
13855 struct tms buf; 13910 struct tms buf;
13856 13911
13857 clk_tck = bb_clk_tck(); 13912 clk_tck = bb_clk_tck();
13858 times(&buf);
13859 13913
13914 times(&buf);
13860 p = timescmd_str; 13915 p = timescmd_str;
13861 do { 13916 do {
13917 unsigned sec, frac;
13918 unsigned long t;
13862 t = *(clock_t *)(((char *) &buf) + p[1]); 13919 t = *(clock_t *)(((char *) &buf) + p[1]);
13863 s = t / clk_tck; 13920 sec = t / clk_tck;
13864 t = t % clk_tck; 13921 frac = t % clk_tck;
13865 out1fmt("%lum%lu.%03lus%c", 13922 out1fmt("%um%u.%03us%c",
13866 s / 60, s % 60, 13923 sec / 60, sec % 60,
13867 (t * 1000) / clk_tck, 13924 (frac * 1000) / clk_tck,
13868 p[0]); 13925 p[0]);
13869 p += 2; 13926 p += 2;
13870 } while (*p); 13927 } while (*p);
@@ -13903,10 +13960,10 @@ letcmd(int argc UNUSED_PARAM, char **argv)
13903 * -p PROMPT Display PROMPT on stderr (if input is from tty) 13960 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13904 * -t SECONDS Timeout after SECONDS (tty or pipe only) 13961 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13905 * -u FD Read from given FD instead of fd 0 13962 * -u FD Read from given FD instead of fd 0
13963 * -d DELIM End on DELIM char, not newline
13906 * This uses unbuffered input, which may be avoidable in some cases. 13964 * This uses unbuffered input, which may be avoidable in some cases.
13907 * TODO: bash also has: 13965 * TODO: bash also has:
13908 * -a ARRAY Read into array[0],[1],etc 13966 * -a ARRAY Read into array[0],[1],etc
13909 * -d DELIM End on DELIM char, not newline
13910 * -e Use line editing (tty only) 13967 * -e Use line editing (tty only)
13911 */ 13968 */
13912static int FAST_FUNC 13969static int FAST_FUNC
@@ -13916,11 +13973,12 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13916 char *opt_p = NULL; 13973 char *opt_p = NULL;
13917 char *opt_t = NULL; 13974 char *opt_t = NULL;
13918 char *opt_u = NULL; 13975 char *opt_u = NULL;
13976 char *opt_d = NULL; /* optimized out if !BASH */
13919 int read_flags = 0; 13977 int read_flags = 0;
13920 const char *r; 13978 const char *r;
13921 int i; 13979 int i;
13922 13980
13923 while ((i = nextopt("p:u:rt:n:s")) != '\0') { 13981 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
13924 switch (i) { 13982 switch (i) {
13925 case 'p': 13983 case 'p':
13926 opt_p = optionarg; 13984 opt_p = optionarg;
@@ -13940,6 +13998,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13940 case 'u': 13998 case 'u':
13941 opt_u = optionarg; 13999 opt_u = optionarg;
13942 break; 14000 break;
14001#if BASH_READ_D
14002 case 'd':
14003 opt_d = optionarg;
14004 break;
14005#endif
13943 default: 14006 default:
13944 break; 14007 break;
13945 } 14008 }
@@ -13957,12 +14020,15 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13957 opt_n, 14020 opt_n,
13958 opt_p, 14021 opt_p,
13959 opt_t, 14022 opt_t,
13960 opt_u 14023 opt_u,
14024 opt_d
13961 ); 14025 );
13962 INT_ON; 14026 INT_ON;
13963 14027
13964 if ((uintptr_t)r == 1 && errno == EINTR) { 14028 if ((uintptr_t)r == 1 && errno == EINTR) {
13965 /* to get SIGCHLD: sleep 1 & read x; echo $x */ 14029 /* To get SIGCHLD: sleep 1 & read x; echo $x
14030 * Correct behavior is to not exit "read"
14031 */
13966 if (pending_sig == 0) 14032 if (pending_sig == 0)
13967 goto again; 14033 goto again;
13968 } 14034 }
@@ -14077,7 +14143,8 @@ exitshell(void)
14077 /* NOTREACHED */ 14143 /* NOTREACHED */
14078} 14144}
14079 14145
14080static void 14146/* Don't inline: conserve stack of caller from having our locals too */
14147static NOINLINE void
14081#if ENABLE_PLATFORM_MINGW32 14148#if ENABLE_PLATFORM_MINGW32
14082init(int xp) 14149init(int xp)
14083#else 14150#else
@@ -14086,8 +14153,9 @@ init(void)
14086{ 14153{
14087 /* we will never free this */ 14154 /* we will never free this */
14088 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 14155 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
14156 basepf.linno = 1;
14089 14157
14090 sigmode[SIGCHLD - 1] = S_DFL; 14158 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14091 setsignal(SIGCHLD); 14159 setsignal(SIGCHLD);
14092 14160
14093 /* bash re-enables SIGHUP which is SIG_IGNed on entry. 14161 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
@@ -14098,7 +14166,6 @@ init(void)
14098 { 14166 {
14099 char **envp; 14167 char **envp;
14100 const char *p; 14168 const char *p;
14101 struct stat st1, st2;
14102 14169
14103 initvar(); 14170 initvar();
14104 14171
@@ -14204,6 +14271,7 @@ init(void)
14204#endif 14271#endif
14205 p = lookupvar("PWD"); 14272 p = lookupvar("PWD");
14206 if (p) { 14273 if (p) {
14274 struct stat st1, st2;
14207 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2) 14275 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14208 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino 14276 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14209 ) { 14277 ) {
@@ -15161,7 +15229,7 @@ sticky_free(void *base)
15161 * may be used to endorse or promote products derived from this software 15229 * may be used to endorse or promote products derived from this software
15162 * without specific prior written permission. 15230 * without specific prior written permission.
15163 * 15231 *
15164 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 15232 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
15165 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15233 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15166 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15234 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15167 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 15235 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE