+ e = sym_find(&bc__env, "BECOME_ORIGINAL_USER", -1, sizeof(*e), &f);
+ if (!f)
+ bc__setenv(e, from_pw->pw_name);
+ e->f |= envFlag_preserve;
+
+ e = sym_find(&bc__env, "BECOME_ORIGINAL_HOME", -1, sizeof(*e), &f);
+ if (!f)
+ bc__setenv(e, from_pw->pw_dir);
+ e->f |= envFlag_preserve;
+
+ bc__putenv("BECOME_OLD_USER", from_pw->pw_name, envFlag_preserve, 0);
+ bc__putenv("BECOME_OLD_HOME", from_pw->pw_dir, envFlag_preserve, 0);
+ bc__putenv("BECOME_USER", to_pw->pw_name, envFlag_preserve, 0);
+ bc__putenv("BECOME_HOME", to_pw->pw_dir, envFlag_preserve, 0);
+
+ /* --- Stage three. Set user identity --- */
+
+ switch (style) {
+ case l_login: {
+ static char *maildirs[] = {
+ "/var/spool/mail", "/var/mail",
+ "/usr/spool/mail", "/usr/mail",
+ 0
+ };
+ struct stat s;
+ char b[128];
+
+ for (pp = maildirs; *pp; pp++) {
+ if (stat(*pp, &s) == 0 && S_ISDIR(s.st_mode)) {
+ sprintf(b, "%s/%s", *pp, to_pw->pw_name);
+ bc__putenv("MAIL", b, envFlag_preserve, 0);
+ break;
+ }
+ }
+ } /* Fall through */
+
+ case l_user:
+ bc__putenv("USER", to_pw->pw_name, envFlag_preserve, 0);
+ bc__putenv("LOGNAME", to_pw->pw_name, envFlag_preserve, 0);
+ bc__putenv("HOME", to_pw->pw_dir, envFlag_preserve, 0);
+ bc__putenv("SHELL", to_pw->pw_shell, envFlag_preserve, 0);
+ break;
+ }
+
+ /* --- Stage four. Set the user's PATH properly --- */
+
+ {
+ /* --- Find an existing path --- *
+ *
+ * If there's no path, or this is a login, then set a default path,
+ * unless we're meant to preserve the existing one. Whew!
+ */
+
+ e = sym_find(&bc__env, "PATH", -1, sizeof(*e), &f);
+
+ if (!f || (style == l_login && ~e->f & envFlag_preserve)) {
+ bc__putenv("PATH",
+ rq.to ? "/usr/bin:/bin" : "/usr/bin:/usr/sbin:/bin:/sbin",
+ envFlag_preserve, 0);
+ } else {
+
+ /* --- Find the string --- */
+
+ e->f = envFlag_preserve;
+ p = strchr(e->val, '=') + 1;
+ r = e->val;
+
+ /* --- Write the new version to a dynamically allocated buffer --- */
+
+ e->val = xmalloc(4 + 1 + strlen(p) + 1);
+ strcpy(e->val, "PATH=");
+ q = e->val + 5;
+
+ for (p = strtok(p, ":"); p; p = strtok(0, ":")) {
+ if (p[0] != '/')
+ continue;
+ while (*p)
+ *q++ = *p++;
+ *q++ = ':';
+ }
+ q[-1] = 0;
+
+ /* --- Done! --- */
+
+ free(r);
+ }
+ }
+
+ /* --- Stages five and six. Expunge variables and count numbers --- *
+ *
+ * Folded together, so I only need one pass through the table. Also
+ * count the number of variables needed at this time.
+ */
+
+ sz = 0;
+
+ for (sym_createIter(&i, &bc__env); (e = sym_next(&i)) != 0; ) {
+
+ /* --- Login style expunges all unpreserved variables --- */
+
+ if (style == l_login && ~e->f & envFlag_preserve)
+ goto expunge;
+
+ /* --- Otherwise just check the name against the list --- */
+
+ for (pp = banned; *pp; pp++) {
+ if (**pp == '-') {
+ p = *pp + 1;
+ if (memcmp(e->_base.name, p, strlen(p)) == 0)
+ goto expunge;
+ } else if (strcmp(e->_base.name, p) == 0)
+ goto expunge;
+ }
+
+ sz++;
+ continue;
+
+ expunge:
+ sym_remove(&bc__env, e);
+ }
+
+ /* --- Stage seven. Build the new environment block --- */
+
+ env = qq = xmalloc((sz + 1) * sizeof(*qq));
+
+ for (sym_createIter(&i, &bc__env); (e = sym_next(&i)) != 0; )
+ *qq++ = e->val;
+ *qq++ = 0;