OSDN Git Service

Upgrade to mksh 50.
[android-x86/external-mksh.git] / src / funcs.c
index e23ec8b..77d9494 100644 (file)
@@ -1,11 +1,11 @@
-/*     $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */
-/*     $OpenBSD: c_sh.c,v 1.41 2010/03/27 09:10:01 jmc Exp $   */
+/*     $OpenBSD: c_ksh.c,v 1.34 2013/12/17 16:37:05 deraadt Exp $      */
+/*     $OpenBSD: c_sh.c,v 1.44 2013/09/04 15:49:18 millert Exp $       */
 /*     $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $        */
-/*     $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $   */
+/*     $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $   */
 
 /*-
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- *              2010, 2011, 2012, 2013
+ *              2010, 2011, 2012, 2013, 2014
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -38,7 +38,7 @@
 #endif
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.238 2013/02/18 22:47:32 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.256 2014/06/09 13:25:52 tg Exp $");
 
 #if HAVE_KILLPG
 /*
@@ -60,6 +60,10 @@ __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.238 2013/02/18 22:47:32 tg Exp $");
 #define c_ulimit       c_true
 #endif
 
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+static int c_suspend(const char **);
+#endif
+
 /* getn() that prints error */
 static int
 bi_getn(const char *as, int *ai)
@@ -84,70 +88,72 @@ c_false(const char **wp MKSH_A_UNUSED)
 }
 
 /*
- * A leading = means assignments before command are kept;
- * a leading * means a POSIX special builtin;
- * a leading + means a POSIX regular builtin
- * (* and + should not be combined).
+ * A leading = means assignments before command are kept.
+ * A leading * means a POSIX special builtin.
  */
 const struct builtin mkshbuiltins[] = {
        {"*=.", c_dot},
        {"*=:", c_true},
        {"[", c_test},
+       /* no =: AT&T manual wrong */
+       {Talias, c_alias},
        {"*=break", c_brkcont},
        {Tgbuiltin, c_builtin},
+       {"cat", c_cat},
+       {"cd", c_cd},
+       /* dash compatibility hack */
+       {"chdir", c_cd},
+       {"command", c_command},
        {"*=continue", c_brkcont},
+       {"echo", c_print},
        {"*=eval", c_eval},
        {"*=exec", c_exec},
        {"*=exit", c_exitreturn},
-       {"+false", c_false},
-       {"*=return", c_exitreturn},
-       {Tsgset, c_set},
-       {"*=shift", c_shift},
-       {"=times", c_times},
-       {"*=trap", c_trap},
-       {"+=wait", c_wait},
-       {"+read", c_read},
-       {"test", c_test},
-       {"+true", c_true},
-       {"ulimit", c_ulimit},
-       {"+umask", c_umask},
-       {Tsgunset, c_unset},
-       /* no =: AT&T manual wrong */
-       {Tpalias, c_alias},
-       {"+cd", c_cd},
-       /* dash compatibility hack */
-       {"chdir", c_cd},
-       {"+command", c_command},
-       {"echo", c_print},
        {Tsgexport, c_typeset},
-       {"+fc", c_fc},
-       {"+getopts", c_getopts},
+       {"false", c_false},
+       {"fc", c_fc},
+       {"getopts", c_getopts},
        {"=global", c_typeset},
-       {"+jobs", c_jobs},
-       {"+kill", c_kill},
+       {"jobs", c_jobs},
+       {"kill", c_kill},
        {"let", c_let},
+       {"let]", c_let},
        {"print", c_print},
-#ifdef MKSH_PRINTF_BUILTIN
-       {"printf", c_printf},
-#endif
        {"pwd", c_pwd},
+       {"read", c_read},
        {Tsgreadonly, c_typeset},
+       {"realpath", c_realpath},
+       {"rename", c_rename},
+       {"*=return", c_exitreturn},
+       {Tsgset, c_set},
+       {"*=shift", c_shift},
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+       {"suspend", c_suspend},
+#endif
+       {"test", c_test},
+       {"*=times", c_times},
+       {"*=trap", c_trap},
+       {"true", c_true},
        {T_typeset, c_typeset},
-       {Tpunalias, c_unalias},
+       {"ulimit", c_ulimit},
+       {"umask", c_umask},
+       {Tunalias, c_unalias},
+       {Tsgunset, c_unset},
+       {"=wait", c_wait},
        {"whence", c_whence},
 #ifndef MKSH_UNEMPLOYED
-       {"+bg", c_fgbg},
-       {"+fg", c_fgbg},
+       {"bg", c_fgbg},
+       {"fg", c_fgbg},
 #endif
 #ifndef MKSH_NO_CMDLINE_EDITING
        {"bind", c_bind},
 #endif
-       {"cat", c_cat},
 #if HAVE_MKNOD
        {"mknod", c_mknod},
 #endif
-       {"realpath", c_realpath},
-       {"rename", c_rename},
+#ifdef MKSH_PRINTF_BUILTIN
+       {"printf", c_printf},
+#endif
 #if HAVE_SELECT
        {"sleep", c_sleep},
 #endif
@@ -642,6 +648,7 @@ c_typeset(const char **wp)
        const char *opts;
        const char *fieldstr = NULL, *basestr = NULL;
        bool localv = false, func = false, pflag = false, istset = true;
+       enum namerefflag new_refflag = SRF_NOP;
 
        switch (**wp) {
 
@@ -722,7 +729,7 @@ c_typeset(const char **wp)
                        flag = LCASEV;
                        break;
                case 'n':
-                       set_refflag = (builtin_opt.info & GI_PLUS) ?
+                       new_refflag = (builtin_opt.info & GI_PLUS) ?
                            SRF_DISABLE : SRF_ENABLE;
                        break;
                /* export, readonly: POSIX -p flag */
@@ -746,8 +753,6 @@ c_typeset(const char **wp)
                        flag = EXPORT;
                        break;
                case '?':
- errout:
-                       set_refflag = SRF_NOP;
                        return (1);
                }
                if (builtin_opt.info & GI_PLUS) {
@@ -762,10 +767,10 @@ c_typeset(const char **wp)
        }
 
        if (fieldstr && !bi_getn(fieldstr, &field))
-               goto errout;
+               return (1);
        if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) {
                bi_errorf("%s: %s", "bad integer base", basestr);
-               goto errout;
+               return (1);
        }
 
        if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
