Esempio n. 1
0
static Char *
globtilde(Char *s)
{
    Char *name, *u, *home, *res;

    u = s;
    for (s++; *s && *s != '/' && *s != ':'; s++)
	continue;
    name = Strnsave(u + 1, s - (u + 1));
    cleanup_push(name, xfree);
    home = gethdir(name);
    if (home == NULL) {
	if (adrof(STRnonomatch)) {
	    cleanup_until(name);
	    return u;
	}
	if (*name)
	    stderror(ERR_UNKUSER, short2str(name));
	else
	    stderror(ERR_NOHOME);
    }
    cleanup_until(name);
    if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
	res = Strsave(s);
    else
	res = Strspl(home, s);
    xfree(home);
    xfree(u);
    return res;
}
Esempio n. 2
0
/*
 * Source to the file which is the catenation of the argument names.
 */
static int
srccat(Char *cp, Char *dp)
{
    Char *ep = Strspl(cp, dp);
    char   *ptr = short2str(ep);

    xfree(ep);
    return srcfile(ptr, mflag ? 0 : 1, 0);
}
Esempio n. 3
0
/* Returns a newly allocated string, old or NULL */
Char *
globequal(Char *old)
{
    int     dig;
    const Char *dir;
    Char    *b;

    /*
     * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
     * in stack. PWP: let =foobar pass through (for X windows)
     */
    if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
	/* =- */
	const Char *olddir = varval (STRowd);

	if (olddir && *olddir &&
	    !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
	    return Strspl(olddir, &old[2]);
	dig = -1;
	b = &old[2];
    }
    else if (Isdigit(old[1])) {
	/* =<number> */
	dig = old[1] - '0';
	for (b = &old[2]; Isdigit(*b); b++)
	    dig = dig * 10 + (*b - '0');
	if (*b != '\0' && *b != '/')
	    /* =<number>foobar */
	    return old;
    }
    else
	/* =foobar */
	return old;

    dir = getstakd(dig);
    if (dir == NULL)
	return NULL;
    return Strspl(dir, b);
}
Esempio n. 4
0
static void
asyn3(struct wordent *p1, struct wordent *p2)
{
    struct varent *ap;
    struct wordent alout;
    int redid;

    if (p1 == p2)
	return;
    if (p1->word[0] == '(') {
	for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
	    if (p2 == p1)
		return;
	if (p2 == p1->next)
	    return;
	asyn0(p1->next, p2);
	return;
    }
    ap = adrof1(p1->word, &aliases);
    if (ap == 0)
	return;
    alhistp = p1->prev;
    alhistt = p2;
    alvec = ap->vec;
    redid = lex(&alout);
    alhistp = alhistt = 0;
    alvec = 0;
    if (seterr) {
	freelex(&alout);
	stderror(ERR_OLD);
    }
    if (p1->word[0] && eq(p1->word, alout.next->word)) {
	Char *cp;

	cp = alout.next->word;
	alout.next->word = Strspl(STRQNULL, cp);
	xfree((ptr_t) cp);
    }
    p1 = freenod(p1, redid ? p2 : p1->next);
    if (alout.next != &alout) {
	p1->next->prev = alout.prev->prev;
	alout.prev->prev->next = p1->next;
	alout.next->prev = p1;
	p1->next = alout.next;
	xfree((ptr_t)alout.prev->word);
	xfree((ptr_t)(alout.prev));
    }
    reset();			/* throw! */
}
Esempio n. 5
0
static int
iscommand(Char *name)
{
    struct varent *v;
    Char **pv, *sav;
    int hashval, hashval1, i;
    int slash;

    hashval = 0;
    slash = any(short2str(name), '/');
    v = adrof(STRpath);
    
    if (v == 0 || v->vec[0] == 0 || slash)
	pv = justabs;
    else
	pv = v->vec;
    sav = Strspl(STRslash, name);	/* / command name for postpending */
    if (havhash)
	hashval = hashname(name);
    i = 0;
    do {
	if (!slash && pv[0][0] == '/' && havhash) {
	    hashval1 = hash(hashval, i);
	    if (!bit(xhash, hashval1))
		goto cont;
	}
	if (pv[0][0] == 0 || eq(pv[0], STRdot)) {	/* don't make ./xxx */
	    if (executable(NULL, name, 0)) {
		free(sav);
		return i + 1;
	    }
	}
	else {
	    if (executable(*pv, sav, 0)) {
		free(sav);
		return i + 1;
	    }
	}
cont:
	pv++;
	i++;
    } while (*pv);
    free(sav);
    return 0;
}
Esempio n. 6
0
static int
tellmewhat(struct wordent *lexp, Char *str)
{
    struct biltins *bptr;
    struct wordent *sp;
    Char *cmd, *s0, *s1, *s2;
    int i;
    int aliased, found;
    Char qc;

    aliased = 0;
    sp = lexp->next;

    if (adrof1(sp->word, &aliases)) {
	alias(lexp);
	sp = lexp->next;
	aliased = 1;
    }

    s0 = sp->word;		/* to get the memory freeing right... */

    /* handle quoted alias hack */
    if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
	(sp->word)++;

    /* do quoting, if it hasn't been done */
    s1 = s2 = sp->word;
    while (*s2)
	switch (*s2) {
	case '\'':
	case '"':
	    qc = *s2++;
	    while (*s2 && *s2 != qc)
		*s1++ = (Char)(*s2++ | QUOTE);
	    if (*s2)
		s2++;
	    break;
	case '\\':
	    if (*++s2)
		*s1++ = (Char)(*s2++ | QUOTE);
	    break;
	default:
	    *s1++ = *s2++;
	}
    *s1 = '\0';

    for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
	if (eq(sp->word, str2short(bptr->bname))) {
	    if (str == NULL) {
		if (aliased)
		    prlex(cshout, lexp);
		(void)fprintf(cshout, "%s: shell built-in command.\n", 
			       vis_str(sp->word));
	    }
	    else
		(void)Strcpy(str, sp->word);
	    sp->word = s0;	/* we save and then restore this */
	    return 1;
	}
    }

    sp->word = cmd = globone(sp->word, G_IGNORE);

    if ((i = iscommand(sp->word)) != 0) {
	Char **pv;
	struct varent *v;
	int    slash = any(short2str(sp->word), '/');

	v = adrof(STRpath);
	if (v == 0 || v->vec[0] == 0 || slash)
	    pv = justabs;
	else
	    pv = v->vec;

	while (--i)
	    pv++;
	if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
	    if (!slash) {
		sp->word = Strspl(STRdotsl, sp->word);
		prlex(cshout, lexp);
		free(sp->word);
	    }
	    else
		prlex(cshout, lexp);
	}
	else {
	    s1 = Strspl(*pv, STRslash);
	    sp->word = Strspl(s1, sp->word);
	    free(s1);
	    if (str == NULL)
		prlex(cshout, lexp);
	    else
		(void)Strcpy(str, sp->word);
	    free(sp->word);
	}
	found = 1;
    }
    else {
 	if (str == NULL) {
	    if (aliased)
		prlex(cshout, lexp);
	    (void)fprintf(csherr,
			   "%s: Command not found.\n", vis_str(sp->word));
	}
	else
	    (void)Strcpy(str, sp->word);
	found = 0;
    }
    sp->word = s0;		/* we save and then restore this */
    free(cmd);
    return found;
}
Esempio n. 7
0
void
/*ARGSUSED*/
doexec(Char **v, struct command *t)
{
    struct varent *pathv;
    Char *blk[2], **av, *dp, **pv, *sav;
    int i, hashval, hashval1;
    sigset_t nsigset;
    int slash;

    hashval = 0;
    /*
     * Glob the command name. We will search $path even if this does something,
     * as in sh but not in csh.  One special case: if there is no PATH, then we
     * execute only commands which start with '/'.
     */
    blk[0] = t->t_dcom[0];
    blk[1] = 0;
    gflag = 0, tglob(blk);
    if (gflag) {
	pv = globall(blk);
	if (pv == 0) {
	    setname(vis_str(blk[0]));
	    stderror(ERR_NAME | ERR_NOMATCH);
	}
	gargv = 0;
    }
    else
	pv = saveblk(blk);

    trim(pv);

    exerr = 0;
    expath = Strsave(pv[0]);
    Vexpath = expath;

    pathv = adrof(STRpath);
    if (pathv == 0 && expath[0] != '/') {
	blkfree(pv);
	pexerr();
    }
    slash = any(short2str(expath), '/');

    /*
     * Glob the argument list, if necessary. Otherwise trim off the quote bits.
     */
    gflag = 0;
    av = &t->t_dcom[1];
    tglob(av);
    if (gflag) {
	av = globall(av);
	if (av == 0) {
	    blkfree(pv);
	    setname(vis_str(expath));
	    stderror(ERR_NAME | ERR_NOMATCH);
	}
	gargv = 0;
    }
    else
	av = saveblk(av);

    blkfree(t->t_dcom);
    t->t_dcom = blkspl(pv, av);
    free(pv);
    free(av);
    av = t->t_dcom;
    trim(av);

    if (*av == NULL || **av == '\0')
	pexerr();

    xechoit(av);		/* Echo command if -x */
    /*
     * Since all internal file descriptors are set to close on exec, we don't
     * need to close them explicitly here.  Just reorient ourselves for error
     * messages.
     */
    SHIN = 0;
    SHOUT = 1;
    SHERR = 2;
    OLDSTD = 0;
    /*
     * We must do this AFTER any possible forking (like `foo` in glob) so that
     * this shell can still do subprocesses.
     */
    sigemptyset(&nsigset);
    (void)sigprocmask(SIG_SETMASK, &nsigset, NULL);
    /*
     * If no path, no words in path, or a / in the filename then restrict the
     * command search.
     */
    if (pathv == 0 || pathv->vec[0] == 0 || slash)
	pv = justabs;
    else
	pv = pathv->vec;
    sav = Strspl(STRslash, *av); 	/* / command name for postpending */
    Vsav = sav;
    if (havhash)
	hashval = hashname(*av);
    i = 0;
    hits++;
    do {
	/*
	 * Try to save time by looking at the hash table for where this command
	 * could be.  If we are doing delayed hashing, then we put the names in
	 * one at a time, as the user enters them.  This is kinda like Korn
	 * Shell's "tracked aliases".
	 */
	if (!slash && pv[0][0] == '/' && havhash) {
	    hashval1 = hash(hashval, i);
	    if (!bit(xhash, hashval1))
		goto cont;
	}
	if (pv[0][0] == 0 || eq(pv[0], STRdot))	/* don't make ./xxx */
	    texec(*av, av);
	else {
	    dp = Strspl(*pv, sav);
	    Vdp = dp;
	    texec(dp, av);
	    Vdp = 0;
	    free(dp);
	}
	misses++;
cont:
	pv++;
	i++;
    } while (*pv);
    hits--;
    Vsav = 0;
    free(sav);
    pexerr();
    /* NOTREACHED */
}
Esempio n. 8
0
int
main(int argc, char *argv[])
{
    struct sigaction oact;
    Char *cp;
    char *tcp, **tempv;
    const char *ecp;
    sigset_t nsigset;
    int f;

    cshin = stdin;
    cshout = stdout;
    csherr = stderr;

    setprogname(argv[0]);
    settimes();			/* Immed. estab. timing base */

    /*
     * Initialize non constant strings
     */
#ifdef _PATH_BSHELL
    STR_BSHELL = SAVE(_PATH_BSHELL);
#endif
#ifdef _PATH_CSHELL
    STR_SHELLPATH = SAVE(_PATH_CSHELL);
#endif
    STR_environ = blk2short(environ);
    environ = short2blk(STR_environ);	/* So that we can free it */
    STR_WORD_CHARS = SAVE(WORD_CHARS);

    HIST = '!';
    HISTSUB = '^';
    word_chars = STR_WORD_CHARS;

    tempv = argv;
    if (eq(str2short(tempv[0]), STRaout))	/* A.out's are quittable */
	quitit = 1;
    uid = getuid();
    gid = getgid();
    euid = geteuid();
    egid = getegid();
    /*
     * We are a login shell if: 1. we were invoked as -<something> and we had
     * no arguments 2. or we were invoked only with the -l flag
     */
    loginsh = (**tempv == '-' && argc == 1) ||
	(argc == 2 && tempv[1][0] == '-' && tempv[1][1] == 'l' &&
	 tempv[1][2] == '\0');

    if (loginsh && **tempv != '-') {
	/*
	 * Mangle the argv space
	 */
	tempv[1][0] = '\0';
	tempv[1][1] = '\0';
	tempv[1] = NULL;
	for (tcp = *tempv; *tcp++;)
	    continue;
	for (tcp--; tcp >= *tempv; tcp--)
	    tcp[1] = tcp[0];
	*++tcp = '-';
	argc--;
    }
    if (loginsh)
	(void)time(&chktim);

    AsciiOnly = 1;
#ifdef NLS
    (void)setlocale(LC_ALL, "");
    {
	int k;

	for (k = 0200; k <= 0377 && !Isprint(k); k++)
	    continue;
	AsciiOnly = k > 0377;
    }
#else
    AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL;
#endif				/* NLS */

    /*
     * Move the descriptors to safe places. The variable didfds is 0 while we
     * have only FSH* to work with. When didfds is true, we have 0,1,2 and
     * prefer to use these.
     */
    initdesc();
    /*
     * XXX: This is to keep programs that use stdio happy.
     *	    what we really want is freunopen() ....
     *	    Closing cshin cshout and csherr (which are really stdin stdout
     *	    and stderr at this point and then reopening them in the same order
     *	    gives us again stdin == cshin stdout == cshout and stderr == csherr.
     *	    If that was not the case builtins like printf that use stdio
     *	    would break. But in any case we could fix that with memcpy and
     *	    a bit of pointer manipulation...
     *	    Fortunately this is not needed under the current implementation
     *	    of stdio.
     */
    (void)fclose(cshin);
    (void)fclose(cshout);
    (void)fclose(csherr);
    if (!(cshin  = funopen2((void *) &SHIN,  readf, writef, seekf, NULL,
	closef)))
	exit(1);
    if (!(cshout = funopen2((void *) &SHOUT, readf, writef, seekf, NULL,
	closef)))
	exit(1);
    if (!(csherr = funopen2((void *) &SHERR, readf, writef, seekf, NULL,
	closef)))
	exit(1);
    (void)setvbuf(cshin,  NULL, _IOLBF, 0);
    (void)setvbuf(cshout, NULL, _IOLBF, 0);
    (void)setvbuf(csherr, NULL, _IOLBF, 0);

    /*
     * Initialize the shell variables. ARGV and PROMPT are initialized later.
     * STATUS is also munged in several places. CHILD is munged when
     * forking/waiting
     */
    set(STRstatus, Strsave(STR0));

    if ((ecp = getenv("HOME")) != NULL)
	cp = quote(SAVE(ecp));
    else
	cp = NULL;

    if (cp == NULL)
	fast = 1;		/* No home -> can't read scripts */
    else
	set(STRhome, cp);
    dinit(cp);			/* dinit thinks that HOME == cwd in a login
				 * shell */
    /*
     * Grab other useful things from the environment. Should we grab
     * everything??
     */
    if ((ecp = getenv("LOGNAME")) != NULL ||
	(ecp = getenv("USER")) != NULL)
	set(STRuser, quote(SAVE(ecp)));
    if ((ecp = getenv("TERM")) != NULL)
	set(STRterm, quote(SAVE(ecp)));

    /*
     * Re-initialize path if set in environment
     */
    if ((ecp = getenv("PATH")) == NULL) {
#ifdef _PATH_DEFPATH
	importpath(str2short(_PATH_DEFPATH));
#else
	setq(STRpath, defaultpath(), &shvhed);
#endif
    } else {
	importpath(str2short(ecp));
    }

    set(STRshell, Strsave(STR_SHELLPATH));

    doldol = putn((int) getpid());	/* For $$ */
    shtemp = Strspl(STRtmpsh, doldol);	/* For << */

    /*
     * Record the interrupt states from the parent process. If the parent is
     * non-interruptible our hand must be forced or we (and our children) won't
     * be either. Our children inherit termination from our parent. We catch it
     * only if we are the login shell.
     */
    /* parents interruptibility */
    (void)sigaction(SIGINT, NULL, &oact);
    parintr = oact.sa_handler;
    (void)sigaction(SIGTERM, NULL, &oact);
    parterm = oact.sa_handler;

    /* catch these all, login shell or not */
    (void)signal(SIGHUP, phup);	/* exit processing on HUP */
    (void)signal(SIGXCPU, phup);	/* ...and on XCPU */
    (void)signal(SIGXFSZ, phup);	/* ...and on XFSZ */

    /*
     * Process the arguments.
     *
     * Note that processing of -v/-x is actually delayed till after script
     * processing.
     *
     * We set the first character of our name to be '-' if we are a shell
     * running interruptible commands.  Many programs which examine ps'es
     * use this to filter such shells out.
     */
    argc--, tempv++;
    while (argc > 0 && (tcp = tempv[0])[0] == '-' && *++tcp != '\0' && !batch) {
	do
	    switch (*tcp++) {
	    case 0:		/* -	Interruptible, no prompt */
		prompt = 0;
		setintr = 1;
		nofile = 1;
		break;
	    case 'b':		/* -b	Next arg is input file */
		batch = 1;
		break;
	    case 'c':		/* -c	Command input from arg */
		if (argc == 1)
		    xexit(0);
		argc--, tempv++;
		arginp = SAVE(tempv[0]);
		prompt = 0;
		nofile = 1;
		break;
	    case 'e':		/* -e	Exit on any error */
		exiterr = 1;
		break;
	    case 'f':		/* -f	Fast start */
		fast = 1;
		break;
	    case 'i':		/* -i	Interactive, even if !intty */
		intact = 1;
		nofile = 1;
		break;
	    case 'm':		/* -m	read .cshrc (from su) */
		mflag = 1;
		break;
	    case 'n':		/* -n	Don't execute */
		noexec = 1;
		break;
	    case 'q':		/* -q	(Undoc'd) ... die on quit */
		quitit = 1;
		break;
	    case 's':		/* -s	Read from std input */
		nofile = 1;
		break;
	    case 't':		/* -t	Read one line from input */
		onelflg = 2;
		prompt = 0;
		nofile = 1;
		break;
	    case 'v':		/* -v	Echo hist expanded input */
		nverbose = 1;	/* ... later */
		break;
	    case 'x':		/* -x	Echo just before execution */
		nexececho = 1;	/* ... later */
		break;
	    case 'V':		/* -V	Echo hist expanded input */
		setNS(STRverbose);	/* NOW! */
		break;
	    case 'X':		/* -X	Echo just before execution */
		setNS(STRecho);	/* NOW! */
		break;

	} while (*tcp);
	tempv++, argc--;
    }

    if (quitit)			/* With all due haste, for debugging */
	(void)signal(SIGQUIT, SIG_DFL);

    /*
     * Unless prevented by -, -c, -i, -s, or -t, if there are remaining
     * arguments the first of them is the name of a shell file from which to
     * read commands.
     */
    if (nofile == 0 && argc > 0) {
	nofile = open(tempv[0], O_RDONLY);
	if (nofile < 0) {
	    child = 1;		/* So this doesn't return */
	    stderror(ERR_SYSTEM, tempv[0], strerror(errno));
	}
	ffile = SAVE(tempv[0]);
	/*
	 * Replace FSHIN. Handle /dev/std{in,out,err} specially
	 * since once they are closed we cannot open them again.
	 * In that case we use our own saved descriptors
	 */
	if ((SHIN = dmove(nofile, FSHIN)) < 0)
	    switch(nofile) {
	    case 0:
		SHIN = FSHIN;
		break;
	    case 1:
		SHIN = FSHOUT;
		break;
	    case 2:
		SHIN = FSHERR;
		break;
	    default:
		stderror(ERR_SYSTEM, tempv[0], strerror(errno));
		/* NOTREACHED */
	    }
	(void)ioctl(SHIN, FIOCLEX, NULL);
	prompt = 0;
	 /* argc not used any more */ tempv++;
    }

    intty = isatty(SHIN);
    intty |= intact;
    if (intty || (intact && isatty(SHOUT))) {
	if (!batch && (uid != euid || gid != egid)) {
	    errno = EACCES;
	    child = 1;		/* So this doesn't return */
	    stderror(ERR_SYSTEM, "csh", strerror(errno));
	}
    }
    /*
     * Decide whether we should play with signals or not. If we are explicitly
     * told (via -i, or -) or we are a login shell (arg0 starts with -) or the
     * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
     * Note that in only the login shell is it likely that parent may have set
     * signals to be ignored
     */
    if (loginsh || intact || (intty && isatty(SHOUT)))
	setintr = 1;
    settell();
    /*
     * Save the remaining arguments in argv.
     */
    setq(STRargv, blk2short(tempv), &shvhed);

    /*
     * Set up the prompt.
     */
    if (prompt) {
	set(STRprompt, Strsave(uid == 0 ? STRsymhash : STRsymcent));
	/* that's a meta-questionmark */
	set(STRprompt2, Strsave(STRmquestion));
    }

    /*
     * If we are an interactive shell, then start fiddling with the signals;
     * this is a tricky game.
     */
    shpgrp = getpgrp();
    opgrp = tpgrp = -1;
    if (setintr) {
	**argv = '-';
	if (!quitit)		/* Wary! */
	    (void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGINT, pintr);
	sigemptyset(&nsigset);
	(void)sigaddset(&nsigset, SIGINT);
	(void)sigprocmask(SIG_BLOCK, &nsigset, NULL);
	(void)signal(SIGTERM, SIG_IGN);
	if (quitit == 0 && arginp == 0) {
	    (void)signal(SIGTSTP, SIG_IGN);
	    (void)signal(SIGTTIN, SIG_IGN);
	    (void)signal(SIGTTOU, SIG_IGN);
	    /*
	     * Wait till in foreground, in case someone stupidly runs csh &
	     * dont want to try to grab away the tty.
	     */
	    if (isatty(FSHERR))
		f = FSHERR;
	    else if (isatty(FSHOUT))
		f = FSHOUT;
	    else if (isatty(OLDSTD))
		f = OLDSTD;
	    else
		f = -1;
    retry:
	    if ((tpgrp = tcgetpgrp(f)) != -1) {
		if (tpgrp != shpgrp) {
		    sig_t old = signal(SIGTTIN, SIG_DFL);
		    (void)kill(0, SIGTTIN);
		    (void)signal(SIGTTIN, old);
		    goto retry;
		}
		opgrp = shpgrp;
		shpgrp = getpid();
		tpgrp = shpgrp;
		/*
		 * Setpgid will fail if we are a session leader and
		 * mypid == mypgrp (POSIX 4.3.3)
		 */
		if (opgrp != shpgrp)
		    if (setpgid(0, shpgrp) == -1)
			goto notty;
		/*
		 * We do that after we set our process group, to make sure
		 * that the process group belongs to a process in the same
		 * session as the tty (our process and our group) (POSIX 7.2.4)
		 */
		if (tcsetpgrp(f, shpgrp) == -1)
		    goto notty;
		(void)ioctl(dcopy(f, FSHTTY), FIOCLEX, NULL);
	    }
	    if (tpgrp == -1) {
notty:
		(void)fprintf(csherr, "Warning: no access to tty (%s).\n",
			       strerror(errno));
		(void)fprintf(csherr, "Thus no job control in this shell.\n");
	    }
	}
    }
    if ((setintr == 0) && (parintr == SIG_DFL))
	setintr = 1;
    (void)signal(SIGCHLD, pchild);	/* while signals not ready */

    /*
     * Set an exit here in case of an interrupt or error reading the shell
     * start-up scripts.
     */
    reenter = setexit();	/* PWP */
    haderr = 0;			/* In case second time through */
    if (!fast && reenter == 0) {
	/* Will have value(STRhome) here because set fast if don't */
	{
	    sig_t oparintr;
	    sigset_t osigset;
	    int osetintr;

	    oparintr = parintr;
	    osetintr = setintr;
	    sigemptyset(&nsigset);
	    (void)sigaddset(&nsigset, SIGINT);
	    (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);

	    setintr = 0;
	    parintr = SIG_IGN;	/* Disable onintr */
#ifdef _PATH_DOTCSHRC
	    (void)srcfile(_PATH_DOTCSHRC, 0, 0);
#endif
	    if (!fast && !arginp && !onelflg)
		dohash(NULL, NULL);
#ifdef _PATH_DOTLOGIN
	    if (loginsh)
		(void)srcfile(_PATH_DOTLOGIN, 0, 0);
#endif
	    (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
	    setintr = osetintr;
	    parintr = oparintr;
	}
	(void)srccat(value(STRhome), STRsldotcshrc);

	if (!fast && !arginp && !onelflg && !havhash)
	    dohash(NULL, NULL);
	/*
	 * Source history before .login so that it is available in .login
	 */
	if ((cp = value(STRhistfile)) != STRNULL)
	    tildehist[2] = cp;
	dosource(tildehist, NULL);
        if (loginsh)
	      (void)srccat(value(STRhome), STRsldotlogin);
    }

    /*
     * Now are ready for the -v and -x flags
     */
    if (nverbose)
	setNS(STRverbose);
    if (nexececho)
	setNS(STRecho);

    /*
     * All the rest of the world is inside this call. The argument to process
     * indicates whether it should catch "error unwinds".  Thus if we are a
     * interactive shell our call here will never return by being blown past on
     * an error.
     */
    process(setintr);

    /*
     * Mop-up.
     */
    if (intty) {
	if (loginsh) {
	    (void)fprintf(cshout, "logout\n");
	    (void)close(SHIN);
	    child = 1;
	    goodbye();
	}
	else {
	    (void)fprintf(cshout, "exit\n");
	}
    }
    rechist();
    exitstat();
    /* NOTREACHED */
}
Esempio n. 9
0
/*
 * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
 *	we are of course assuming that the file system is standardly
 *	constructed (always have ..'s, directories have links)
 */
Char   *
dcanon(Char *cp, Char *p)
{
    Char *sp;
    Char *p1, *p2;	/* general purpose */
    bool    slash;

    Char    link[PATH_MAX];
    char    tlink[PATH_MAX];
    int     cc;
    Char   *newcp;

    /*
     * christos: if the path given does not start with a slash prepend cwd. If
     * cwd does not start with a path or the result would be too long abort().
     */
    if (*cp != '/') {
	Char    tmpdir[PATH_MAX];

	p1 = value(STRcwd);
	if (p1 == NULL || *p1 != '/')
	    abort();
	if (Strlen(p1) + Strlen(cp) + 1 >= PATH_MAX)
	    abort();
	(void) Strlcpy(tmpdir, p1, sizeof tmpdir/sizeof(Char));
	(void) Strlcat(tmpdir, STRslash, sizeof tmpdir/sizeof(Char));
	(void) Strlcat(tmpdir, cp, sizeof tmpdir/sizeof(Char));
	free(cp);
	cp = p = Strsave(tmpdir);
    }

    while (*p) {		/* for each component */
	sp = p;			/* save slash address */
	while (*++p == '/')	/* flush extra slashes */
	    continue;
	if (p != ++sp)
	    for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
		continue;
	p = sp;			/* save start of component */
	slash = 0;
	while (*p)		/* find next slash or end of path */
	    if (*++p == '/') {
		slash = 1;
		*p = 0;
		break;
	    }

	if (*sp == '\0')	/* if component is null */
	    if (--sp == cp)	/* if path is one char (i.e. /) */
		break;
	    else
		*sp = '\0';
	else if (sp[0] == '.' && sp[1] == 0) {
	    if (slash) {
		for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
		    continue;
		p = --sp;
	    }
	    else if (--sp != cp)
		*sp = '\0';
	}
	else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
	    /*
	     * We have something like "yyy/xxx/..", where "yyy" can be null or
	     * a path starting at /, and "xxx" is a single component. Before
	     * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
	     * symbolic link.
	     */
	    *--sp = 0;		/* form the pathname for readlink */
	    if (sp != cp && !adrof(STRignore_symlinks) &&
		(cc = readlink(short2str(cp), tlink,
			       sizeof tlink-1)) >= 0) {
		tlink[cc] = '\0';
		(void) Strlcpy(link, str2short(tlink), sizeof link/sizeof(Char));

		if (slash)
		    *p = '/';
		/*
		 * Point p to the '/' in "/..", and restore the '/'.
		 */
		*(p = sp) = '/';
		/*
		 * find length of p
		 */
		for (p1 = p; *p1++;)
		    continue;
		if (*link != '/') {
		    /*
		     * Relative path, expand it between the "yyy/" and the
		     * "/..". First, back sp up to the character past "yyy/".
		     */
		    while (*--sp != '/')
			continue;
		    sp++;
		    *sp = 0;
		    /*
		     * New length is "yyy/" + link + "/.." and rest
		     */
		    p1 = newcp = xreallocarray(NULL,
			(sp - cp) + cc + (p1 - p), sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = link; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at expanded "/xxx".
		     */
		    p = sp - cp - 1 + newcp;
		}
		else {
		    /*
		     * New length is link + "/.." and rest
		     */
		    p1 = newcp = xreallocarray(NULL, cc + (p1 - p),
		        sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = link; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at beginning
		     */
		    p = newcp;
		}
		free(cp);
		cp = newcp;
		continue;	/* canonicalize the link */
	    }
	    *sp = '/';
	    if (sp != cp)
		while (*--sp != '/')
		    continue;
	    if (slash) {
		for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
		    continue;
		p = sp;
	    }
	    else if (cp == sp)
		*++sp = '\0';
	    else
		*sp = '\0';
	}
	else {			/* normal dir name (not . or .. or nothing) */

	    if (sp != cp && adrof(STRchase_symlinks) &&
		!adrof(STRignore_symlinks) &&
		(cc = readlink(short2str(cp), tlink,
			       sizeof tlink-1)) >= 0) {
		tlink[cc] = '\0';
		(void) Strlcpy(link, str2short(tlink), sizeof link/sizeof(Char));

		/*
		 * restore the '/'.
		 */
		if (slash)
		    *p = '/';

		/*
		 * point sp to p (rather than backing up).
		 */
		sp = p;

		/*
		 * find length of p
		 */
		for (p1 = p; *p1++;)
		    continue;
		if (*link != '/') {
		    /*
		     * Relative path, expand it between the "yyy/" and the
		     * remainder. First, back sp up to the character past
		     * "yyy/".
		     */
		    while (*--sp != '/')
			continue;
		    sp++;
		    *sp = 0;
		    /*
		     * New length is "yyy/" + link + "/.." and rest
		     */
		    p1 = newcp = xreallocarray(NULL,
			  (sp - cp) + cc + (p1 - p), sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = link; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at expanded "/xxx".
		     */
		    p = sp - cp - 1 + newcp;
		}
		else {
		    /*
		     * New length is link + the rest
		     */
		    p1 = newcp = xreallocarray(NULL, cc + (p1 - p), sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = link; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at beginning
		     */
		    p = newcp;
		}
		free(cp);
		cp = newcp;
		continue;	/* canonicalize the link */
	    }
	    if (slash)
		*p = '/';
	}
    }

    /*
     * fix home...
     */
    p1 = value(STRhome);
    cc = Strlen(p1);
    /*
     * See if we're not in a subdir of STRhome
     */
    if (p1 && *p1 == '/' &&
	(Strncmp(p1, cp, cc) != 0 || (cp[cc] != '/' && cp[cc] != '\0'))) {
	static ino_t home_ino = -1;
	static dev_t home_dev = -1;
	static Char *home_ptr = NULL;
	struct stat statbuf;

	/*
	 * Get dev and ino of STRhome
	 */
	if (home_ptr != p1 &&
	    stat(short2str(p1), &statbuf) != -1) {
	    home_dev = statbuf.st_dev;
	    home_ino = statbuf.st_ino;
	    home_ptr = p1;
	}
	/*
	 * Start comparing dev & ino backwards
	 */
	Strlcpy(link, cp, sizeof link/sizeof(Char));
	p2 = link;
	for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) {
	    if (statbuf.st_dev == home_dev &&
		statbuf.st_ino == home_ino) {
		sp = (Char *) - 1;
		break;
	    }
	    if ((sp = Strrchr(p2, '/')) != NULL)
		*sp = '\0';
	}
	/*
	 * See if we found it
	 */
	if (*p2 && sp == (Char *) -1) {
	    /*
	     * Use STRhome to make '~' work
	     */
	    newcp = Strspl(p1, cp + Strlen(p2));
	    free(cp);
	    cp = newcp;
	}
    }
    return cp;
}
Esempio n. 10
0
/* dnormalize():
 *	If the name starts with . or .. then we might need to normalize
 *	it depending on the symbolic link flags
 */
Char   *
dnormalize(Char *cp)
{

#define UC (unsigned char)
#define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))
#define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1])))

    if ((unsigned char) cp[0] == '/')
	return (Strsave(cp));

    if (adrof(STRignore_symlinks)) {
	int     dotdot = 0;
	Char   *dp, *cwd;
	size_t	len;

	len = (size_t) (Strlen(dcwd->di_name) + 3);
	cwd = xreallocarray(NULL, len, sizeof(Char));
	(void) Strlcpy(cwd, dcwd->di_name, len);

	/*
	 * Ignore . and count ..'s
	 */
	while (*cp) {
	    if (ISDOT(cp)) {
		if (*++cp)
		    cp++;
	    }
	    else if (ISDOTDOT(cp)) {
		dotdot++;
		cp += 2;
		if (*cp)
		    cp++;
	    }
	    else
		break;
	}
	while (dotdot > 0)
	    if ((dp = Strrchr(cwd, '/'))) {
		*dp = '\0';
		dotdot--;
	    }
	    else
		break;

	if (*cp) {
	    cwd[dotdot = Strlen(cwd)] = '/';
	    cwd[dotdot + 1] = '\0';
	    dp = Strspl(cwd, cp);
	    free(cwd);
	    return dp;
	}
	else {
	    if (!*cwd) {
		cwd[0] = '/';
		cwd[1] = '\0';
	    }
	    return cwd;
	}
    }
    return Strsave(cp);
}
Esempio n. 11
0
File: ntfunc.c Progetto: phase/tcsh
int nt_try_fast_exec(struct command *t) {
	register Char  **pv, **av;
	register Char *dp,*sav;
	register char **tt;
	register char *f;
	register struct varent *v;
	register int hashval,i;
	register int slash;
	int rc = 0, gflag;
	Char *vp;
	Char   *blk[2];

	vp = varval(STRNTslowexec);
	if (vp != STRNULL)
		return 1;

	blk[0] = t->t_dcom[0];
	blk[1] = 0;

	// don't do backtick
	if(Strchr(t->t_dcom[0],'`') )
		return 1;


	gflag = tglob(blk);
	if (gflag) {
		pv = globall(blk, gflag);
		if (pv == 0) {
			return 1;
		}
	}
	else
		pv = saveblk(blk);

	trim(pv);

	epath = Strsave(pv[0]);
	v = adrof(STRpath);
	if (v == 0 && epath[0] != '/' && epath[0] != '.') {
		blkfree(pv);
		return 1;
	}
	slash = any(short2str(epath),'/');
	/*
	 * Glob the argument list, if necessary. Otherwise trim off the quote bits.
	 */
	av = &t->t_dcom[1];
	gflag = tglob(av);
	if (gflag) {
		av = globall(av, gflag);/*FIXRESET*/
		if (av == 0) {
			blkfree(pv);
			return 1;
		}
	}
	else
		av = saveblk(av);

	blkfree(t->t_dcom);
	t->t_dcom = blkspl(pv, av);
	xfree((ptr_t) pv);
	xfree((ptr_t) av);
	av = t->t_dcom;
	//trim(av);

	if (*av == NULL || **av == '\0')
		return 1;

	xechoit(av);/*FIXRESET*/		/* Echo command if -x */
	if (v == 0 || v->vec[0] == 0 || slash)
		pv = abspath;
	else
		pv = v->vec;

	sav = Strspl(STRslash,*av);
	hashval = hashval_extern(*av);

	i = 0;
	do {
#pragma warning(disable:4310)
		if (!slash && ABSOLUTEP(pv[0]) && havhash) {
#pragma warning(default:4310)
			if (!bit_extern(hashval,i)){
				pv++;i++;
				continue;
			}
		}
		if (pv[0][0] == 0 || eq(pv[0],STRdot)) {

			tt = short2blk(av);
			f = short2str(*av);

			rc = nt_texec(f, tt);

			blkfree((Char**)tt);
			if (!rc)
				break;
		}
		else {
			dp = Strspl(*pv,sav);
			tt = short2blk(av);
			f = short2str(dp);

			rc = nt_texec(f, tt);

			blkfree((Char**)tt);
			xfree((ptr_t)dp);
			if (!rc)
				break;
		}
		pv++;
		i++;
	}while(*pv);
	return rc;
}
Esempio n. 12
0
/*
 * Form a shell temporary file (in unit 0) from the words
 * of the shell input up to EOF or a line the same as "term".
 * Unit 0 should have been closed before this call.
 */
void
heredoc(Char *term)
{
    eChar  c;
    Char   *Dv[2];
    struct Strbuf lbuf = Strbuf_INIT, mbuf = Strbuf_INIT;
    Char    obuf[BUFSIZE + 1];
#define OBUF_END (obuf + sizeof(obuf) / sizeof (*obuf) - 1)
    Char *lbp, *obp, *mbp;
    Char  **vp;
    int    quoted;
#ifdef HAVE_MKSTEMP
    char   *tmp = short2str(shtemp);
    char   *dot = strrchr(tmp, '.');

    if (!dot)
	stderror(ERR_NAME | ERR_NOMATCH);
    strcpy(dot, TMP_TEMPLATE);

    xclose(0);
    if (mkstemp(tmp) == -1)
	stderror(ERR_SYSTEM, tmp, strerror(errno));
#else /* !HAVE_MKSTEMP */
    char   *tmp;
# ifndef WINNT_NATIVE

again:
# endif /* WINNT_NATIVE */
    tmp = short2str(shtemp);
# if O_CREAT == 0
    if (xcreat(tmp, 0600) < 0)
	stderror(ERR_SYSTEM, tmp, strerror(errno));
# endif
    xclose(0);
    if (xopen(tmp, O_RDWR|O_CREAT|O_EXCL|O_TEMPORARY|O_LARGEFILE, 0600) ==
	-1) {
	int oerrno = errno;
# ifndef WINNT_NATIVE
	if (errno == EEXIST) {
	    if (unlink(tmp) == -1) {
		xfree(shtemp);
		mbp = randsuf();
		shtemp = Strspl(STRtmpsh, mbp);
		xfree(mbp);
	    }
	    goto again;
	}
# endif /* WINNT_NATIVE */
	(void) unlink(tmp);
	errno = oerrno;
 	stderror(ERR_SYSTEM, tmp, strerror(errno));
    }
#endif /* HAVE_MKSTEMP */
    (void) unlink(tmp);		/* 0 0 inode! */
    Dv[0] = term;
    Dv[1] = NULL;
    gflag = 0;
    trim(Dv);
    rscan(Dv, Dtestq);
    quoted = gflag;
    obp = obuf;
    obuf[BUFSIZE] = 0;
    inheredoc = 1;
    cleanup_push(&inheredoc, inheredoc_cleanup);
#ifdef WINNT_NATIVE
    __dup_stdin = 1;
#endif /* WINNT_NATIVE */
    cleanup_push(&lbuf, Strbuf_cleanup);
    cleanup_push(&mbuf, Strbuf_cleanup);
    for (;;) {
	Char **words;

	/*
	 * Read up a line
	 */
	lbuf.len = 0;
	for (;;) {
	    c = readc(1);	/* 1 -> Want EOF returns */
	    if (c == CHAR_ERR || c == '\n')
		break;
	    if ((c &= TRIM) != 0)
		Strbuf_append1(&lbuf, (Char) c);
	}
	Strbuf_terminate(&lbuf);

	/* Catch EOF in the middle of a line. */
	if (c == CHAR_ERR && lbuf.len != 0)
	    c = '\n';

	/*
	 * Check for EOF or compare to terminator -- before expansion
	 */
	if (c == CHAR_ERR || eq(lbuf.s, term))
	    break;

	/*
	 * If term was quoted or -n just pass it on
	 */
	if (quoted || noexec) {
	    Strbuf_append1(&lbuf, '\n');
	    Strbuf_terminate(&lbuf);
	    for (lbp = lbuf.s; (c = *lbp++) != 0;) {
		*obp++ = (Char) c;
		if (obp == OBUF_END) {
		    tmp = short2str(obuf);
		    (void) xwrite(0, tmp, strlen (tmp));
		    obp = obuf;
		}
	    }
	    continue;
	}

	/*
	 * Term wasn't quoted so variable and then command expand the input
	 * line
	 */
	Dcp = lbuf.s;
	Dvp = Dv + 1;
	mbuf.len = 0;
	for (;;) {
	    c = DgetC(DODOL);
	    if (c == DEOF)
		break;
	    if ((c &= TRIM) == 0)
		continue;
	    /* \ quotes \ $ ` here */
	    if (c == '\\') {
		c = DgetC(0);
		if (!any("$\\`", c))
		    unDgetC(c | QUOTE), c = '\\';
		else
		    c |= QUOTE;
	    }
	    Strbuf_append1(&mbuf, (Char) c);
	}
	Strbuf_terminate(&mbuf);

	/*
	 * If any ` in line do command substitution
	 */
	mbp = mbuf.s;
	if (Strchr(mbp, '`') != NULL) {
	    /*
	     * 1 arg to dobackp causes substitution to be literal. Words are
	     * broken only at newlines so that all blanks and tabs are
	     * preserved.  Blank lines (null words) are not discarded.
	     */
	    words = dobackp(mbp, 1);
	}
	else
	    /* Setup trivial vector similar to return of dobackp */
	    Dv[0] = mbp, Dv[1] = NULL, words = Dv;

	/*
	 * Resurrect the words from the command substitution each separated by
	 * a newline.  Note that the last newline of a command substitution
	 * will have been discarded, but we put a newline after the last word
	 * because this represents the newline after the last input line!
	 */
	for (vp= words; *vp; vp++) {
	    for (mbp = *vp; *mbp; mbp++) {
		*obp++ = *mbp & TRIM;
		if (obp == OBUF_END) {
		    tmp = short2str(obuf);
		    (void) xwrite(0, tmp, strlen (tmp));
		    obp = obuf;
		}
	    }
	    *obp++ = '\n';
	    if (obp == OBUF_END) {
	        tmp = short2str(obuf);
		(void) xwrite(0, tmp, strlen (tmp));
		obp = obuf;
	    }
	}
	if (words != Dv)
	    blkfree(words);
    }
    *obp = 0;
    tmp = short2str(obuf);
    (void) xwrite(0, tmp, strlen (tmp));
    (void) lseek(0, (off_t) 0, L_SET);
    cleanup_until(&inheredoc);
}
Esempio n. 13
0
File: sh.dir.c Progetto: lukem/tcsh
/*
 * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
 *	we are of course assuming that the file system is standardly
 *	constructed (always have ..'s, directories have links)
 */
Char   *
dcanon(Char *cp, Char *p)
{
    Char *sp;
    Char *p1, *p2;	/* general purpose */
    int    slash;
#ifdef HAVE_SLASHSLASH
    int    slashslash;
#endif /* HAVE_SLASHSLASH */
    size_t  clen;

#ifdef S_IFLNK			/* if we have symlinks */
    Char *mlink, *newcp;
    char *tlink;
    size_t cc;
#endif /* S_IFLNK */

    clen = Strlen(cp);

    /*
     * christos: if the path given does not start with a slash prepend cwd. If
     * cwd does not start with a slash or the result would be too long try to
     * correct it.
     */
    if (!ABSOLUTEP(cp)) {
	Char *tmpdir;
	size_t	len;

	p1 = varval(STRcwd);
	if (p1 == STRNULL || !ABSOLUTEP(p1)) {
	    Char *new_cwd = agetcwd();

	    if (new_cwd == NULL) {
		xprintf("%s: %s\n", progname, strerror(errno));
		setcopy(STRcwd, str2short("/"), VAR_READWRITE|VAR_NOGLOB);
	    }
	    else
		setv(STRcwd, new_cwd, VAR_READWRITE|VAR_NOGLOB);
	    p1 = varval(STRcwd);
	}
	len = Strlen(p1);
	tmpdir = xmalloc((len + clen + 2) * sizeof (*tmpdir));
	(void) Strcpy(tmpdir, p1);
	(void) Strcat(tmpdir, STRslash);
	(void) Strcat(tmpdir, cp);
	xfree(cp);
	cp = p = tmpdir;
    }

#ifdef HAVE_SLASHSLASH
    slashslash = (cp[0] == '/' && cp[1] == '/');
#endif /* HAVE_SLASHSLASH */

    while (*p) {		/* for each component */
	sp = p;			/* save slash address */
	while (*++p == '/')	/* flush extra slashes */
	    continue;
	if (p != ++sp)
	    for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
		continue;
	p = sp;			/* save start of component */
	slash = 0;
	if (*p) 
	    while (*++p)	/* find next slash or end of path */
		if (*p == '/') {
		    slash = 1;
		    *p = 0;
		    break;
		}

#ifdef HAVE_SLASHSLASH
	if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0')
	    slashslash = 1;
#endif /* HAVE_SLASHSLASH */
	if (*sp == '\0') {	/* if component is null */
	    if (--sp == cp)	/* if path is one char (i.e. /) */ 
		break;
	    else
		*sp = '\0';
	}
	else if (sp[0] == '.' && sp[1] == 0) {
	    if (slash) {
		for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
		    continue;
		p = --sp;
	    }
	    else if (--sp != cp)
		*sp = '\0';
	    else
		sp[1] = '\0';
	}
	else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
	    /*
	     * We have something like "yyy/xxx/..", where "yyy" can be null or
	     * a path starting at /, and "xxx" is a single component. Before
	     * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
	     * symbolic link.
	     */
	    *--sp = 0;		/* form the pathname for readlink */
#ifdef S_IFLNK			/* if we have symlinks */
	    if (sp != cp && /* symlinks != SYM_IGNORE && */
		(tlink = areadlink(short2str(cp))) != NULL) {
		mlink = str2short(tlink);
		xfree(tlink);

		if (slash)
		    *p = '/';
		/*
		 * Point p to the '/' in "/..", and restore the '/'.
		 */
		*(p = sp) = '/';
		if (*mlink != '/') {
		    /*
		     * Relative path, expand it between the "yyy/" and the
		     * "/..". First, back sp up to the character past "yyy/".
		     */
		    while (*--sp != '/')
			continue;
		    sp++;
		    *sp = 0;
		    /*
		     * New length is "yyy/" + mlink + "/.." and rest
		     */
		    p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
					  Strlen(p) + 1) * sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at expanded "/xxx".
		     */
		    p = sp - cp - 1 + newcp;
		}
		else {
		    newcp = Strspl(mlink, p);
		    /*
		     * Restart canonicalization at beginning
		     */
		    p = newcp;
		}
		xfree(cp);
		cp = newcp;
#ifdef HAVE_SLASHSLASH
                slashslash = (cp[0] == '/' && cp[1] == '/');
#endif /* HAVE_SLASHSLASH */
		continue;	/* canonicalize the link */
	    }
#endif /* S_IFLNK */
	    *sp = '/';
	    if (sp != cp)
		while (*--sp != '/')
		    continue;
	    if (slash) {
		for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
		    continue;
		p = sp;
	    }
	    else if (cp == sp)
		*++sp = '\0';
	    else
		*sp = '\0';
	}
	else {			/* normal dir name (not . or .. or nothing) */

#ifdef S_IFLNK			/* if we have symlinks */
	    if (sp != cp && symlinks == SYM_CHASE &&
		(tlink = areadlink(short2str(cp))) != NULL) {
		mlink = str2short(tlink);
		xfree(tlink);

		/*
		 * restore the '/'.
		 */
		if (slash)
		    *p = '/';

		/*
		 * point sp to p (rather than backing up).
		 */
		sp = p;

		if (*mlink != '/') {
		    /*
		     * Relative path, expand it between the "yyy/" and the
		     * remainder. First, back sp up to the character past
		     * "yyy/".
		     */
		    while (*--sp != '/')
			continue;
		    sp++;
		    *sp = 0;
		    /*
		     * New length is "yyy/" + mlink + "/.." and rest
		     */
		    p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
					  Strlen(p) + 1) * sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at expanded "/xxx".
		     */
		    p = sp - cp - 1 + newcp;
		}
		else {
		    newcp = Strspl(mlink, p);
		    /*
		     * Restart canonicalization at beginning
		     */
		    p = newcp;
		}
		xfree(cp);
		cp = newcp;
#ifdef HAVE_SLASHSLASH
                slashslash = (cp[0] == '/' && cp[1] == '/');
#endif /* HAVE_SLASHSLASH */
		continue;	/* canonicalize the mlink */
	    }
#endif /* S_IFLNK */
	    if (slash)
		*p = '/';
	}
    }

    /*
     * fix home...
     */
#ifdef S_IFLNK
    p1 = varval(STRhome);
    cc = Strlen(p1);
    /*
     * See if we're not in a subdir of STRhome
     */
    if (p1 && *p1 == '/' && (Strncmp(p1, cp, cc) != 0 ||
	(cp[cc] != '/' && cp[cc] != '\0'))) {
	static ino_t home_ino = (ino_t) -1;
	static dev_t home_dev = (dev_t) -1;
	static Char *home_ptr = NULL;
	struct stat statbuf;
	int found;
	Char *copy;

	/*
	 * Get dev and ino of STRhome
	 */
	if (home_ptr != p1 &&
	    stat(short2str(p1), &statbuf) != -1) {
	    home_dev = statbuf.st_dev;
	    home_ino = statbuf.st_ino;
	    home_ptr = p1;
	}
	/*
	 * Start comparing dev & ino backwards
	 */
	p2 = copy = Strsave(cp);
	found = 0;
	while (*p2 && stat(short2str(p2), &statbuf) != -1) {
	    if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) &&
			statbuf.st_ino == home_ino) {
			found = 1;
			break;
	    }
	    if ((sp = Strrchr(p2, '/')) != NULL)
		*sp = '\0';
	}
	/*
	 * See if we found it
	 */
	if (*p2 && found) {
	    /*
	     * Use STRhome to make '~' work
	     */
	    newcp = Strspl(p1, cp + Strlen(p2));
	    xfree(cp);
	    cp = newcp;
	}
	xfree(copy);
    }
