Ejemplo n.º 1
0
static int
bin_clone(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
    int ttyfd, pid, cttyfd;

    unmetafy(*args, NULL);
    ttyfd = open(*args, O_RDWR|O_NOCTTY);
    if (ttyfd < 0) {
	zwarnnam(nam, "%s: %e", *args, errno);
	return 1;
    }
    pid = fork();
    if (!pid) {
	clearjobtab(0);
	ppid = getppid();
	mypid = getpid();
#ifdef HAVE_SETSID
	if (setsid() != mypid)
	    zwarnnam(nam, "failed to create new session: %e", NULL, errno);
#elif defined(TIOCNOTTY)
	    if (ioctl(SHTTY, TIOCNOTTY, 0))
	    zwarnnam(*args, "%e", NULL, errno);
	    setpgrp(0L, mypid);
#endif
	dup2(ttyfd,0);
	dup2(ttyfd,1);
	dup2(ttyfd,2);
	if (ttyfd > 2)
	    close(ttyfd);
	closem(0);
	close(coprocin);
	close(coprocout);
	/* Acquire a controlling terminal */
	cttyfd = open(*args, O_RDWR);
	if (cttyfd == -1)
	    zwarnnam(nam, "%e", NULL, errno);
	else {
#ifdef TIOCSCTTY
	    ioctl(cttyfd, TIOCSCTTY, 0);
#endif
	    close(cttyfd);
	}
	/* check if we acquired the tty successfully */
	cttyfd = open("/dev/tty", O_RDWR);
	if (cttyfd == -1)
	    zwarnnam(nam, "could not make %s my controlling tty, job control "
		     "disabled", *args, 0);
	else
	    close(cttyfd);

	/* Clear mygrp so that acquire_pgrp() gets the new process group.
	 * (acquire_pgrp() is called from init_io()) */
	mypgrp = 0;
	init_io();
	setsparam("TTY", ztrdup(ttystrname));
    }
    close(ttyfd);
    if (pid < 0) {
	zerrnam(nam, "fork failed: %e", NULL, errno);
	return 1;
    }
    lastpid = pid;
    return 0;
}
Ejemplo n.º 2
0
static void
backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
{
    ssize_t icnt;
    Char c, *ip;
    struct command faket;
    int    hadnl;
    int     pvec[2], quoted;
    Char   *fakecom[2], ibuf[BUFSIZE];
    char    tibuf[BUFSIZE];

    hadnl = 0;
    icnt = 0;
    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
    faket.t_dtyp = NODE_COMMAND;
    faket.t_dflg = F_BACKQ;
    faket.t_dlef = 0;
    faket.t_drit = 0;
    faket.t_dspr = 0;
    faket.t_dcom = fakecom;
    fakecom[0] = STRfakecom1;
    fakecom[1] = 0;

    /*
     * We do the psave job to temporarily change the current job so that the
     * following fork is considered a separate job.  This is so that when
     * backquotes are used in a builtin function that calls glob the "current
     * job" is not corrupted.  We only need one level of pushed jobs as long as
     * we are sure to fork here.
     */
    psavejob();
    cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */

    /*
     * It would be nicer if we could integrate this redirection more with the
     * routines in sh.sem.c by doing a fake execute on a builtin function that
     * was piped out.
     */
    mypipe(pvec);
    cleanup_push(&pvec[0], open_cleanup);
    cleanup_push(&pvec[1], open_cleanup);
    if (pfork(&faket, -1) == 0) {
	jmp_buf_t osetexit;
	struct command *t;
	size_t omark;

	xclose(pvec[0]);
	(void) dmove(pvec[1], 1);
	(void) dmove(SHDIAG,  2);
	initdesc();
	closem();
	arginp = cp;
	for (arginp = cp; *cp; cp++) {
	    *cp &= TRIM;
	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
		*cp = ' ';
	}

        /*
	 * In the child ``forget'' everything about current aliases or
	 * eval vectors.
	 */
	alvec = NULL;
	evalvec = NULL;
	alvecp = NULL;
	evalp = NULL;

	omark = cleanup_push_mark();
	getexit(osetexit);
	for (;;) {
	    (void) setexit();
	    justpr = 0;
	    
	    if (haderr) {
		/* unwind */
		doneinp = 0;
		cleanup_pop_mark(omark);
		resexit(osetexit);
		reset();
	    }
	    if (seterr) {
		xfree(seterr);
		seterr = NULL;
	    }

	    (void) lex(&paraml);
	    cleanup_push(&paraml, lex_cleanup);
	    if (seterr)
		stderror(ERR_OLD);
	    alias(&paraml);
	    t = syntax(paraml.next, &paraml, 0);
	    if (t == NULL)
		return;
	    cleanup_push(t, syntax_cleanup);
	    /* The F_BACKQ flag must set so the job output is correct if
	     * printexitvalue is set.  If it's not set, the job output
	     * will have "Exit N" appended where N is the exit status. */
	    t->t_dflg = F_BACKQ|F_NOFORK;
	    if (seterr)
		stderror(ERR_OLD);
#ifdef SIGTSTP
	    signal(SIGTSTP, SIG_IGN);
#endif
#ifdef SIGTTIN
	    signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTTOU
	    signal(SIGTTOU, SIG_IGN);
#endif
	    execute(t, -1, NULL, NULL, TRUE);

	    cleanup_until(&paraml);
	}
    }
    cleanup_until(&pvec[1]);
    c = 0;
    ip = NULL;
    do {
	ssize_t     cnt = 0;
	char   *tmp;

	tmp = tibuf;
	for (;;) {
	    while (icnt == 0) {
		int     i, eof;

		ip = ibuf;
		icnt = xread(pvec[0], tmp, tibuf + BUFSIZE - tmp);
		eof = 0;
		if (icnt <= 0) {
		    if (tmp == tibuf)
			goto eof;
		    icnt = 0;
		    eof = 1;
		}
		icnt += tmp - tibuf;
		i = 0;
		tmp = tibuf;
		while (tmp < tibuf + icnt) {
		    int len;

		    len = normal_mbtowc(&ip[i], tmp, tibuf + icnt - tmp);
		    if (len == -1) {
		        reset_mbtowc();
		        if (!eof && (size_t)(tibuf + icnt - tmp) < MB_CUR_MAX) {
			    break; /* Maybe a partial character */
			}
			ip[i] = (unsigned char) *tmp | INVALID_BYTE; /* Error */
		    }
		    if (len <= 0)
		        len = 1;
		    i++;
		    tmp += len;
		}
		if (tmp != tibuf)
		    memmove (tibuf, tmp, tibuf + icnt - tmp);
		tmp = tibuf + (tibuf + icnt - tmp);
		icnt = i;
	    }
	    if (hadnl)
		break;
	    --icnt;
	    c = (*ip++ & TRIM);
	    if (c == 0)
		break;
#if defined(WINNT_NATIVE) || defined(__CYGWIN__)
	    if (c == '\r')
	    	c = ' ';
#endif /* WINNT_NATIVE || __CYGWIN__ */
	    if (c == '\n') {
		/*
		 * Continue around the loop one more time, so that we can eat
		 * the last newline without terminating this word.
		 */
		hadnl = 1;
		continue;
	    }
	    if (!quoted && (c == ' ' || c == '\t'))
		break;
	    cnt++;
	    Strbuf_append1(word, c | quoted);
	}
	/*
	 * Unless at end-of-file, we will form a new word here if there were
	 * characters in the word, or in any case when we take text literally.
	 * If we didn't make empty words here when literal was set then we
	 * would lose blank lines.
	 */
	if (c != 0 && (cnt || literal))
	    pword(bb, word);
	hadnl = 0;
    } while (c > 0);
 eof:
    cleanup_until(&pvec[0]);
    pwait();
    cleanup_until(&faket); /* psavejob_cleanup(); */
}
Ejemplo n.º 3
0
Archivo: zpty.c Proyecto: zsh-users/zsh
static int
newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
{
    Ptycmd p;
    int master, slave, pid, oineval = ineval, ret;
    char *oscriptname = scriptname, syncch;
    Eprog prog;

    /* code borrowed from bin_eval() */
    ineval = !isset(EVALLINENO);
    if (!ineval)
	scriptname = "(zpty)";

    prog = parse_string(zjoin(args, ' ', 1), 0);
    if (!prog) {
	errflag &= ~ERRFLAG_ERROR;
	scriptname = oscriptname;
	ineval = oineval;
	return 1;
    }

    if (get_pty(1, &master)) {
	zwarnnam(nam, "can't open pseudo terminal: %e", errno);
	scriptname = oscriptname;
	ineval = oineval;
	return 1;
    }
    if ((pid = fork()) == -1) {
	zwarnnam(nam, "can't create pty command %s: %e", pname, errno);
	close(master);
	scriptname = oscriptname;
	ineval = oineval;
	return 1;
    } else if (!pid) {
	/* This code copied from the clone module, except for getting *
	 * the descriptor from get_pty() and duplicating it to 0/1/2. */

	deletehookfunc("exit", ptyhook);
	clearjobtab(0);
	ppid = getppid();
	mypid = getpid();
#ifdef HAVE_SETSID
	if (setsid() != mypid) {
	    zwarnnam(nam, "failed to create new session: %e", errno);
#endif
#ifdef TIOCNOTTY
	    if (ioctl(SHTTY, TIOCNOTTY, 0))
		zwarnnam(nam, "%e", errno);
	    setpgrp(0L, mypid);
#endif
#ifdef HAVE_SETSID
	}
#endif

	if (get_pty(0, &slave))
	    exit(1);
	SHTTY = slave;
	attachtty(mypid);
#ifdef TIOCGWINSZ
	/* Set the window size before associating with the terminal *
	 * so that we don't get hit with a SIGWINCH.  I'm paranoid. */
	if (interact) {
	    struct ttyinfo info;

	    if (ioctl(slave, TIOCGWINSZ, (char *) &info.winsize) == 0) {
		info.winsize.ws_row = zterm_lines;
		info.winsize.ws_col = zterm_columns;
		ioctl(slave, TIOCSWINSZ, (char *) &info.winsize);
	    }
	}
#endif /* TIOCGWINSZ */

	if (!echo) {
	    struct ttyinfo info;

	    if (!ptygettyinfo(slave, &info)) {
#ifdef HAVE_TERMIOS_H
		info.tio.c_lflag &= ~ECHO;
#else
#ifdef HAVE_TERMIO_H
		info.tio.c_lflag &= ~ECHO;
#else
		info.tio.lmodes &= ~ECHO; /**** dunno if this is right */
#endif
#endif
		ptysettyinfo(slave, &info);
	    }
	}

#ifdef TIOCSCTTY
	ioctl(slave, TIOCSCTTY, 0);
#endif

	close(0);
	close(1);
	close(2);

	dup2(slave, 0);
	dup2(slave, 1);
	dup2(slave, 2);

	closem(FDT_UNUSED, 0);
	close(slave);
	close(master);
	close(coprocin);
	close(coprocout);
	init_io(NULL);
	setsparam("TTY", ztrdup(ttystrname));

	opts[INTERACTIVE] = 0;

	syncch = 0;
	do {
	    ret = write(1, &syncch, 1);
	} while (ret != 1 && (
#ifdef EWOULDBLOCK
	    errno == EWOULDBLOCK ||
#else
#ifdef EAGAIN
	    errno == EAGAIN ||
#endif
#endif
	    errno == EINTR));

	execode(prog, 1, 0, "zpty");
	stopmsg = 2;
	mypid = 0; /* trick to ensure we _exit() */
	zexit(lastval, 0);
    }
    master = movefd(master);
    if (master == -1) {
	zerrnam(nam, "cannot duplicate fd %d: %e", master, errno);
	scriptname = oscriptname;
	ineval = oineval;
	return 1;
    }

    p = (Ptycmd) zalloc(sizeof(*p));

    p->name = ztrdup(pname);
    p->args = zarrdup(args);
    p->fd = master;
    p->pid = pid;
    p->echo = echo;
    p->nblock = nblock;
    p->fin = 0;
    p->read = -1;
    p->old = NULL;
    p->olen = 0;

    p->next = ptycmds;
    ptycmds = p;

    if (nblock)
	ptynonblock(master);

    scriptname = oscriptname;
    ineval = oineval;

    do {
	ret = read(master, &syncch, 1);
    } while (ret != 1 && (
#ifdef EWOULDBLOCK
	    errno == EWOULDBLOCK ||
#else
#ifdef EAGAIN
	    errno == EAGAIN ||
#endif
#endif
	    errno == EINTR));

    setiparam_no_convert("REPLY", (zlong)master);

    return 0;
}