@@ -777,9 +782,9 @@ c_typeset(const char **wp)
        }
 
        if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) ||
-           set_refflag != SRF_NOP)) {
+           new_refflag != SRF_NOP)) {
                bi_errorf("only -t, -u and -x options may be used with -f");
-               goto errout;
+               return (1);
        }
        if (wp[builtin_opt.optind]) {
                /*
@@ -803,10 +808,18 @@ c_typeset(const char **wp)
                 * are also set in this command
                 */
                if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV |
-                   INTEGER | INT_U | INT_L)) || set_refflag != SRF_NOP)
+                   INTEGER | INT_U | INT_L)) || new_refflag != SRF_NOP)
                        fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL |
                            LCASEV | INTEGER | INT_U | INT_L);
        }
+       if (new_refflag != SRF_NOP) {
+               fclr &= ~(ARRAY | ASSOC);
+               fset &= ~(ARRAY | ASSOC);
+               fclr |= EXPORT;
+               fset |= ASSOC;
+               if (new_refflag == SRF_DISABLE)
+                       fclr |= ASSOC;
+       }
 
        /* set variables and attributes */
        if (wp[builtin_opt.optind] &&
@@ -836,15 +849,13 @@ c_typeset(const char **wp)
                                        shf_putc('\n', shl_stdout);
                                }
                        } else if (!typeset(wp[i], fset, fclr, field, base)) {
-                               bi_errorf("%s: %s", wp[i], "not identifier");
-                               goto errout;
+                               bi_errorf("%s: %s", wp[i], "is not an identifier");
+                               return (1);
                        }
                }