#endif /* S_IFLNK */

#ifdef HAVE_SLASHSLASH
    if (slashslash) {
	if (cp[1] != '/') {
	    p = xmalloc((Strlen(cp) + 2) * sizeof(Char));
	    *p = '/';
	    (void) Strcpy(&p[1], cp);
	    xfree(cp);
	    cp = p;
	}
    }
    if (cp[1] == '/' && cp[2] == '/') {
	for (p1 = &cp[1], p2 = &cp[2]; (*p1++ = *p2++) != '\0';)
	    continue;
    }
#endif /* HAVE_SLASHSLASH */
    return cp;
}
Esempio n. 14
0
File: sh.dir.c Progetto: lukem/tcsh
/* dnormalize():
 *	The path will be normalized if it
 *	1) is "..",
 *	2) or starts with "../",
 *	3) or ends with "/..",
 *	4) or contains the string "/../",
 *	then it will be normalized, unless those strings are quoted. 
 *	Otherwise, a copy is made and sent back.
 */
Char   *
dnormalize(const Char *cp, int expnd)
{

/* return true if dp is of the form "../xxx" or "/../xxx" */
#define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))
#define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))

#ifdef S_IFLNK
    if (expnd) {
	struct Strbuf buf = Strbuf_INIT;
 	int     dotdot = 0;
	Char   *dp, *cwd;
	const Char *start = cp;
# ifdef HAVE_SLASHSLASH
	int slashslash;
# endif /* HAVE_SLASHSLASH */

	/*
	 * count the number of "../xxx" or "xxx/../xxx" in the path
	 */
	for ( ; *cp && *(cp + 1); cp++)
	    if (IS_DOTDOT(start, cp))
	        dotdot++;

	/*
	 * if none, we are done.
	 */
        if (dotdot == 0)
	    return (Strsave(start));
	
# ifdef notdef
	struct stat sb;
	/*
	 * We disable this test because:
	 * cd /tmp; mkdir dir1 dir2; cd dir2; ln -s /tmp/dir1; cd dir1;
	 * echo ../../dir1 does not expand. We had enabled this before
	 * because it was bothering people with expansions in compilation
	 * lines like -I../../foo. Maybe we need some kind of finer grain
	 * control?
	 *
	 * If the path doesn't exist, we are done too.
	 */
	if (lstat(short2str(start), &sb) != 0 && errno == ENOENT)
	    return (Strsave(start));
# endif

	cwd = xmalloc((Strlen(dcwd->di_name) + 3) * sizeof(Char));
	(void) Strcpy(cwd, dcwd->di_name);

	/*
	 * If the path starts with a slash, we are not relative to
	 * the current working directory.
	 */
	if (ABSOLUTEP(start))
	    *cwd = '\0';
# ifdef HAVE_SLASHSLASH
	slashslash = cwd[0] == '/' && cwd[1] == '/';
# endif /* HAVE_SLASHSLASH */

	/*
	 * Ignore . and count ..'s
	 */
	cp = start;
	do {
	    dotdot = 0;
	    buf.len = 0;
	    while (*cp) 
	        if (IS_DOT(start, cp)) {
	            if (*++cp)
	                cp++;
	        }
	        else if (IS_DOTDOT(start, cp)) {
		    if (buf.len != 0)
		        break; /* finish analyzing .././../xxx/[..] */
		    dotdot++;
		    cp += 2;
		    if (*cp)
		        cp++;
	        }
	        else 
		    Strbuf_append1(&buf, *cp++);

	    Strbuf_terminate(&buf);
	    while (dotdot > 0) 
	        if ((dp = Strrchr(cwd, '/')) != NULL) {
# ifdef HAVE_SLASHSLASH
		    if (dp == &cwd[1]) 
		        slashslash = 1;
# endif /* HAVE_SLASHSLASH */
		        *dp = '\0';
		        dotdot--;
	        }
	        else
		    break;

	    if (!*cwd) {	/* too many ..'s, starts with "/" */
	        cwd[0] = '/';
# ifdef HAVE_SLASHSLASH
		/*
		 * Only append another slash, if already the former cwd
		 * was in a double-slash path.
		 */
		cwd[1] = slashslash ? '/' : '\0';
		cwd[2] = '\0';
# else /* !HAVE_SLASHSLASH */
		cwd[1] = '\0';
# endif /* HAVE_SLASHSLASH */
	    }
# ifdef HAVE_SLASHSLASH
	    else if (slashslash && cwd[1] == '\0') {
		cwd[1] = '/';
		cwd[2] = '\0';
	    }
# endif /* HAVE_SLASHSLASH */

	    if (buf.len != 0) {
		size_t i;

		i = Strlen(cwd);
		if (TRM(cwd[i - 1]) != '/') {
		    cwd[i++] = '/';
		    cwd[i] = '\0';
		}
	        dp = Strspl(cwd, TRM(buf.s[0]) == '/' ? &buf.s[1] : buf.s);
	        xfree(cwd);
	        cwd = dp;
		i = Strlen(cwd) - 1;
	        if (TRM(cwd[i]) == '/')
		    cwd[i] = '\0';
	    }
	    /* Reduction of ".." following the stuff we collected in buf
	     * only makes sense if the directory item in buf really exists.
	     * Avoid reduction of "-I../.." (typical compiler call) to ""
	     * or "/usr/nonexistant/../bin" to "/usr/bin":
	     */
	    if (cwd[0]) {
	        struct stat exists;
		if (0 != stat(short2str(cwd), &exists)) {
		    xfree(buf.s);
		    xfree(cwd);
		    return Strsave(start);
		}
	    }
	} while (*cp != '\0');
	xfree(buf.s);
	return cwd;
    }
#endif /* S_IFLNK */
    return Strsave(cp);
}
Esempio n. 15
0
File: sh.dir.c Progetto: lukem/tcsh
/*
 * create a file called ~/.cshdirs which has a sequence
 * of pushd commands which will restore the dir stack to
 * its state before exit/logout. remember that the order
 * is reversed in the file because we are pushing.
 * -strike
 */
