示例#1
0
文件: main.c 项目: albfan/rlwrap
/*
 * create pty pair and fork using my_pty_fork; parent returns immediately; child
 * executes the part of rlwrap's command line that remains after
 * read_options_and_command_name() has harvested rlwrap's own options
 */  
static void
fork_child(char *command_name, char **argv)
{
  char *arg = argv[optind], *p, **argp;
  int pid;

  command_line = mysavestring(arg);
  for (argp = argv + optind + 1; *argp; argp++) {
    command_line = append_and_free_old (command_line, " ");
    command_line = append_and_free_old (command_line, *argp);
  }

  pid = my_pty_fork(&master_pty_fd, &saved_terminal_settings, &winsize);
  if (pid > 0)			/* parent: */
    return;
  else {			/* child: */
    DPRINTF1(DEBUG_TERMIO, "preparing to execute %s", arg);
    close_open_files_without_writing_buffers();
    
    if (client_term_name)
      mysetenv("TERM", client_term_name);   
    if (execvp(argv[optind], &argv[optind]) < 0) {
      if (last_opt > 0 && last_option_didnt_have_optional_argument) { /* e.g. 'rlwrap -a Password: sqlpus' will try to exec 'Password:'******'; !(){}"; *p; p++) /* does arg need shell quoting? */ 
	  if (strchr(arg,*p)) { 
            arg = add3strings("'", arg,"'"); /* quote it  */
            break;
	  }	
	fprintf(stderr, "Did you mean '%s' to be an option argument?\nThen you should write -%c%s, without the space(s)\n",
                argv[optind], last_opt, arg); 
      }
      myerror("Cannot execute %s", argv[optind]);   	/* stillborn child, parent will live on and display child's last gasps */
    }
  }
}
示例#2
0
void
man_getopt (int argc, char **argv) {
     char *config_file = NULL;
     char *manp = NULL;
     int optct = 0;

     optct = get_options_from_argvec(argc, argv, &config_file, &manp);

     read_config_file (config_file);

     /* If no options were given and MANDEFOPTIONS is set, use that */
     if (optct == 0) {
	     const char *defopts = getval ("MANDEFOPTIONS");
	     get_options_from_string(defopts);
     }

     /* In case an explicit -P option was given, put it in the
	environment for possible use with -k or -K.
	Ignore errors (out of memory?) */

     if (pager && (global_apropos || apropos || whatis))
	     mysetenv("PAGER", pager);

     if (pager == NULL || *pager == '\0')
	  if ((pager = getenv ("MANPAGER")) == NULL)
	       if ((pager = getenv ("PAGER")) == NULL)
		    pager = getval ("PAGER");

     if (debug)
	  gripe (PAGER_IS, pager);

     /* Ditto for BROWSER and -B */
     if (browser && (global_apropos || apropos || whatis))
	 mysetenv("BROWSER", browser);

     if (browser == NULL || *browser == '\0')
	 if ((browser = getenv ("BROWSER")) == NULL)
	     browser = getval ("BROWSER");

     if (debug)
	  gripe (BROWSER_IS, browser);

     /* Ditto for HTMLHTMLPAGER and -D */
     if (htmlpager && (global_apropos || apropos || whatis))
	 mysetenv("HTMLPAGER", htmlpager);

     if (htmlpager == NULL || *htmlpager == '\0')
	 if ((htmlpager = getenv ("HTMLPAGER")) == NULL)
	     htmlpager = getval ("HTMLPAGER");

     if (debug)
	  gripe (HTMLPAGER_IS, htmlpager);

     if (do_compress && !*getval ("COMPRESS")) {
	  if (debug)
	       gripe (NO_COMPRESS);
	  do_compress = 0;
     }

     if (do_troff && !*getval ("TROFF")) {
	  gripe (NO_TROFF, configuration_file);
	  exit (1);
     }

     opt_manpath = manp;		/* do not yet expand manpath -
					   maybe it is not needed */

     if (alt_system_name == NULL || *alt_system_name == '\0')
	  if ((alt_system_name = getenv ("SYSTEM")) != NULL)
	       alt_system_name = my_strdup (alt_system_name);

}
示例#3
0
int
dgl_exec_cmdqueue(struct dg_cmdpart *queue, int game, struct dg_user *me)
{
    int i;
    struct dg_cmdpart *tmp = queue;
    char *p1;
    char *p2;
    int played = 0;

    if (!queue) return 1;

    p1 = (char *)malloc(1024);
    p2 = (char *)malloc(1024);

    if (!p1 || !p2) return 1;

    return_from_submenu = 0;

    while (tmp && !return_from_submenu) {
        if (tmp->param1) strcpy(p1, dgl_format_str(game, me, tmp->param1, NULL));
        if (tmp->param2) strcpy(p2, dgl_format_str(game, me, tmp->param2, NULL));

        switch (tmp->cmd) {
        default:
            break;
        case DGLCMD_RAWPRINT:
            if (p1) fprintf(stdout, "%s", p1);
            break;
        case DGLCMD_MKDIR:
            if (p1 && (access(p1, F_OK) != 0)) mkdir(p1, 0755);
            break;
        case DGLCMD_UNLINK:
            if (p1 && (access(p1, F_OK) == 0)) unlink(p1);
            break;
        case DGLCMD_CHDIR:
            if (p1) {
                if (chdir(p1) == -1) {
                    debug_write("chdir-command failed");
                    graceful_exit(123);
                }
            }
            break;
        case DGLCMD_IF_NX_CP:
            if (p1 && p2) {
                FILE *tmpfile;
                tmpfile = fopen(p2, "r");
                if (tmpfile) {
                    fclose(tmpfile);
                    break;
                }
            }
        /* else fall through to cp */
        case DGLCMD_CP:
            if (p1 && p2) {
                FILE *cannedf, *newfile;
                char buf[1024];
                size_t bytes;
                /* FIXME: use nethack-themed error messages here, as per write_canned_rcfile() */
                if (!(cannedf = fopen (p1, "r"))) break;
                if (!(newfile = fopen (p2, "w"))) break;
                while ((bytes = fread (buf, 1, 1024, cannedf)) > 0) {
                    if (fwrite (buf, 1, bytes, newfile) != bytes) {
                        if (ferror (newfile)) {
                            fclose (cannedf);
                            fclose (newfile);
                            break;
                        }
                    }
                }
                fclose (cannedf);
                fclose (newfile);
                chmod (p2, default_fmode);
            }
            break;
        case DGLCMD_EXEC:
            if (p1 && p2) {
                pid_t child;
                char *myargv[3];

                myargv[0] = p1;
                myargv[1] = p2;
                myargv[2] = 0;

                clear();
                refresh();
                endwin();
                idle_alarm_set_enabled(0);
                child = fork();
                if (child == -1) {
                    perror("fork");
                    debug_write("exec-command fork failed");
                    graceful_exit(114);
                } else if (child == 0) {
                    execvp(p1, myargv);
                    exit(0);
                } else
                    waitpid(child, NULL, 0);
                idle_alarm_set_enabled(1);
                initcurses();
                check_retard(1);
            }
            break;
        case DGLCMD_SETENV:
            if (p1 && p2) mysetenv(p1, p2, 1);
            break;
        case DGLCMD_CHPASSWD:
            if (loggedin) changepw(1);
            break;
        case DGLCMD_CHMAIL:
            if (loggedin) change_email();
            break;
        case DGLCMD_WATCH_MENU:
            inprogressmenu(-1);
            break;
        case DGLCMD_LOGIN:
            if (!loggedin) loginprompt(0);
            if (loggedin) runmenuloop(dgl_find_menu(get_mainmenu_name()));
            break;
        case DGLCMD_REGISTER:
            if (!loggedin && globalconfig.allow_registration) newuser();
            break;
        case DGLCMD_QUIT:
            debug_write("command: quit");
            graceful_exit(0);
        /* break; */
        case DGLCMD_SUBMENU:
            if (p1)
                runmenuloop(dgl_find_menu(p1));
            break;
        case DGLCMD_RETURN:
            return_from_submenu = 1;
            break;
        case DGLCMD_PLAY_IF_EXIST:
            if (!(loggedin && me && p1 && p2)) break;
            {
                FILE *tmpfile;
                tmpfile = fopen(p2, "r");
                if (tmpfile) {
                    fclose(tmpfile);
                } else break;
            }
        /* else fall through to playgame */
        case DGLCMD_PLAYGAME:
            if (loggedin && me && p1 && !played) {
                int userchoice, i;
                char *tmpstr;
                for (userchoice = 0; userchoice < num_games; userchoice++) {
                    if (!strcmp(myconfig[userchoice]->game_id, p1) || !strcmp(myconfig[userchoice]->game_name, p1) || !strcmp(myconfig[userchoice]->shortname, p1)) {
                        if (purge_stale_locks(userchoice)) {
                            if (myconfig[userchoice]->rcfile) {
                                if (access (dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt, NULL), R_OK) == -1)
                                    write_canned_rcfile (userchoice, dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt, NULL));
                            }

                            setproctitle("%s [playing %s]", me->username, myconfig[userchoice]->shortname);

                            clear();
                            refresh();
                            endwin ();

                            /* first run the generic "do these when a game is started" commands */
                            dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_GAMESTART], userchoice, me);
                            /* then run the game-specific commands */
                            dgl_exec_cmdqueue(myconfig[userchoice]->cmdqueue, userchoice, me);

                            /* fix the variables in the arguments */
                            for (i = 0; i < myconfig[userchoice]->num_args; i++) {
                                tmpstr = strdup(dgl_format_str(userchoice, me, myconfig[userchoice]->bin_args[i], NULL));
                                free(myconfig[userchoice]->bin_args[i]);
                                myconfig[userchoice]->bin_args[i] = tmpstr;
                            }

                            signal(SIGWINCH, SIG_DFL);
                            signal(SIGINT, SIG_DFL);
                            signal(SIGQUIT, SIG_DFL);
                            signal(SIGTERM, SIG_DFL);
                            idle_alarm_set_enabled(0);
                            /* launch program */
                            ttyrec_main (userchoice, me->username,
                                         dgl_format_str(userchoice, me, myconfig[userchoice]->ttyrecdir, NULL),
                                         gen_ttyrec_filename());
                            idle_alarm_set_enabled(1);
                            played = 1;
                            /* lastly, run the generic "do these when a game is left" commands */
                            signal (SIGHUP, catch_sighup);
                            signal (SIGINT, catch_sighup);
                            signal (SIGQUIT, catch_sighup);
                            signal (SIGTERM, catch_sighup);
                            signal(SIGWINCH, sigwinch_func);

                            dgl_exec_cmdqueue(myconfig[userchoice]->postcmdqueue, userchoice, me);

                            dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_GAMEEND], userchoice, me);

                            setproctitle ("%s", me->username);
                            initcurses ();
                            check_retard(1); /* reset retard counter */
                        }
                        break;
                    }
                }
            }
            break;
        }
        tmp = tmp->next;
    }

    free(p1);
    free(p2);

    return 0;
}
示例#4
0
文件: filter.c 项目: rubicks/rlwrap
void spawn_filter(const char *filter_command) {
    int input_pipe_fds[2];
    int output_pipe_fds[2];

    mypipe(input_pipe_fds);
    filter_input_fd = input_pipe_fds[1]; /* rlwrap writes filter input to this */

    mypipe(output_pipe_fds);
    filter_output_fd = output_pipe_fds[0]; /* rlwrap  reads filter output from here */
    DPRINTF1(DEBUG_FILTERING, "preparing to spawn filter <%s>", filter_command);
    assert(!command_pid || signal_handlers_were_installed);  /* if there is a command, then signal handlers are installed */

    if ((filter_pid = fork()) < 0)
        myerror(FATAL|USE_ERRNO, "Cannot spawn filter '%s'", filter_command);
    else if (filter_pid == 0) {           /* child */
        int signals_to_allow[] = {SIGPIPE, SIGCHLD, SIGALRM, SIGUSR1, SIGUSR2};
        char **argv;
        unblock_signals(signals_to_allow);  /* when we run a pager from a filter we want to catch these */


        DEBUG_RANDOM_SLEEP;
        i_am_child =  TRUE;
        /* set environment for filter (it needs to know at least the file descriptors for its input and output) */

        if (!getenv("RLWRAP_FILTERDIR"))
            mysetenv("RLWRAP_FILTERDIR", add2strings(DATADIR,"/rlwrap/filters"));
        mysetenv("PATH", add3strings(getenv("RLWRAP_FILTERDIR"),":",getenv("PATH")));
        mysetenv("RLWRAP_VERSION", VERSION);
        mysetenv("RLWRAP_COMMAND_PID",  as_string(command_pid));
        mysetenv("RLWRAP_COMMAND_LINE", command_line);
        if (impatient_prompt)
            mysetenv("RLWRAP_IMPATIENT", "1");
        mysetenv("RLWRAP_INPUT_PIPE_FD", as_string(input_pipe_fds[0]));
        mysetenv("RLWRAP_OUTPUT_PIPE_FD", as_string(output_pipe_fds[1]));
        mysetenv("RLWRAP_MASTER_PTY_FD", as_string(master_pty_fd));

        close(filter_input_fd);
        close(filter_output_fd);


        if (scan_metacharacters(filter_command, "'|\"><"))  { /* if filter_command contains shell metacharacters, let the shell unglue them */
            char *exec_command = add3strings("exec", " ", filter_command);
            argv = list4("sh", "-c", exec_command, NULL);
        } else {                                              /* if not, split and feed to execvp directly (cheaper, better error message) */
            argv = split_with(filter_command, " ");
        }
        assert(argv[0]);
        if(execvp(argv[0], argv) < 0) {
            char *sorry = add3strings("Cannot exec filter '", argv[0], add2strings("': ", strerror(errno)));
            write_message(output_pipe_fds[1], TAG_ERROR, sorry, "to stdout"); /* this will kill rlwrap */
            mymicrosleep(100 * 1000); /* 100 sec for rlwrap to go away should be enough */
            exit (-1);
        }
        assert(!"not reached");

    } else {
        DEBUG_RANDOM_SLEEP;
        signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE - we have othere ways to deal with filter death */
        DPRINTF1(DEBUG_FILTERING, "spawned filter with pid %d", filter_pid);
        close (input_pipe_fds[0]);
        close (output_pipe_fds[1]);
    }
}
示例#5
0
文件: curdir.c 项目: idunham/dtextra
static void update_shelf_path(String dirname)
{
  mysetenv("CURSHELF", dirname, True);
}
示例#6
0
文件: curdir.c 项目: idunham/dtextra
static void update_cur_path(String dirname)
{
  strcpy(save_cur_path, dirname);
  mysetenv("CURDIR", dirname, True);
}
示例#7
0
int process_ssh_request(char *request)
{
	char **av, **tmp_av, **tenv;
	char *flat_request,*tmpstring, *tmprequest;
	char bad_winscp3str[] = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server exec sftp-server";
	int retval;
	int reqlen=strlen(request);
	char **env = NULL;

	debug(LOG_DEBUG, "processing request: \"%s\"\n", request);

	tmprequest=strdup(request);

#ifdef WINSCP_COMPAT			

	bad_winscp3str[57]=10;
	bad_winscp3str[127]=10;
			
	if(strcmp(request,bad_winscp3str)==0)
	{
	    /*
		 * switch out the command to use, winscp wont know the difference
	 	 */
		free(tmprequest);
		tmprequest=strdup(PROG_SFTP_SERVER);
	    syslog(LOG_DEBUG, "winscp3 compat correcting to: \"[%s]\"\n", PROG_SFTP_SERVER);
	}
#endif

	
#ifdef GFTP_COMPAT 
	/*
	 *	gFTP compatibility hack
	 */
	if (NULL != (tmpstring=strbeg(request, "echo -n xsftp ; ")))
	{
		free(tmprequest);
		tmprequest=strdup(tmpstring);
		printf("xsftp");
		fflush(stdout);
	}
#endif

#ifdef RESTRICTIVE_FILENAMES
	/*
	 * we flat out reject special chars
	 */
	if (!valid_chars(tmprequest))
	{
		debug(LOG_DEBUG, "rejected because of invalid chars (%s)", logstamp());
		free(tmprequest);
		return(-1);
	}
#endif

#ifdef WINSCP_COMPAT
	if (strbeg(tmprequest,PROG_CD))
	{
		char *destdir=(char *)malloc(reqlen);
		if (destdir == NULL)
		{
			perror("malloc");
			exit(EXIT_FAILURE);
		}

		/*
		 * well, now that scponly is a persistent shell
		 * i have to maintain a $PWD.  damn.
		 * we're going to INSIST upon a double quote
		 * encapsulated new directory to change to.
		 */
		if ((tmprequest[(reqlen-1)]=='"') && (tmprequest[3]=='"'))
		{
			bzero(destdir,reqlen);
			strncpy(destdir,&tmprequest[4],reqlen-5);
			debug(LOG_INFO, "chdir: %s (%s)", tmprequest, logstamp());
			retval=chdir(destdir);
			free(destdir);
			free(tmprequest);
			return(retval);
		}
		syslog(LOG_ERR, "bogus chdir request: %s (%s)", tmprequest, logstamp());
		free(tmprequest);
		return(-1);
	}
#endif

	/*
	 * convert request string to an arg_vector
	 */
	av = build_arg_vector(tmprequest);

	/*
	 * clean any path info from request and substitute our known pathnames
	 */
	av[0] = substitute_known_path(av[0]);
	
	/*
	 * we only process wildcards for scp commands
	 */
#ifdef ENABLE_WILDCARDS
#ifdef ENABLE_SCP2
	if (exact_match(av[0],PROG_SCP))
		av = expand_wildcards(av);
#endif
#endif

/*
 *	check for a compile time chdir configuration
 */
#ifdef ENABLE_DEFAULT_CHDIR
	if (exact_match(av[0],PROG_SFTP_SERVER))
	{
		syslog(LOG_INFO, "changing initial directory to %s", DEFAULT_CHDIR);
		chdir(DEFAULT_CHDIR);
	}
#endif
	

	flat_request = flatten_vector(av);

	/* 
	 * Use a temp arg vector since getopt will permute the command line arguments
	 * for anything that it does not know about.  If all rsync options are well
	 * defined this isn't necessary.
	 */
	tmp_av = build_arg_vector(flat_request);
	if(check_dangerous_args(tmp_av))
	{
		syslog(LOG_ERR, "requested command (%s) tried to use disallowed argument (%s))", 
			flat_request, logstamp());
		exit(EXIT_FAILURE);
	}
	discard_vector(tmp_av);

	if (valid_arg_vector(av))
	{

/*														   
 * Unison needs the HOME environment variable be set to the directory						  
 * where the .unison directory resides.										
 */														    
#ifdef USE_SAFE_ENVIRONMENT
		safeenv[0] = NULL;
		filter_allowed_env_vars();
		tenv = safeenv;
		if (debuglevel) {
			while (NULL != *tenv) {
				syslog(LOG_DEBUG, "Environment contains \"%s\"", *tenv++);
			}
		}
		env = safeenv;
#endif

#ifdef UNISON_COMPAT
		/* the HOME environment variable should have been set above, but I need to make sure
		 * that it's value as read from the environment is replaced with the actual value
		 * as it exists within the chroot, which is what the applications will expect to see.
		 */
		if (replace_env_entry("HOME",homedir) && (((strlen(homedir) + 6 ) > FILENAME_MAX) || !mysetenv("HOME",homedir)))
		{
			syslog(LOG_ERR, "could not set HOME environment variable (%s)", logstamp());
			exit(EXIT_FAILURE);
		}
		debug(LOG_DEBUG, "set non-chrooted HOME environment variable to %s (%s)", homedir, logstamp());
#endif 
		syslog(LOG_INFO, "running: %s (%s)", flat_request, logstamp());

#ifdef WINSCP_COMPAT
		if (winscp_mode)
		{
			int status=0;
			if (fork() == 0)
				retval=execve(av[0],av,env);
			else
			{
				wait(&status);
				fflush(stdout);
				fflush(stderr);
				discard_vector(av);
#ifdef USE_SAFE_ENVIRONMENT											    
				discard_child_vectors(safeenv);
#endif
				free(flat_request);
				free(tmprequest);
				return(WEXITSTATUS(status));
			}
		}
		else
#endif
		{
			debug(LOG_DEBUG, "about to exec \"%s\" (%s)", av[0], logstamp());
			retval=execve(av[0],av,env);
		}
		syslog(LOG_ERR, "failed: %s with error %s(%u) (%s)", flat_request, strerror(errno), errno, logstamp());
		free(flat_request);
		discard_vector(av);
#ifdef USE_SAFE_ENVIRONMENT
		discard_child_vectors(safeenv);
#endif
#ifdef WINSCP_COMPAT
		if (winscp_mode)
		{
			free(tmprequest);
			return(-1);
		}
		else
#endif 
			exit(errno);
	}

	/*
	 *	reaching this point in the code means the request isnt one of
	 *	our accepted commands
 	 */
	if (debuglevel)
	{
		if (exact_match(flat_request,tmprequest))
			syslog (LOG_ERR, "denied request: %s [%s]", tmprequest, logstamp());
		else
			syslog (LOG_ERR, "denied request: %s (resolved to: %s) [%s]", tmprequest, flat_request, logstamp());
	}
	free(flat_request); 
#ifdef WINSCP_COMPAT
	if (winscp_mode)
	{
		printf ("command not permitted by scponly\n");
		free(tmprequest);
		return(-1);
	}
	else
#endif 
		exit(EXIT_FAILURE);
}
示例#8
0
int main(int argc, char **argv)
{
	const char *user;
	const char *logname;
	const struct passwd *pw;
	char **newargv;
	//char envsh[BUFSIZ];
	//char envhome[BUFSIZ];
	int j;
	//char *neweviron[10];
	char *shell;
	char *argv0;
	char *newargv0;

#ifdef DEBUG_PRINTS
	fp = fopen("/var/log/chrootshell.log", "a");
#endif
	user = getenv("USER");
	if (!user)
		die("USER not set?!");
	logname = getenv("LOGNAME");
	if (logname && *logname && strcmp(user, logname))
		die("USER does not match LOGNAME\n");
	/* Look up user in outer /etc/passwd */
	pw = getpwnam(user);
	if (!pw)
		die2("no such user %s\n", user);
	shell = strrchr(pw->pw_shell, '/');
	if (!shell)
		die("shell contains no / ?");
	shell++;	/* skip slash */
	argv0 = argv[0];
	if (*argv0 == '-') {
		/* it's a login shell */
		argv0++;	/* skip dash */
	}
	if (strcmp(shell, argv0)) {
		fprintf(fp, "shell '%s', argv[0] '%s'\n", shell, argv[0]);
		die2("%s not chrootshell\n", shell);
	}
	/* Enter jail */
	if (chdir(pw->pw_dir))
		die2("chdir(%s) fails", pw->pw_dir);
	if (chroot(pw->pw_dir))
		die2("chroot(%s) fails", pw->pw_dir);
	/* Permanently discard root privs */
	if (setuid(pw->pw_uid))
		die2("setuid(%d) fails", (void *)pw->pw_uid);
	/* Look up user in jail's /etc/passwd */
	endpwent();
	pw = getpwnam(user);
	if (!pw)
		die2("no such user %s in jail\n", user);
	/* Go to his home directory */
	if (chdir(pw->pw_dir))
		die2("chdir(%s) fails", pw->pw_dir);

	/* Fix up the environment. 
	 * Clear the whole thing out for security reasons, and give him a minimal one.
	 */
	mysetenv("SHELL", pw->pw_shell);
	mysetenv("HOME", pw->pw_dir);
	mysetenv("PATH", "/bin:/usr/bin");
	mysetenv("USER", user);
	/* Note: rshd does not set LOGNAME, as the user hasn't really logged in... */
	if (logname && *logname)
		mysetenv("LOGNAME", user);
	myenv[myenv_used] = 0;
	/* yes, this is the posix way of replacing the entire environment */
	environ = myenv;

	/* Close the handle to the jail's /etc/passwd */
	endpwent();
	/* Finally, run the original command. */
	newargv = malloc((argc + 3) * sizeof(argv[0]));
	if (!newargv)
		die("malloc fails?!\n");
	j = 0;
	if (argc == 1) {
		/* Case 1: interactive login; argv[0] is the shell, there are no args */
		char *buf = malloc(strlen(pw->pw_shell) + 2);
		newargv0 = pw->pw_shell;
		sprintf(buf, "-%s", pw->pw_shell);
		newargv[j++] = buf;
	} else if (argc > 1 && !strcmp(argv[1], "-c")) {
		/* Case 2: non-interactive; argv[0] is the shell, argv[1] is -c, argv[2] is the command */
		newargv[j++] = pw->pw_shell;
		newargv0 = pw->pw_shell;
		newargv[j++] = "-c";
		newargv[j++] = argv[2];
	} else
		die("Expected argc==1 || (argc==3 && argv[1] == '-c')");
	newargv[j++] = 0;
	execvp(newargv0, newargv);
	die2("exec %s fails", newargv[0]);
	/*notreached*/
	return 1;
}