summaryrefslogtreecommitdiff
path: root/src/cmd/ksh93/bltins/regress.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/cmd/ksh93/bltins/regress.c
downloadksh-3950ffe2a485479f6561c27364d3d7df5a21d124.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/cmd/ksh93/bltins/regress.c')
-rw-r--r--src/cmd/ksh93/bltins/regress.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/src/cmd/ksh93/bltins/regress.c b/src/cmd/ksh93/bltins/regress.c
new file mode 100644
index 0000000..25f3c25
--- /dev/null
+++ b/src/cmd/ksh93/bltins/regress.c
@@ -0,0 +1,343 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2012 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * regression test intercept control
+ * enable with SHOPT_REGRESS==1 in Makefile
+ * not for production use
+ * see --man for details
+ * all string constants inline here instead of in data/...
+ *
+ * David Korn
+ * at&t research
+ */
+
+#include "defs.h"
+
+#if SHOPT_REGRESS
+
+#include <error.h>
+#include <ls.h>
+#include "io.h"
+#include "builtins.h"
+#include <tmx.h>
+
+#define REGRESS_HEADER "ksh:REGRESS:"
+
+#define TRACE(r,i,f) sh_regress(REGRESS_##r, i, sfprints f, __LINE__, __FILE__)
+
+static const char usage[] =
+"[-1p0?\n@(#)$Id: __regress__ (AT&T Research) 2009-03-29 $\n]"
+USAGE_LICENSE
+"[+NAME?__regress__ - shell regression test intercept control]"
+"[+DESCRIPTION?\b__regress__\b controls the regression test intercepts "
+ "for shells compiled with SHOPT_REGRESS==1. Shells compiled this way are "
+ "for testing only. In addition to \b__regress__\b and the \b--regress\b "
+ "command line option, these shells may contain system library function "
+ "intercepts that behave different from the native counterparts.]"
+"[+?Each option controls a different test and possibly a different set "
+ "of intercepts. The options are interpreted \bdd\b(1) style -- '-' or "
+ "'--' prefix not required. This simplifies the specification of the "
+ "command line \b--regress\b=\avalue\a option, where \avalue\a is passed "
+ "as an option to the \b__regress__\b builtin. Typically regression test "
+ "intercepts are enabled with one or more command line \b--regress\b "
+ "options, with optional specific calls to \b__regress__\b in test "
+ "scripts to enable/disable intercepts as the test progresses.]"
+"[+?Each enabled intercept may result in trace lines of the form \b" REGRESS_HEADER
+ "\aoption\a:\aintercept\a:\ainfo\a on the standard error, where "
+ "\aoption\a is one of the options below, \aintercept\a is the name of "
+ "the specific intercept for \aoption\a, and \ainfo\a is \aoption\a "
+ "specific information. Unless noted otherwise, one regression test trace "
+ "line is produced each time an enabled intercept is called.]"
+"[101:egid?The intercept effective gid is set to \aoriginal-egid\a. The "
+ "effective gid of the underlying system process is not affected. The "
+ "trace line info is either \begid==rgid\b or \begid!=rgid\b. The "
+ "intercepts are:]#?[original-egid:=1]"
+ "{"
+ "[+getegid()?The intercept effecive gid is returned. The "
+ "\bsetgid\b() intercept may change this between the real gid and "
+ "\aoriginal-egid\a.]"
+ "[+setgid(gid)?Sets the intercept effective gid to \agid\a. "
+ "Fails if \agid\a is neither the real gid nor "
+ "\aoriginal-egid\a.]"
+ "}"
+"[102:euid?The intercept effective uid is set to \aoriginal-euid\a. The "
+ "effective uid of the underlying system process is not affected. The "
+ "trace line info is either \beuid==ruid\b or \beuid!=ruid\b. The "
+ "intercepts are:]#?[original-euid:=1]"
+ "{"
+ "[+geteuid()?The intercept effecive uid is returned. The "
+ "\bsetuid\b() intercept may change this between the real uid and "
+ "\aoriginal-euid\a.]"
+ "[+setuid(uid)?Sets the intercept effective uid to \auid\a. "
+ "Fails if \auid\a is neither the real uid nor "
+ "\aoriginal-euid\a.]"
+ "}"
+"[103:p_suid?Specifies a value for SHOPT_P_SUID. Effective uids greater "
+ "than the non-privileged-uid disable the priveleged mode. The intercepts "
+ "are:]#?[non-privileged-uid:=1]"
+ "{"
+ "[+SHOPT_P_SUID?The SHOPT_P_SUID macro value is overridden by "
+ "\bp_suid\b. A trace line is output for each SHOPT_P_SUID "
+ "access.]"
+ "}"
+"[104:source?The intercepts are:]"
+ "{"
+ "[+sh_source()?The trace line info is the path of the script "
+ "being sourced. Used to trace shell startup scripts.]"
+ "}"
+"[105:etc?Map file paths matching \b/etc/\b* to \aetc-dir\a/*. The "
+ "intercepts are:]:[etc-dir:=/etc]"
+ "{"
+ "[+sh_open()?Paths matching \b/etc/\b* are changed to "
+ "\aetc-dir\a/*.]"
+ "}"
+"[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)]"
+;
+
+static const char* regress_options[] =
+{
+ "ERROR",
+ "egid",
+ "euid",
+ "p_suid",
+ "source",
+ "etc",
+};
+
+void sh_regress_init(Shell_t* shp)
+{
+ static Regress_t state;
+
+ shp->regress = &state;
+}
+
+/*
+ * regress info trace output
+ */
+
+void sh_regress(unsigned int index, const char* intercept, const char* info, unsigned int line, const char* file)
+{
+ char* name;
+ char buf[16];
+
+ if (index >= 1 && index <= elementsof(regress_options))
+ name = (char*)regress_options[index];
+ else
+ sfsprintf(name = buf, sizeof(buf), "%u", index);
+ sfprintf(sfstderr, REGRESS_HEADER "%s:%s:%s\n", name, intercept, fmtesc(info));
+}
+
+/*
+ * egid intercepts
+ */
+
+static gid_t intercept_sgid = 0;
+static gid_t intercept_egid = -1;
+static gid_t intercept_rgid = -1;
+
+gid_t getegid(void)
+{
+ if (intercept_rgid == -1)
+ intercept_rgid = getgid();
+ if (sh_isregress(REGRESS_egid))
+ {
+ TRACE(egid, "getegid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid"));
+ return intercept_egid;
+ }
+ return intercept_rgid;
+}
+
+int setgid(gid_t gid)
+{
+ if (intercept_rgid == -1)
+ intercept_rgid = getgid();
+ if (sh_isregress(REGRESS_egid))
+ {
+ if (gid != intercept_rgid && gid != intercept_sgid)
+ {
+ TRACE(egid, "setgid", ("%s", "EPERM"));
+ errno = EPERM;
+ return -1;
+ }
+ intercept_egid = gid;
+ TRACE(egid, "setgid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid"));
+ }
+ else if (gid != intercept_rgid)
+ {
+ errno = EPERM;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * euid intercepts
+ */
+
+static uid_t intercept_suid = 0;
+static uid_t intercept_euid = -1;
+static uid_t intercept_ruid = -1;
+
+uid_t geteuid(void)
+{
+ if (intercept_ruid == -1)
+ intercept_ruid = getuid();
+ if (sh_isregress(REGRESS_euid))
+ {
+ TRACE(euid, "geteuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid"));
+ return intercept_euid;
+ }
+ return intercept_ruid;
+}
+
+int setuid(uid_t uid)
+{
+ if (intercept_ruid == -1)
+ intercept_ruid = getuid();
+ if (sh_isregress(REGRESS_euid))
+ {
+ if (uid != intercept_ruid && uid != intercept_suid)
+ {
+ TRACE(euid, "setuid", ("%s", "EPERM"));
+ errno = EPERM;
+ return -1;
+ }
+ intercept_euid = uid;
+ TRACE(euid, "setuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid"));
+ }
+ else if (uid != intercept_ruid)
+ {
+ errno = EPERM;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * p_suid intercept
+ */
+
+static uid_t intercept_p_suid = 0x7fffffff;
+
+uid_t sh_regress_p_suid(unsigned int line, const char* file)
+{
+ REGRESS(p_suid, "SHOPT_P_SUID", ("%d", intercept_p_suid));
+ return intercept_p_suid;
+}
+
+/*
+ * p_suid intercept
+ */
+
+static char* intercept_etc = 0;
+
+char* sh_regress_etc(const char* path, unsigned int line, const char* file)
+{
+ REGRESS(etc, "sh_open", ("%s => %s%s", path, intercept_etc, path+4));
+ return intercept_etc;
+}
+
+/*
+ * __regress__ builtin
+ */
+
+int b___regress__(int argc, char** argv, Shbltin_t *context)
+{
+ register Shell_t* shp = context->shp;
+ int n;
+
+ for (;;)
+ {
+ switch (n = optget(argv, usage))
+ {
+ case '?':
+ errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
+ break;
+ case ':':
+ errormsg(SH_DICT, 2, "%s", opt_info.arg);
+ break;
+ case 0:
+ break;
+ default:
+ if (n < -100)
+ {
+ n = -(n + 100);
+ if (opt_info.arg || opt_info.number)
+ sh_onregress(n);
+ else
+ sh_offregress(n);
+ switch (n)
+ {
+ case REGRESS_egid:
+ if (sh_isregress(n))
+ {
+ intercept_egid = intercept_sgid = (gid_t)opt_info.number;
+ TRACE(egid, argv[0], ("%d", intercept_egid));
+ }
+ else
+ TRACE(egid, argv[0], ("%s", "off"));
+ break;
+ case REGRESS_euid:
+ if (sh_isregress(n))
+ {
+ intercept_euid = intercept_suid = (uid_t)opt_info.number;
+ TRACE(euid, argv[0], ("%d", intercept_euid));
+ }
+ else
+ TRACE(euid, argv[0], ("%s", "off"));
+ break;
+ case REGRESS_p_suid:
+ if (sh_isregress(n))
+ {
+ intercept_p_suid = (uid_t)opt_info.number;
+ TRACE(p_suid, argv[0], ("%d", intercept_p_suid));
+ }
+ else
+ TRACE(p_suid, argv[0], ("%s", "off"));
+ break;
+ case REGRESS_source:
+ TRACE(source, argv[0], ("%s", sh_isregress(n) ? "on" : "off"));
+ break;
+ case REGRESS_etc:
+ if (sh_isregress(n))
+ {
+ intercept_etc = opt_info.arg;
+ TRACE(etc, argv[0], ("%s", intercept_etc));
+ }
+ else
+ TRACE(etc, argv[0], ("%s", "off"));
+ break;
+ }
+ }
+ continue;
+ }
+ break;
+ }
+ if (error_info.errors || *(argv + opt_info.index))
+ errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NiL));
+ return 0;
+}
+
+#else
+
+NoN(regress)
+
+#endif