void
recdirs(Char *fname, int def)
{
    int     fp, ftmp, oldidfds;
    int     cdflag = 0;
    struct directory *dp;
    unsigned int    num;
    Char   *snum;
    struct Strbuf qname = Strbuf_INIT;

    if (fname == NULL && !def) 
	return;

    if (fname == NULL) {
	if ((fname = varval(STRdirsfile)) == STRNULL)
	    fname = Strspl(varval(STRhome), &STRtildotdirs[1]);
	else
	    fname = Strsave(fname);
    }
    else 
	fname = globone(fname, G_ERROR);
    cleanup_push(fname, xfree);

    if ((fp = xcreat(short2str(fname), 0600)) == -1) {
	cleanup_until(fname);
	return;
    }

    if ((snum = varval(STRsavedirs)) == STRNULL || snum[0] == '\0') 
	num = (unsigned int) ~0;
    else
	num = (unsigned int) atoi(short2str(snum));

    oldidfds = didfds;
    didfds = 0;
    ftmp = SHOUT;
    SHOUT = fp;

    cleanup_push(&qname, Strbuf_cleanup);
    dp = dcwd->di_next;
    do {
	if (dp == &dhead)
	    continue;

	if (cdflag == 0) {
	    cdflag = 1;
	    xprintf("cd %S\n", quote_meta(&qname, dp->di_name));
	}
	else
	    xprintf("pushd %S\n", quote_meta(&qname, dp->di_name));

	if (num-- == 0)
	    break;

    } while ((dp = dp->di_next) != dcwd->di_next);

    xclose(fp);
    SHOUT = ftmp;
    didfds = oldidfds;
    cleanup_until(fname);
}