-               set_refflag = SRF_NOP;
                return (rv);
        }
 
-       set_refflag = SRF_NOP;
        /* list variables and attributes */
 
        /* no difference at this point.. */
@@ -1346,8 +1357,10 @@ c_kill(const char **wp)
                        for (; wp[i]; i++) {
                                if (!bi_getn(wp[i], &n))
                                        return (1);
+#if (NSIG < 128)
                                if (n > 128 && n < 128 + NSIG)
                                        n -= 128;
+#endif
                                if (n > 0 && n < NSIG)
                                        shprintf("%s\n", sigtraps[n].name);
                                else
@@ -2253,7 +2266,7 @@ c_trap(const char **wp)
        wp += builtin_opt.optind;
 
        if (*wp == NULL) {
-               for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
+               for (p = sigtraps, i = NSIG + 1; --i >= 0; p++)
                        if (p->trap != NULL) {
                                shf_puts("trap -- ", shl_stdout);
                                print_value_quoted(shl_stdout, p->trap);
@@ -2427,12 +2440,13 @@ c_set(const char **wp)
         * which assumes the exit value set will be that of the $()
         * (subst_exstat is cleared in execute() so that it will be 0
         * if there are no command substitutions).
-        * Switched ksh (!posix !sh) to POSIX in mksh R39b.
         */
 #ifdef MKSH_LEGACY_MODE
-       return (subst_exstat);
+       /* traditional behaviour, unless set -o posix */
+       return (Flag(FPOSIX) ? 0 : subst_exstat);
 #else
-       return (Flag(FSH) ? subst_exstat : 0);
+       /* conformant behaviour, unless set -o sh +o posix */
+       return (Flag(FSH) && !Flag(FPOSIX) ? subst_exstat : 0);
 #endif
 }
 
@@ -3333,16 +3347,6 @@ ptest_error(Test_env *te, int ofs, const char *msg)
 #define SOFT   0x1
 #define HARD   0x2
 
-struct limits {
-       const char *name;
-       int resource;           /* resource to get/set */
-       unsigned int factor;    /* multiply by to get rlim_{cur,max} values */
-       char option;
-};
-
-static void print_ulimit(const struct limits *, int);
-static int set_ulimit(const struct limits *, const char *, int);
-
 /* Magic to divine the 'm' and 'v' limits */
 
 #ifdef RLIMIT_AS
@@ -3385,165 +3389,38 @@ static int set_ulimit(const struct limits *, const char *, int);
 #undef ULIMIT_M_IS_VMEM
 #endif
 
+#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
+# error nonsensical m ulimit
+#endif
+
+#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
+# error nonsensical v ulimit
+#endif
+
+#define RLIMITS_DEFNS
+#include "rlimits.gen"
+
+static void print_ulimit(const struct limits *, int);
+static int set_ulimit(const struct limits *, const char *, int);
+
+static const struct limits * const rlimits[] = {
+#define RLIMITS_ITEMS
+#include "rlimits.gen"
+};
+
+static const char rlimits_opts[] =
+#define RLIMITS_OPTCS
+#include "rlimits.gen"
+    ;
 
 int
 c_ulimit(const char **wp)
 {
-       static const struct limits limits[] = {
-               /* do not use options -H, -S or -a or change the order */
-#ifdef RLIMIT_CPU
-               { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
-#endif
-#ifdef RLIMIT_FSIZE
-               { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
-#endif
-#ifdef RLIMIT_CORE
-               { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
-#endif
-#ifdef RLIMIT_DATA
-               { "data(KiB)", RLIMIT_DATA, 1024, 'd' },
-#endif
-#ifdef RLIMIT_STACK
-               { "stack(KiB)", RLIMIT_STACK, 1024, 's' },
-#endif
-#ifdef RLIMIT_MEMLOCK
-               { "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' },
-#endif
-#ifdef RLIMIT_NOFILE
-               { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
-#endif
-#ifdef RLIMIT_NPROC
-               { "processes", RLIMIT_NPROC, 1, 'p' },
-#endif
-#ifdef RLIMIT_SWAP
-               { "swap(KiB)", RLIMIT_SWAP, 1024, 'w' },
-#endif
-#ifdef RLIMIT_LOCKS
-               { "flocks", RLIMIT_LOCKS, -1, 'L' },
-#endif
-#ifdef RLIMIT_TIME
-               { "humantime(seconds)", RLIMIT_TIME, 1, 'T' },
-#endif
-#ifdef RLIMIT_NOVMON
-               { "vnodemonitors", RLIMIT_NOVMON, 1, 'V' },
-#endif
-#ifdef RLIMIT_SIGPENDING
-               { "sigpending", RLIMIT_SIGPENDING, 1, 'i' },
-#endif
-#ifdef RLIMIT_MSGQUEUE
-               { "msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q' },
-#endif
-#ifdef RLIMIT_AIO_MEM
-               { "AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M' },
-#endif
-#ifdef RLIMIT_AIO_OPS
-               { "AIOoperations", RLIMIT_AIO_OPS, 1, 'O' },
-#endif
-#ifdef RLIMIT_TCACHE
-               { "cachedthreads", RLIMIT_TCACHE, 1, 'C' },
-#endif
-#ifdef RLIMIT_SBSIZE
-               { "sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B' },
-#endif
-#ifdef RLIMIT_PTHREAD
-               { "threadsperprocess", RLIMIT_PTHREAD, 1, 'P' },
-#endif
-#ifdef RLIMIT_NICE
-               { "maxnice", RLIMIT_NICE, 1, 'e' },
-#endif
-#ifdef RLIMIT_RTPRIO
-               { "maxrtprio", RLIMIT_RTPRIO, 1, 'r' },
-#endif
-#if defined(ULIMIT_M_IS_RSS)
-               { "resident-set(KiB)", RLIMIT_RSS, 1024, 'm' },
-#elif defined(ULIMIT_M_IS_VMEM)
-               { "memory(KiB)", RLIMIT_VMEM, 1024, 'm' },
-#endif
-#if defined(ULIMIT_V_IS_VMEM)
-               { "virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v' },
-#elif defined(ULIMIT_V_IS_AS)
-               { "address-space(KiB)", RLIMIT_AS, 1024, 'v' },
-#endif
-               { NULL, 0, 0, 0 }
-       };
-       static const char opts[] = "a"
-#ifdef RLIMIT_SBSIZE
-           "B"
-#endif
-#ifdef RLIMIT_TCACHE
-           "C"
-#endif
-#ifdef RLIMIT_CORE
-           "c"
-#endif
-#ifdef RLIMIT_DATA
-           "d"
-#endif
-#ifdef RLIMIT_NICE
-           "e"
-#endif
-#ifdef RLIMIT_FSIZE
-           "f"
-#endif
-           "H"
-#ifdef RLIMIT_SIGPENDING
-           "i"
-#endif
-#ifdef RLIMIT_LOCKS
-           "L"
-#endif
-#ifdef RLIMIT_MEMLOCK
-           "l"
-#endif
-#ifdef RLIMIT_AIO_MEM
-           "M"
-#endif
-#if defined(ULIMIT_M_IS_RSS) || defined(ULIMIT_M_IS_VMEM)
-           "m"
-#endif
-#ifdef RLIMIT_NOFILE
-           "n"
-#endif
-#ifdef RLIMIT_AIO_OPS
-           "O"
-#endif
-#ifdef RLIMIT_PTHREAD
-           "P"
-#endif
-#ifdef RLIMIT_NPROC
-           "p"
-#endif
-#ifdef RLIMIT_MSGQUEUE
-           "q"
-#endif
-#ifdef RLIMIT_RTPRIO
-           "r"
-#endif
-           "S"
-#ifdef RLIMIT_STACK
-           "s"
-#endif
-#ifdef RLIMIT_TIME
-           "T"
-#endif
-#ifdef RLIMIT_CPU
-           "t"
-#endif
-#ifdef RLIMIT_NOVMON
-           "V"
-#endif
-#if defined(ULIMIT_V_IS_VMEM) || defined(ULIMIT_V_IS_AS)
-           "v"
-#endif
-#ifdef RLIMIT_SWAP
-           "w"
-#endif
-           ;
+       size_t i = 0;
        int how = SOFT | HARD, optc, what = 'f';
        bool all = false;
-       const struct limits *l;
 
-       while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
+       while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
                switch (optc) {
                case 'H':
                        how = HARD;
@@ -3555,31 +3432,32 @@ c_ulimit(const char **wp)
                        all = true;
                        break;
                case '?':
-                       bi_errorf("usage: ulimit [-%s] [value]", opts);
+                       bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
                        return (1);
                default:
                        what = optc;
                }
 
-       for (l = limits; l->name && l->option != what; l++)
-               ;
-       if (!l->name) {
-               internal_warningf("ulimit: %c", what);
-               return (1);
+       while (i < NELEM(rlimits)) {
+               if (rlimits[i]->optchar == what)
+                       goto found;
+               ++i;
        }
-
+       internal_warningf("ulimit: %c", what);
+       return (1);
+ found:
        if (wp[builtin_opt.optind]) {
                if (all || wp[builtin_opt.optind + 1]) {
                        bi_errorf("too many arguments");
                        return (1);
                }
-               return (set_ulimit(l, wp[builtin_opt.optind], how));
+               return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
        }
        if (!all)
-               print_ulimit(l, how);
-       else for (l = limits; l->name; l++) {
-               shprintf("%-20s ", l->name);
-               print_ulimit(l, how);
+               print_ulimit(rlimits[i], how);
+       else for (i = 0; i < NELEM(rlimits); ++i) {
+               shprintf("%-20s ", rlimits[i]->name);
+               print_ulimit(rlimits[i], how);
        }
        return (0);
 }
@@ -3611,7 +3489,11 @@ set_ulimit(const struct limits *l, const char *v, int how)
        }
 
        if (getrlimit(l->resource, &limit) < 0) {
-               /* some can't be read, e.g. Linux RLIMIT_LOCKS */
+#ifndef MKSH_SMALL
+               bi_errorf("limit %s could not be read, contact the mksh developers: %s",
+                   l->name, cstrerror(errno));
+#endif
+               /* some can't be read */
                limit.rlim_cur = RLIM_INFINITY;
                limit.rlim_max = RLIM_INFINITY;
        }
@@ -3726,7 +3608,7 @@ c_cat(const char **wp)
        rv = 0;
 
        if ((buf = malloc_osfunc(MKSH_CAT_BUFSIZ)) == NULL) {
-               bi_errorf(Toomem, (unsigned long)MKSH_CAT_BUFSIZ);
+               bi_errorf(Toomem, (size_t)MKSH_CAT_BUFSIZ);
                return (1);
        }
 
@@ -3735,7 +3617,7 @@ c_cat(const char **wp)
                        fn = *wp++;
                        if (fn[0] == '-' && fn[1] == '\0')
                                fd = STDIN_FILENO;
-                       else if ((fd = open(fn, O_RDONLY)) < 0) {
+                       else if ((fd = open(fn, O_RDONLY | O_BINARY)) < 0) {
                                eno = errno;
                                bi_errorf("%s: %s", fn, cstrerror(eno));
                                rv = 1;
@@ -3842,3 +3724,24 @@ c_sleep(const char **wp)
        return (rv);
 }
 #endif
+
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+static int
+c_suspend(const char **wp)
+{
+       if (wp[1] != NULL) {
+               bi_errorf("too many arguments");
+               return (1);
+       }
+       if (Flag(FLOGIN)) {
+               /* Can't suspend an orphaned process group. */
+               if (getpgid(kshppid) == getpgid(0) ||
+                   getsid(kshppid) != getsid(0)) {
+                       bi_errorf("can't suspend a login shell");
+                       return (1);
+               }
+       }
+       j_suspend();
+       return (0);
+}
+#endif