1*d1e4d7ceSDavid van Moolenbroek /* $NetBSD: dir.c,v 1.30 2013/07/16 17:47:43 christos Exp $ */
2*d1e4d7ceSDavid van Moolenbroek
3*d1e4d7ceSDavid van Moolenbroek /*-
4*d1e4d7ceSDavid van Moolenbroek * Copyright (c) 1980, 1991, 1993
5*d1e4d7ceSDavid van Moolenbroek * The Regents of the University of California. All rights reserved.
6*d1e4d7ceSDavid van Moolenbroek *
7*d1e4d7ceSDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
8*d1e4d7ceSDavid van Moolenbroek * modification, are permitted provided that the following conditions
9*d1e4d7ceSDavid van Moolenbroek * are met:
10*d1e4d7ceSDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
11*d1e4d7ceSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
12*d1e4d7ceSDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
13*d1e4d7ceSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
14*d1e4d7ceSDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
15*d1e4d7ceSDavid van Moolenbroek * 3. Neither the name of the University nor the names of its contributors
16*d1e4d7ceSDavid van Moolenbroek * may be used to endorse or promote products derived from this software
17*d1e4d7ceSDavid van Moolenbroek * without specific prior written permission.
18*d1e4d7ceSDavid van Moolenbroek *
19*d1e4d7ceSDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*d1e4d7ceSDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*d1e4d7ceSDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*d1e4d7ceSDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*d1e4d7ceSDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*d1e4d7ceSDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*d1e4d7ceSDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*d1e4d7ceSDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*d1e4d7ceSDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*d1e4d7ceSDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*d1e4d7ceSDavid van Moolenbroek * SUCH DAMAGE.
30*d1e4d7ceSDavid van Moolenbroek */
31*d1e4d7ceSDavid van Moolenbroek
32*d1e4d7ceSDavid van Moolenbroek #include <sys/cdefs.h>
33*d1e4d7ceSDavid van Moolenbroek #ifndef lint
34*d1e4d7ceSDavid van Moolenbroek #if 0
35*d1e4d7ceSDavid van Moolenbroek static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 5/31/93";
36*d1e4d7ceSDavid van Moolenbroek #else
37*d1e4d7ceSDavid van Moolenbroek __RCSID("$NetBSD: dir.c,v 1.30 2013/07/16 17:47:43 christos Exp $");
38*d1e4d7ceSDavid van Moolenbroek #endif
39*d1e4d7ceSDavid van Moolenbroek #endif /* not lint */
40*d1e4d7ceSDavid van Moolenbroek
41*d1e4d7ceSDavid van Moolenbroek #include <sys/param.h>
42*d1e4d7ceSDavid van Moolenbroek #include <sys/stat.h>
43*d1e4d7ceSDavid van Moolenbroek
44*d1e4d7ceSDavid van Moolenbroek #include <errno.h>
45*d1e4d7ceSDavid van Moolenbroek #include <stdarg.h>
46*d1e4d7ceSDavid van Moolenbroek #include <stdlib.h>
47*d1e4d7ceSDavid van Moolenbroek #include <string.h>
48*d1e4d7ceSDavid van Moolenbroek #include <unistd.h>
49*d1e4d7ceSDavid van Moolenbroek
50*d1e4d7ceSDavid van Moolenbroek #include "csh.h"
51*d1e4d7ceSDavid van Moolenbroek #include "dir.h"
52*d1e4d7ceSDavid van Moolenbroek #include "extern.h"
53*d1e4d7ceSDavid van Moolenbroek
54*d1e4d7ceSDavid van Moolenbroek /* Directory management. */
55*d1e4d7ceSDavid van Moolenbroek
56*d1e4d7ceSDavid van Moolenbroek static struct directory *dfind(Char *);
57*d1e4d7ceSDavid van Moolenbroek static Char *dfollow(Char *);
58*d1e4d7ceSDavid van Moolenbroek static void printdirs(void);
59*d1e4d7ceSDavid van Moolenbroek static Char *dgoto(Char *);
60*d1e4d7ceSDavid van Moolenbroek static void skipargs(Char ***, const char *);
61*d1e4d7ceSDavid van Moolenbroek static void dnewcwd(struct directory *);
62*d1e4d7ceSDavid van Moolenbroek static void dset(Char *);
63*d1e4d7ceSDavid van Moolenbroek
64*d1e4d7ceSDavid van Moolenbroek struct directory dhead; /* "head" of loop */
65*d1e4d7ceSDavid van Moolenbroek int printd; /* force name to be printed */
66*d1e4d7ceSDavid van Moolenbroek
67*d1e4d7ceSDavid van Moolenbroek static int dirflag = 0;
68*d1e4d7ceSDavid van Moolenbroek
69*d1e4d7ceSDavid van Moolenbroek /*
70*d1e4d7ceSDavid van Moolenbroek * dinit - initialize current working directory
71*d1e4d7ceSDavid van Moolenbroek */
72*d1e4d7ceSDavid van Moolenbroek void
dinit(Char * hp)73*d1e4d7ceSDavid van Moolenbroek dinit(Char *hp)
74*d1e4d7ceSDavid van Moolenbroek {
75*d1e4d7ceSDavid van Moolenbroek static const char emsg[] = "csh: Trying to start from \"%s\"\n";
76*d1e4d7ceSDavid van Moolenbroek char path[MAXPATHLEN];
77*d1e4d7ceSDavid van Moolenbroek struct directory *dp;
78*d1e4d7ceSDavid van Moolenbroek const char *ecp;
79*d1e4d7ceSDavid van Moolenbroek Char *cp;
80*d1e4d7ceSDavid van Moolenbroek
81*d1e4d7ceSDavid van Moolenbroek /* Don't believe the login shell home, because it may be a symlink */
82*d1e4d7ceSDavid van Moolenbroek ecp = getcwd(path, MAXPATHLEN);
83*d1e4d7ceSDavid van Moolenbroek if (ecp == NULL || *ecp == '\0') {
84*d1e4d7ceSDavid van Moolenbroek (void)fprintf(csherr, "csh: %s\n", strerror(errno));
85*d1e4d7ceSDavid van Moolenbroek if (hp && *hp) {
86*d1e4d7ceSDavid van Moolenbroek ecp = short2str(hp);
87*d1e4d7ceSDavid van Moolenbroek if (chdir(ecp) == -1)
88*d1e4d7ceSDavid van Moolenbroek cp = NULL;
89*d1e4d7ceSDavid van Moolenbroek else
90*d1e4d7ceSDavid van Moolenbroek cp = Strsave(hp);
91*d1e4d7ceSDavid van Moolenbroek (void)fprintf(csherr, emsg, vis_str(hp));
92*d1e4d7ceSDavid van Moolenbroek }
93*d1e4d7ceSDavid van Moolenbroek else
94*d1e4d7ceSDavid van Moolenbroek cp = NULL;
95*d1e4d7ceSDavid van Moolenbroek if (cp == NULL) {
96*d1e4d7ceSDavid van Moolenbroek (void)fprintf(csherr, emsg, "/");
97*d1e4d7ceSDavid van Moolenbroek if (chdir("/") == -1) {
98*d1e4d7ceSDavid van Moolenbroek /* I am not even try to print an error message! */
99*d1e4d7ceSDavid van Moolenbroek xexit(1);
100*d1e4d7ceSDavid van Moolenbroek }
101*d1e4d7ceSDavid van Moolenbroek cp = SAVE("/");
102*d1e4d7ceSDavid van Moolenbroek }
103*d1e4d7ceSDavid van Moolenbroek }
104*d1e4d7ceSDavid van Moolenbroek else {
105*d1e4d7ceSDavid van Moolenbroek struct stat swd, shp;
106*d1e4d7ceSDavid van Moolenbroek
107*d1e4d7ceSDavid van Moolenbroek /*
108*d1e4d7ceSDavid van Moolenbroek * See if $HOME is the working directory we got and use that
109*d1e4d7ceSDavid van Moolenbroek */
110*d1e4d7ceSDavid van Moolenbroek if (hp && *hp &&
111*d1e4d7ceSDavid van Moolenbroek stat(ecp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
112*d1e4d7ceSDavid van Moolenbroek swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
113*d1e4d7ceSDavid van Moolenbroek cp = Strsave(hp);
114*d1e4d7ceSDavid van Moolenbroek else {
115*d1e4d7ceSDavid van Moolenbroek const char *cwd;
116*d1e4d7ceSDavid van Moolenbroek
117*d1e4d7ceSDavid van Moolenbroek /*
118*d1e4d7ceSDavid van Moolenbroek * use PWD if we have it (for subshells)
119*d1e4d7ceSDavid van Moolenbroek */
120*d1e4d7ceSDavid van Moolenbroek if ((cwd = getenv("PWD")) != NULL) {
121*d1e4d7ceSDavid van Moolenbroek if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
122*d1e4d7ceSDavid van Moolenbroek swd.st_ino == shp.st_ino)
123*d1e4d7ceSDavid van Moolenbroek ecp = cwd;
124*d1e4d7ceSDavid van Moolenbroek }
125*d1e4d7ceSDavid van Moolenbroek cp = dcanon(SAVE(ecp), STRNULL);
126*d1e4d7ceSDavid van Moolenbroek }
127*d1e4d7ceSDavid van Moolenbroek }
128*d1e4d7ceSDavid van Moolenbroek
129*d1e4d7ceSDavid van Moolenbroek dp = (struct directory *)xcalloc(1, sizeof(struct directory));
130*d1e4d7ceSDavid van Moolenbroek dp->di_name = cp;
131*d1e4d7ceSDavid van Moolenbroek dp->di_count = 0;
132*d1e4d7ceSDavid van Moolenbroek dhead.di_next = dhead.di_prev = dp;
133*d1e4d7ceSDavid van Moolenbroek dp->di_next = dp->di_prev = &dhead;
134*d1e4d7ceSDavid van Moolenbroek printd = 0;
135*d1e4d7ceSDavid van Moolenbroek dnewcwd(dp);
136*d1e4d7ceSDavid van Moolenbroek }
137*d1e4d7ceSDavid van Moolenbroek
138*d1e4d7ceSDavid van Moolenbroek static void
dset(Char * dp)139*d1e4d7ceSDavid van Moolenbroek dset(Char *dp)
140*d1e4d7ceSDavid van Moolenbroek {
141*d1e4d7ceSDavid van Moolenbroek Char **vec;
142*d1e4d7ceSDavid van Moolenbroek
143*d1e4d7ceSDavid van Moolenbroek /*
144*d1e4d7ceSDavid van Moolenbroek * Don't call set() directly cause if the directory contains ` or
145*d1e4d7ceSDavid van Moolenbroek * other junk characters glob will fail.
146*d1e4d7ceSDavid van Moolenbroek */
147*d1e4d7ceSDavid van Moolenbroek
148*d1e4d7ceSDavid van Moolenbroek vec = xmalloc((size_t)(2 * sizeof(Char **)));
149*d1e4d7ceSDavid van Moolenbroek vec[0] = Strsave(dp);
150*d1e4d7ceSDavid van Moolenbroek vec[1] = 0;
151*d1e4d7ceSDavid van Moolenbroek setq(STRcwd, vec, &shvhed);
152*d1e4d7ceSDavid van Moolenbroek Setenv(STRPWD, dp);
153*d1e4d7ceSDavid van Moolenbroek }
154*d1e4d7ceSDavid van Moolenbroek
155*d1e4d7ceSDavid van Moolenbroek #define DIR_LONG 1
156*d1e4d7ceSDavid van Moolenbroek #define DIR_VERT 2
157*d1e4d7ceSDavid van Moolenbroek #define DIR_LINE 4
158*d1e4d7ceSDavid van Moolenbroek
159*d1e4d7ceSDavid van Moolenbroek static void
skipargs(Char *** v,const char * str)160*d1e4d7ceSDavid van Moolenbroek skipargs(Char ***v, const char *str)
161*d1e4d7ceSDavid van Moolenbroek {
162*d1e4d7ceSDavid van Moolenbroek Char **n, *s;
163*d1e4d7ceSDavid van Moolenbroek
164*d1e4d7ceSDavid van Moolenbroek n = *v;
165*d1e4d7ceSDavid van Moolenbroek dirflag = 0;
166*d1e4d7ceSDavid van Moolenbroek for (n++; *n != NULL && (*n)[0] == '-'; n++)
167*d1e4d7ceSDavid van Moolenbroek for (s = &((*n)[1]); *s; s++)
168*d1e4d7ceSDavid van Moolenbroek switch (*s) {
169*d1e4d7ceSDavid van Moolenbroek case 'l':
170*d1e4d7ceSDavid van Moolenbroek dirflag |= DIR_LONG;
171*d1e4d7ceSDavid van Moolenbroek break;
172*d1e4d7ceSDavid van Moolenbroek case 'n':
173*d1e4d7ceSDavid van Moolenbroek dirflag |= DIR_LINE;
174*d1e4d7ceSDavid van Moolenbroek break;
175*d1e4d7ceSDavid van Moolenbroek case 'v':
176*d1e4d7ceSDavid van Moolenbroek dirflag |= DIR_VERT;
177*d1e4d7ceSDavid van Moolenbroek break;
178*d1e4d7ceSDavid van Moolenbroek default:
179*d1e4d7ceSDavid van Moolenbroek stderror(ERR_DIRUS, vis_str(**v), str);
180*d1e4d7ceSDavid van Moolenbroek /* NOTREACHED */
181*d1e4d7ceSDavid van Moolenbroek }
182*d1e4d7ceSDavid van Moolenbroek *v = n;
183*d1e4d7ceSDavid van Moolenbroek }
184*d1e4d7ceSDavid van Moolenbroek
185*d1e4d7ceSDavid van Moolenbroek /*
186*d1e4d7ceSDavid van Moolenbroek * dodirs - list all directories in directory loop
187*d1e4d7ceSDavid van Moolenbroek */
188*d1e4d7ceSDavid van Moolenbroek void
189*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dodirs(Char ** v,struct command * t)190*d1e4d7ceSDavid van Moolenbroek dodirs(Char **v, struct command *t)
191*d1e4d7ceSDavid van Moolenbroek {
192*d1e4d7ceSDavid van Moolenbroek skipargs(&v, "");
193*d1e4d7ceSDavid van Moolenbroek
194*d1e4d7ceSDavid van Moolenbroek if (*v != NULL)
195*d1e4d7ceSDavid van Moolenbroek stderror(ERR_DIRUS, "dirs", "");
196*d1e4d7ceSDavid van Moolenbroek printdirs();
197*d1e4d7ceSDavid van Moolenbroek }
198*d1e4d7ceSDavid van Moolenbroek
199*d1e4d7ceSDavid van Moolenbroek static void
printdirs(void)200*d1e4d7ceSDavid van Moolenbroek printdirs(void)
201*d1e4d7ceSDavid van Moolenbroek {
202*d1e4d7ceSDavid van Moolenbroek struct directory *dp;
203*d1e4d7ceSDavid van Moolenbroek Char *hp, *s;
204*d1e4d7ceSDavid van Moolenbroek size_t cur, idx, len;
205*d1e4d7ceSDavid van Moolenbroek
206*d1e4d7ceSDavid van Moolenbroek hp = value(STRhome);
207*d1e4d7ceSDavid van Moolenbroek if (*hp == '\0')
208*d1e4d7ceSDavid van Moolenbroek hp = NULL;
209*d1e4d7ceSDavid van Moolenbroek dp = dcwd;
210*d1e4d7ceSDavid van Moolenbroek idx = 0;
211*d1e4d7ceSDavid van Moolenbroek cur = 0;
212*d1e4d7ceSDavid van Moolenbroek do {
213*d1e4d7ceSDavid van Moolenbroek if (dp == &dhead)
214*d1e4d7ceSDavid van Moolenbroek continue;
215*d1e4d7ceSDavid van Moolenbroek if (dirflag & DIR_VERT) {
216*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "%zu\t", idx++);
217*d1e4d7ceSDavid van Moolenbroek cur = 0;
218*d1e4d7ceSDavid van Moolenbroek }
219*d1e4d7ceSDavid van Moolenbroek if (!(dirflag & DIR_LONG) && hp != NULL && !eq(hp, STRslash) &&
220*d1e4d7ceSDavid van Moolenbroek (len = Strlen(hp), Strncmp(hp, dp->di_name, len) == 0) &&
221*d1e4d7ceSDavid van Moolenbroek (dp->di_name[len] == '\0' || dp->di_name[len] == '/'))
222*d1e4d7ceSDavid van Moolenbroek len = Strlen(s = (dp->di_name + len)) + 2;
223*d1e4d7ceSDavid van Moolenbroek else
224*d1e4d7ceSDavid van Moolenbroek len = Strlen(s = dp->di_name) + 1;
225*d1e4d7ceSDavid van Moolenbroek
226*d1e4d7ceSDavid van Moolenbroek cur += len;
227*d1e4d7ceSDavid van Moolenbroek if ((dirflag & DIR_LINE) && cur >= 80 - 1 && len < 80) {
228*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "\n");
229*d1e4d7ceSDavid van Moolenbroek cur = len;
230*d1e4d7ceSDavid van Moolenbroek }
231*d1e4d7ceSDavid van Moolenbroek (void) fprintf(cshout, "%s%s%c", (s != dp->di_name)? "~" : "",
232*d1e4d7ceSDavid van Moolenbroek vis_str(s), (dirflag & DIR_VERT) ? '\n' : ' ');
233*d1e4d7ceSDavid van Moolenbroek } while ((dp = dp->di_prev) != dcwd);
234*d1e4d7ceSDavid van Moolenbroek if (!(dirflag & DIR_VERT))
235*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "\n");
236*d1e4d7ceSDavid van Moolenbroek }
237*d1e4d7ceSDavid van Moolenbroek
238*d1e4d7ceSDavid van Moolenbroek void
dtildepr(Char * home,Char * dir)239*d1e4d7ceSDavid van Moolenbroek dtildepr(Char *home, Char *dir)
240*d1e4d7ceSDavid van Moolenbroek {
241*d1e4d7ceSDavid van Moolenbroek if (!eq(home, STRslash) && prefix(home, dir))
242*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "~%s", vis_str(dir + Strlen(home)));
243*d1e4d7ceSDavid van Moolenbroek else
244*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "%s", vis_str(dir));
245*d1e4d7ceSDavid van Moolenbroek }
246*d1e4d7ceSDavid van Moolenbroek
247*d1e4d7ceSDavid van Moolenbroek void
dtilde(void)248*d1e4d7ceSDavid van Moolenbroek dtilde(void)
249*d1e4d7ceSDavid van Moolenbroek {
250*d1e4d7ceSDavid van Moolenbroek struct directory *d;
251*d1e4d7ceSDavid van Moolenbroek
252*d1e4d7ceSDavid van Moolenbroek d = dcwd;
253*d1e4d7ceSDavid van Moolenbroek do {
254*d1e4d7ceSDavid van Moolenbroek if (d == &dhead)
255*d1e4d7ceSDavid van Moolenbroek continue;
256*d1e4d7ceSDavid van Moolenbroek d->di_name = dcanon(d->di_name, STRNULL);
257*d1e4d7ceSDavid van Moolenbroek } while ((d = d->di_prev) != dcwd);
258*d1e4d7ceSDavid van Moolenbroek
259*d1e4d7ceSDavid van Moolenbroek dset(dcwd->di_name);
260*d1e4d7ceSDavid van Moolenbroek }
261*d1e4d7ceSDavid van Moolenbroek
262*d1e4d7ceSDavid van Moolenbroek
263*d1e4d7ceSDavid van Moolenbroek /* dnormalize():
264*d1e4d7ceSDavid van Moolenbroek * If the name starts with . or .. then we might need to normalize
265*d1e4d7ceSDavid van Moolenbroek * it depending on the symbolic link flags
266*d1e4d7ceSDavid van Moolenbroek */
267*d1e4d7ceSDavid van Moolenbroek Char *
dnormalize(Char * cp)268*d1e4d7ceSDavid van Moolenbroek dnormalize(Char *cp)
269*d1e4d7ceSDavid van Moolenbroek {
270*d1e4d7ceSDavid van Moolenbroek #define UC (unsigned char)
271*d1e4d7ceSDavid van Moolenbroek #define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))
272*d1e4d7ceSDavid van Moolenbroek #define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1])))
273*d1e4d7ceSDavid van Moolenbroek if ((unsigned char) cp[0] == '/')
274*d1e4d7ceSDavid van Moolenbroek return (Strsave(cp));
275*d1e4d7ceSDavid van Moolenbroek
276*d1e4d7ceSDavid van Moolenbroek if (adrof(STRignore_symlinks)) {
277*d1e4d7ceSDavid van Moolenbroek size_t dotdot = 0;
278*d1e4d7ceSDavid van Moolenbroek Char *dp, *cwd;
279*d1e4d7ceSDavid van Moolenbroek
280*d1e4d7ceSDavid van Moolenbroek cwd = xmalloc((size_t)((Strlen(dcwd->di_name) + 3) *
281*d1e4d7ceSDavid van Moolenbroek sizeof(Char)));
282*d1e4d7ceSDavid van Moolenbroek (void)Strcpy(cwd, dcwd->di_name);
283*d1e4d7ceSDavid van Moolenbroek
284*d1e4d7ceSDavid van Moolenbroek /*
285*d1e4d7ceSDavid van Moolenbroek * Ignore . and count ..'s
286*d1e4d7ceSDavid van Moolenbroek */
287*d1e4d7ceSDavid van Moolenbroek while (*cp) {
288*d1e4d7ceSDavid van Moolenbroek if (ISDOT(cp)) {
289*d1e4d7ceSDavid van Moolenbroek if (*++cp)
290*d1e4d7ceSDavid van Moolenbroek cp++;
291*d1e4d7ceSDavid van Moolenbroek }
292*d1e4d7ceSDavid van Moolenbroek else if (ISDOTDOT(cp)) {
293*d1e4d7ceSDavid van Moolenbroek dotdot++;
294*d1e4d7ceSDavid van Moolenbroek cp += 2;
295*d1e4d7ceSDavid van Moolenbroek if (*cp)
296*d1e4d7ceSDavid van Moolenbroek cp++;
297*d1e4d7ceSDavid van Moolenbroek }
298*d1e4d7ceSDavid van Moolenbroek else
299*d1e4d7ceSDavid van Moolenbroek break;
300*d1e4d7ceSDavid van Moolenbroek }
301*d1e4d7ceSDavid van Moolenbroek while (dotdot > 0) {
302*d1e4d7ceSDavid van Moolenbroek dp = Strrchr(cwd, '/');
303*d1e4d7ceSDavid van Moolenbroek if (dp) {
304*d1e4d7ceSDavid van Moolenbroek *dp = '\0';
305*d1e4d7ceSDavid van Moolenbroek dotdot--;
306*d1e4d7ceSDavid van Moolenbroek }
307*d1e4d7ceSDavid van Moolenbroek else
308*d1e4d7ceSDavid van Moolenbroek break;
309*d1e4d7ceSDavid van Moolenbroek }
310*d1e4d7ceSDavid van Moolenbroek
311*d1e4d7ceSDavid van Moolenbroek if (*cp) {
312*d1e4d7ceSDavid van Moolenbroek cwd[dotdot = Strlen(cwd)] = '/';
313*d1e4d7ceSDavid van Moolenbroek cwd[dotdot + 1] = '\0';
314*d1e4d7ceSDavid van Moolenbroek dp = Strspl(cwd, cp);
315*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cwd);
316*d1e4d7ceSDavid van Moolenbroek return dp;
317*d1e4d7ceSDavid van Moolenbroek }
318*d1e4d7ceSDavid van Moolenbroek else {
319*d1e4d7ceSDavid van Moolenbroek if (!*cwd) {
320*d1e4d7ceSDavid van Moolenbroek cwd[0] = '/';
321*d1e4d7ceSDavid van Moolenbroek cwd[1] = '\0';
322*d1e4d7ceSDavid van Moolenbroek }
323*d1e4d7ceSDavid van Moolenbroek return cwd;
324*d1e4d7ceSDavid van Moolenbroek }
325*d1e4d7ceSDavid van Moolenbroek }
326*d1e4d7ceSDavid van Moolenbroek return Strsave(cp);
327*d1e4d7ceSDavid van Moolenbroek }
328*d1e4d7ceSDavid van Moolenbroek
329*d1e4d7ceSDavid van Moolenbroek /*
330*d1e4d7ceSDavid van Moolenbroek * dochngd - implement chdir command.
331*d1e4d7ceSDavid van Moolenbroek */
332*d1e4d7ceSDavid van Moolenbroek void
333*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dochngd(Char ** v,struct command * t)334*d1e4d7ceSDavid van Moolenbroek dochngd(Char **v, struct command *t)
335*d1e4d7ceSDavid van Moolenbroek {
336*d1e4d7ceSDavid van Moolenbroek struct directory *dp;
337*d1e4d7ceSDavid van Moolenbroek Char *cp;
338*d1e4d7ceSDavid van Moolenbroek
339*d1e4d7ceSDavid van Moolenbroek skipargs(&v, " [<dir>]");
340*d1e4d7ceSDavid van Moolenbroek printd = 0;
341*d1e4d7ceSDavid van Moolenbroek if (*v == NULL) {
342*d1e4d7ceSDavid van Moolenbroek if ((cp = value(STRhome)) == NULL || *cp == 0)
343*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_NOHOMEDIR);
344*d1e4d7ceSDavid van Moolenbroek if (chdir(short2str(cp)) < 0)
345*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_CANTCHANGE);
346*d1e4d7ceSDavid van Moolenbroek cp = Strsave(cp);
347*d1e4d7ceSDavid van Moolenbroek }
348*d1e4d7ceSDavid van Moolenbroek else if (v[1] != NULL)
349*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_TOOMANY);
350*d1e4d7ceSDavid van Moolenbroek else if ((dp = dfind(*v)) != 0) {
351*d1e4d7ceSDavid van Moolenbroek char *tmp;
352*d1e4d7ceSDavid van Moolenbroek
353*d1e4d7ceSDavid van Moolenbroek printd = 1;
354*d1e4d7ceSDavid van Moolenbroek if (chdir(tmp = short2str(dp->di_name)) < 0)
355*d1e4d7ceSDavid van Moolenbroek stderror(ERR_SYSTEM, tmp, strerror(errno));
356*d1e4d7ceSDavid van Moolenbroek dcwd->di_prev->di_next = dcwd->di_next;
357*d1e4d7ceSDavid van Moolenbroek dcwd->di_next->di_prev = dcwd->di_prev;
358*d1e4d7ceSDavid van Moolenbroek dfree(dcwd);
359*d1e4d7ceSDavid van Moolenbroek dnewcwd(dp);
360*d1e4d7ceSDavid van Moolenbroek return;
361*d1e4d7ceSDavid van Moolenbroek }
362*d1e4d7ceSDavid van Moolenbroek else
363*d1e4d7ceSDavid van Moolenbroek cp = dfollow(*v);
364*d1e4d7ceSDavid van Moolenbroek dp = (struct directory *)xcalloc(1, sizeof(struct directory));
365*d1e4d7ceSDavid van Moolenbroek dp->di_name = cp;
366*d1e4d7ceSDavid van Moolenbroek dp->di_count = 0;
367*d1e4d7ceSDavid van Moolenbroek dp->di_next = dcwd->di_next;
368*d1e4d7ceSDavid van Moolenbroek dp->di_prev = dcwd->di_prev;
369*d1e4d7ceSDavid van Moolenbroek dp->di_prev->di_next = dp;
370*d1e4d7ceSDavid van Moolenbroek dp->di_next->di_prev = dp;
371*d1e4d7ceSDavid van Moolenbroek dfree(dcwd);
372*d1e4d7ceSDavid van Moolenbroek dnewcwd(dp);
373*d1e4d7ceSDavid van Moolenbroek }
374*d1e4d7ceSDavid van Moolenbroek
375*d1e4d7ceSDavid van Moolenbroek static Char *
dgoto(Char * cp)376*d1e4d7ceSDavid van Moolenbroek dgoto(Char *cp)
377*d1e4d7ceSDavid van Moolenbroek {
378*d1e4d7ceSDavid van Moolenbroek Char *dp;
379*d1e4d7ceSDavid van Moolenbroek
380*d1e4d7ceSDavid van Moolenbroek if (*cp != '/') {
381*d1e4d7ceSDavid van Moolenbroek Char *p, *q;
382*d1e4d7ceSDavid van Moolenbroek size_t cwdlen;
383*d1e4d7ceSDavid van Moolenbroek
384*d1e4d7ceSDavid van Moolenbroek for (p = dcwd->di_name; *p++;)
385*d1e4d7ceSDavid van Moolenbroek continue;
386*d1e4d7ceSDavid van Moolenbroek if ((cwdlen = (size_t)(p - dcwd->di_name - 1)) == 1) /* root */
387*d1e4d7ceSDavid van Moolenbroek cwdlen = 0;
388*d1e4d7ceSDavid van Moolenbroek for (p = cp; *p++;)
389*d1e4d7ceSDavid van Moolenbroek continue;
390*d1e4d7ceSDavid van Moolenbroek dp = xmalloc((size_t)(cwdlen + (size_t)(p - cp) + 1) * sizeof(Char));
391*d1e4d7ceSDavid van Moolenbroek for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
392*d1e4d7ceSDavid van Moolenbroek continue;
393*d1e4d7ceSDavid van Moolenbroek if (cwdlen)
394*d1e4d7ceSDavid van Moolenbroek p[-1] = '/';
395*d1e4d7ceSDavid van Moolenbroek else
396*d1e4d7ceSDavid van Moolenbroek p--; /* don't add a / after root */
397*d1e4d7ceSDavid van Moolenbroek for (q = cp; (*p++ = *q++) != '\0';)
398*d1e4d7ceSDavid van Moolenbroek continue;
399*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
400*d1e4d7ceSDavid van Moolenbroek cp = dp;
401*d1e4d7ceSDavid van Moolenbroek dp += cwdlen;
402*d1e4d7ceSDavid van Moolenbroek }
403*d1e4d7ceSDavid van Moolenbroek else
404*d1e4d7ceSDavid van Moolenbroek dp = cp;
405*d1e4d7ceSDavid van Moolenbroek
406*d1e4d7ceSDavid van Moolenbroek cp = dcanon(cp, dp);
407*d1e4d7ceSDavid van Moolenbroek return cp;
408*d1e4d7ceSDavid van Moolenbroek }
409*d1e4d7ceSDavid van Moolenbroek
410*d1e4d7ceSDavid van Moolenbroek /*
411*d1e4d7ceSDavid van Moolenbroek * dfollow - change to arg directory; fall back on cdpath if not valid
412*d1e4d7ceSDavid van Moolenbroek */
413*d1e4d7ceSDavid van Moolenbroek static Char *
dfollow(Char * cp)414*d1e4d7ceSDavid van Moolenbroek dfollow(Char *cp)
415*d1e4d7ceSDavid van Moolenbroek {
416*d1e4d7ceSDavid van Moolenbroek char ebuf[MAXPATHLEN];
417*d1e4d7ceSDavid van Moolenbroek struct varent *c;
418*d1e4d7ceSDavid van Moolenbroek Char *dp;
419*d1e4d7ceSDavid van Moolenbroek int serrno;
420*d1e4d7ceSDavid van Moolenbroek
421*d1e4d7ceSDavid van Moolenbroek cp = globone(cp, G_ERROR);
422*d1e4d7ceSDavid van Moolenbroek /*
423*d1e4d7ceSDavid van Moolenbroek * if we are ignoring symlinks, try to fix relatives now.
424*d1e4d7ceSDavid van Moolenbroek */
425*d1e4d7ceSDavid van Moolenbroek dp = dnormalize(cp);
426*d1e4d7ceSDavid van Moolenbroek if (chdir(short2str(dp)) >= 0) {
427*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
428*d1e4d7ceSDavid van Moolenbroek return dgoto(dp);
429*d1e4d7ceSDavid van Moolenbroek }
430*d1e4d7ceSDavid van Moolenbroek else {
431*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) dp);
432*d1e4d7ceSDavid van Moolenbroek if (chdir(short2str(cp)) >= 0)
433*d1e4d7ceSDavid van Moolenbroek return dgoto(cp);
434*d1e4d7ceSDavid van Moolenbroek serrno = errno;
435*d1e4d7ceSDavid van Moolenbroek }
436*d1e4d7ceSDavid van Moolenbroek
437*d1e4d7ceSDavid van Moolenbroek if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
438*d1e4d7ceSDavid van Moolenbroek && (c = adrof(STRcdpath))) {
439*d1e4d7ceSDavid van Moolenbroek Char **cdp;
440*d1e4d7ceSDavid van Moolenbroek Char *p;
441*d1e4d7ceSDavid van Moolenbroek Char buf[MAXPATHLEN];
442*d1e4d7ceSDavid van Moolenbroek
443*d1e4d7ceSDavid van Moolenbroek for (cdp = c->vec; *cdp; cdp++) {
444*d1e4d7ceSDavid van Moolenbroek for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';)
445*d1e4d7ceSDavid van Moolenbroek continue;
446*d1e4d7ceSDavid van Moolenbroek dp[-1] = '/';
447*d1e4d7ceSDavid van Moolenbroek for (p = cp; (*dp++ = *p++) != '\0';)
448*d1e4d7ceSDavid van Moolenbroek continue;
449*d1e4d7ceSDavid van Moolenbroek if (chdir(short2str(buf)) >= 0) {
450*d1e4d7ceSDavid van Moolenbroek printd = 1;
451*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
452*d1e4d7ceSDavid van Moolenbroek cp = Strsave(buf);
453*d1e4d7ceSDavid van Moolenbroek return dgoto(cp);
454*d1e4d7ceSDavid van Moolenbroek }
455*d1e4d7ceSDavid van Moolenbroek }
456*d1e4d7ceSDavid van Moolenbroek }
457*d1e4d7ceSDavid van Moolenbroek dp = value(cp);
458*d1e4d7ceSDavid van Moolenbroek if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
459*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
460*d1e4d7ceSDavid van Moolenbroek cp = Strsave(dp);
461*d1e4d7ceSDavid van Moolenbroek printd = 1;
462*d1e4d7ceSDavid van Moolenbroek return dgoto(cp);
463*d1e4d7ceSDavid van Moolenbroek }
464*d1e4d7ceSDavid van Moolenbroek (void)strcpy(ebuf, short2str(cp));
465*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
466*d1e4d7ceSDavid van Moolenbroek stderror(ERR_SYSTEM, ebuf, strerror(serrno));
467*d1e4d7ceSDavid van Moolenbroek /* NOTREACHED */
468*d1e4d7ceSDavid van Moolenbroek }
469*d1e4d7ceSDavid van Moolenbroek
470*d1e4d7ceSDavid van Moolenbroek /*
471*d1e4d7ceSDavid van Moolenbroek * dopushd - push new directory onto directory stack.
472*d1e4d7ceSDavid van Moolenbroek * with no arguments exchange top and second.
473*d1e4d7ceSDavid van Moolenbroek * with numeric argument (+n) bring it to top.
474*d1e4d7ceSDavid van Moolenbroek */
475*d1e4d7ceSDavid van Moolenbroek void
476*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dopushd(Char ** v,struct command * t)477*d1e4d7ceSDavid van Moolenbroek dopushd(Char **v, struct command *t)
478*d1e4d7ceSDavid van Moolenbroek {
479*d1e4d7ceSDavid van Moolenbroek struct directory *dp;
480*d1e4d7ceSDavid van Moolenbroek
481*d1e4d7ceSDavid van Moolenbroek skipargs(&v, " [<dir>|+<n>]");
482*d1e4d7ceSDavid van Moolenbroek printd = 1;
483*d1e4d7ceSDavid van Moolenbroek if (*v == NULL) {
484*d1e4d7ceSDavid van Moolenbroek char *tmp;
485*d1e4d7ceSDavid van Moolenbroek
486*d1e4d7ceSDavid van Moolenbroek if ((dp = dcwd->di_prev) == &dhead)
487*d1e4d7ceSDavid van Moolenbroek dp = dhead.di_prev;
488*d1e4d7ceSDavid van Moolenbroek if (dp == dcwd)
489*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_NODIR);
490*d1e4d7ceSDavid van Moolenbroek if (chdir(tmp = short2str(dp->di_name)) < 0)
491*d1e4d7ceSDavid van Moolenbroek stderror(ERR_SYSTEM, tmp, strerror(errno));
492*d1e4d7ceSDavid van Moolenbroek dp->di_prev->di_next = dp->di_next;
493*d1e4d7ceSDavid van Moolenbroek dp->di_next->di_prev = dp->di_prev;
494*d1e4d7ceSDavid van Moolenbroek dp->di_next = dcwd->di_next;
495*d1e4d7ceSDavid van Moolenbroek dp->di_prev = dcwd;
496*d1e4d7ceSDavid van Moolenbroek dcwd->di_next->di_prev = dp;
497*d1e4d7ceSDavid van Moolenbroek dcwd->di_next = dp;
498*d1e4d7ceSDavid van Moolenbroek }
499*d1e4d7ceSDavid van Moolenbroek else if (v[1] != NULL)
500*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_TOOMANY);
501*d1e4d7ceSDavid van Moolenbroek else if ((dp = dfind(*v)) != NULL) {
502*d1e4d7ceSDavid van Moolenbroek char *tmp;
503*d1e4d7ceSDavid van Moolenbroek
504*d1e4d7ceSDavid van Moolenbroek if (chdir(tmp = short2str(dp->di_name)) < 0)
505*d1e4d7ceSDavid van Moolenbroek stderror(ERR_SYSTEM, tmp, strerror(errno));
506*d1e4d7ceSDavid van Moolenbroek }
507*d1e4d7ceSDavid van Moolenbroek else {
508*d1e4d7ceSDavid van Moolenbroek Char *ccp;
509*d1e4d7ceSDavid van Moolenbroek
510*d1e4d7ceSDavid van Moolenbroek ccp = dfollow(*v);
511*d1e4d7ceSDavid van Moolenbroek dp = (struct directory *)xcalloc(1, sizeof(struct directory));
512*d1e4d7ceSDavid van Moolenbroek dp->di_name = ccp;
513*d1e4d7ceSDavid van Moolenbroek dp->di_count = 0;
514*d1e4d7ceSDavid van Moolenbroek dp->di_prev = dcwd;
515*d1e4d7ceSDavid van Moolenbroek dp->di_next = dcwd->di_next;
516*d1e4d7ceSDavid van Moolenbroek dcwd->di_next = dp;
517*d1e4d7ceSDavid van Moolenbroek dp->di_next->di_prev = dp;
518*d1e4d7ceSDavid van Moolenbroek }
519*d1e4d7ceSDavid van Moolenbroek dnewcwd(dp);
520*d1e4d7ceSDavid van Moolenbroek }
521*d1e4d7ceSDavid van Moolenbroek
522*d1e4d7ceSDavid van Moolenbroek /*
523*d1e4d7ceSDavid van Moolenbroek * dfind - find a directory if specified by numeric (+n) argument
524*d1e4d7ceSDavid van Moolenbroek */
525*d1e4d7ceSDavid van Moolenbroek static struct directory *
dfind(Char * cp)526*d1e4d7ceSDavid van Moolenbroek dfind(Char *cp)
527*d1e4d7ceSDavid van Moolenbroek {
528*d1e4d7ceSDavid van Moolenbroek struct directory *dp;
529*d1e4d7ceSDavid van Moolenbroek Char *ep;
530*d1e4d7ceSDavid van Moolenbroek int i;
531*d1e4d7ceSDavid van Moolenbroek
532*d1e4d7ceSDavid van Moolenbroek if (*cp++ != '+')
533*d1e4d7ceSDavid van Moolenbroek return (0);
534*d1e4d7ceSDavid van Moolenbroek for (ep = cp; Isdigit(*ep); ep++)
535*d1e4d7ceSDavid van Moolenbroek continue;
536*d1e4d7ceSDavid van Moolenbroek if (*ep)
537*d1e4d7ceSDavid van Moolenbroek return (0);
538*d1e4d7ceSDavid van Moolenbroek i = getn(cp);
539*d1e4d7ceSDavid van Moolenbroek if (i <= 0)
540*d1e4d7ceSDavid van Moolenbroek return (0);
541*d1e4d7ceSDavid van Moolenbroek for (dp = dcwd; i != 0; i--) {
542*d1e4d7ceSDavid van Moolenbroek if ((dp = dp->di_prev) == &dhead)
543*d1e4d7ceSDavid van Moolenbroek dp = dp->di_prev;
544*d1e4d7ceSDavid van Moolenbroek if (dp == dcwd)
545*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_DEEP);
546*d1e4d7ceSDavid van Moolenbroek }
547*d1e4d7ceSDavid van Moolenbroek return (dp);
548*d1e4d7ceSDavid van Moolenbroek }
549*d1e4d7ceSDavid van Moolenbroek
550*d1e4d7ceSDavid van Moolenbroek /*
551*d1e4d7ceSDavid van Moolenbroek * dopopd - pop a directory out of the directory stack
552*d1e4d7ceSDavid van Moolenbroek * with a numeric argument just discard it.
553*d1e4d7ceSDavid van Moolenbroek */
554*d1e4d7ceSDavid van Moolenbroek void
555*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dopopd(Char ** v,struct command * t)556*d1e4d7ceSDavid van Moolenbroek dopopd(Char **v, struct command *t)
557*d1e4d7ceSDavid van Moolenbroek {
558*d1e4d7ceSDavid van Moolenbroek struct directory *dp, *p = NULL;
559*d1e4d7ceSDavid van Moolenbroek
560*d1e4d7ceSDavid van Moolenbroek skipargs(&v, " [+<n>]");
561*d1e4d7ceSDavid van Moolenbroek printd = 1;
562*d1e4d7ceSDavid van Moolenbroek if (*v == NULL)
563*d1e4d7ceSDavid van Moolenbroek dp = dcwd;
564*d1e4d7ceSDavid van Moolenbroek else if (v[1] != NULL)
565*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_TOOMANY);
566*d1e4d7ceSDavid van Moolenbroek else if ((dp = dfind(*v)) == 0)
567*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_BADDIR);
568*d1e4d7ceSDavid van Moolenbroek if (dp->di_prev == &dhead && dp->di_next == &dhead)
569*d1e4d7ceSDavid van Moolenbroek stderror(ERR_NAME | ERR_EMPTY);
570*d1e4d7ceSDavid van Moolenbroek if (dp == dcwd) {
571*d1e4d7ceSDavid van Moolenbroek char *tmp;
572*d1e4d7ceSDavid van Moolenbroek
573*d1e4d7ceSDavid van Moolenbroek if ((p = dp->di_prev) == &dhead)
574*d1e4d7ceSDavid van Moolenbroek p = dhead.di_prev;
575*d1e4d7ceSDavid van Moolenbroek if (chdir(tmp = short2str(p->di_name)) < 0)
576*d1e4d7ceSDavid van Moolenbroek stderror(ERR_SYSTEM, tmp, strerror(errno));
577*d1e4d7ceSDavid van Moolenbroek }
578*d1e4d7ceSDavid van Moolenbroek dp->di_prev->di_next = dp->di_next;
579*d1e4d7ceSDavid van Moolenbroek dp->di_next->di_prev = dp->di_prev;
580*d1e4d7ceSDavid van Moolenbroek if (dp == dcwd)
581*d1e4d7ceSDavid van Moolenbroek dnewcwd(p);
582*d1e4d7ceSDavid van Moolenbroek else {
583*d1e4d7ceSDavid van Moolenbroek printdirs();
584*d1e4d7ceSDavid van Moolenbroek }
585*d1e4d7ceSDavid van Moolenbroek dfree(dp);
586*d1e4d7ceSDavid van Moolenbroek }
587*d1e4d7ceSDavid van Moolenbroek
588*d1e4d7ceSDavid van Moolenbroek /*
589*d1e4d7ceSDavid van Moolenbroek * dfree - free the directory (or keep it if it still has ref count)
590*d1e4d7ceSDavid van Moolenbroek */
591*d1e4d7ceSDavid van Moolenbroek void
dfree(struct directory * dp)592*d1e4d7ceSDavid van Moolenbroek dfree(struct directory *dp)
593*d1e4d7ceSDavid van Moolenbroek {
594*d1e4d7ceSDavid van Moolenbroek
595*d1e4d7ceSDavid van Moolenbroek if (dp->di_count != 0) {
596*d1e4d7ceSDavid van Moolenbroek dp->di_next = dp->di_prev = 0;
597*d1e4d7ceSDavid van Moolenbroek }
598*d1e4d7ceSDavid van Moolenbroek else {
599*d1e4d7ceSDavid van Moolenbroek xfree((char *) dp->di_name);
600*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) dp);
601*d1e4d7ceSDavid van Moolenbroek }
602*d1e4d7ceSDavid van Moolenbroek }
603*d1e4d7ceSDavid van Moolenbroek
604*d1e4d7ceSDavid van Moolenbroek /*
605*d1e4d7ceSDavid van Moolenbroek * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
606*d1e4d7ceSDavid van Moolenbroek * we are of course assuming that the file system is standardly
607*d1e4d7ceSDavid van Moolenbroek * constructed (always have ..'s, directories have links)
608*d1e4d7ceSDavid van Moolenbroek */
609*d1e4d7ceSDavid van Moolenbroek Char *
dcanon(Char * cp,Char * p)610*d1e4d7ceSDavid van Moolenbroek dcanon(Char *cp, Char *p)
611*d1e4d7ceSDavid van Moolenbroek {
612*d1e4d7ceSDavid van Moolenbroek Char slink[MAXPATHLEN];
613*d1e4d7ceSDavid van Moolenbroek char tlink[MAXPATHLEN];
614*d1e4d7ceSDavid van Moolenbroek Char *newcp, *sp;
615*d1e4d7ceSDavid van Moolenbroek Char *p1, *p2; /* general purpose */
616*d1e4d7ceSDavid van Moolenbroek ssize_t cc;
617*d1e4d7ceSDavid van Moolenbroek size_t len;
618*d1e4d7ceSDavid van Moolenbroek int slash;
619*d1e4d7ceSDavid van Moolenbroek
620*d1e4d7ceSDavid van Moolenbroek /*
621*d1e4d7ceSDavid van Moolenbroek * christos: if the path given does not start with a slash prepend cwd. If
622*d1e4d7ceSDavid van Moolenbroek * cwd does not start with a path or the result would be too long abort().
623*d1e4d7ceSDavid van Moolenbroek */
624*d1e4d7ceSDavid van Moolenbroek if (*cp != '/') {
625*d1e4d7ceSDavid van Moolenbroek Char tmpdir[MAXPATHLEN];
626*d1e4d7ceSDavid van Moolenbroek
627*d1e4d7ceSDavid van Moolenbroek p1 = value(STRcwd);
628*d1e4d7ceSDavid van Moolenbroek if (p1 == NULL || *p1 != '/')
629*d1e4d7ceSDavid van Moolenbroek abort();
630*d1e4d7ceSDavid van Moolenbroek if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
631*d1e4d7ceSDavid van Moolenbroek abort();
632*d1e4d7ceSDavid van Moolenbroek (void)Strcpy(tmpdir, p1);
633*d1e4d7ceSDavid van Moolenbroek (void)Strcat(tmpdir, STRslash);
634*d1e4d7ceSDavid van Moolenbroek (void)Strcat(tmpdir, cp);
635*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
636*d1e4d7ceSDavid van Moolenbroek cp = p = Strsave(tmpdir);
637*d1e4d7ceSDavid van Moolenbroek }
638*d1e4d7ceSDavid van Moolenbroek
639*d1e4d7ceSDavid van Moolenbroek while (*p) { /* for each component */
640*d1e4d7ceSDavid van Moolenbroek sp = p; /* save slash address */
641*d1e4d7ceSDavid van Moolenbroek while (*++p == '/') /* flush extra slashes */
642*d1e4d7ceSDavid van Moolenbroek continue;
643*d1e4d7ceSDavid van Moolenbroek if (p != ++sp)
644*d1e4d7ceSDavid van Moolenbroek for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
645*d1e4d7ceSDavid van Moolenbroek continue;
646*d1e4d7ceSDavid van Moolenbroek p = sp; /* save start of component */
647*d1e4d7ceSDavid van Moolenbroek slash = 0;
648*d1e4d7ceSDavid van Moolenbroek while (*++p) /* find next slash or end of path */
649*d1e4d7ceSDavid van Moolenbroek if (*p == '/') {
650*d1e4d7ceSDavid van Moolenbroek slash = 1;
651*d1e4d7ceSDavid van Moolenbroek *p = 0;
652*d1e4d7ceSDavid van Moolenbroek break;
653*d1e4d7ceSDavid van Moolenbroek }
654*d1e4d7ceSDavid van Moolenbroek
655*d1e4d7ceSDavid van Moolenbroek if (*sp == '\0') { /* if component is null */
656*d1e4d7ceSDavid van Moolenbroek if (--sp == cp) /* if path is one char (i.e. /) */
657*d1e4d7ceSDavid van Moolenbroek break;
658*d1e4d7ceSDavid van Moolenbroek else
659*d1e4d7ceSDavid van Moolenbroek *sp = '\0';
660*d1e4d7ceSDavid van Moolenbroek } else if (sp[0] == '.' && sp[1] == 0) {
661*d1e4d7ceSDavid van Moolenbroek if (slash) {
662*d1e4d7ceSDavid van Moolenbroek for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
663*d1e4d7ceSDavid van Moolenbroek continue;
664*d1e4d7ceSDavid van Moolenbroek p = --sp;
665*d1e4d7ceSDavid van Moolenbroek }
666*d1e4d7ceSDavid van Moolenbroek else if (--sp != cp)
667*d1e4d7ceSDavid van Moolenbroek *sp = '\0';
668*d1e4d7ceSDavid van Moolenbroek }
669*d1e4d7ceSDavid van Moolenbroek else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
670*d1e4d7ceSDavid van Moolenbroek /*
671*d1e4d7ceSDavid van Moolenbroek * We have something like "yyy/xxx/..", where "yyy" can be null or
672*d1e4d7ceSDavid van Moolenbroek * a path starting at /, and "xxx" is a single component. Before
673*d1e4d7ceSDavid van Moolenbroek * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
674*d1e4d7ceSDavid van Moolenbroek * symbolic link.
675*d1e4d7ceSDavid van Moolenbroek */
676*d1e4d7ceSDavid van Moolenbroek *--sp = 0; /* form the pathname for readlink */
677*d1e4d7ceSDavid van Moolenbroek if (sp != cp && !adrof(STRignore_symlinks) &&
678*d1e4d7ceSDavid van Moolenbroek (cc = readlink(short2str(cp), tlink,
679*d1e4d7ceSDavid van Moolenbroek sizeof(tlink) - 1)) >= 0) {
680*d1e4d7ceSDavid van Moolenbroek tlink[cc] = '\0';
681*d1e4d7ceSDavid van Moolenbroek (void)Strcpy(slink, str2short(tlink));
682*d1e4d7ceSDavid van Moolenbroek
683*d1e4d7ceSDavid van Moolenbroek if (slash)
684*d1e4d7ceSDavid van Moolenbroek *p = '/';
685*d1e4d7ceSDavid van Moolenbroek /*
686*d1e4d7ceSDavid van Moolenbroek * Point p to the '/' in "/..", and restore the '/'.
687*d1e4d7ceSDavid van Moolenbroek */
688*d1e4d7ceSDavid van Moolenbroek *(p = sp) = '/';
689*d1e4d7ceSDavid van Moolenbroek /*
690*d1e4d7ceSDavid van Moolenbroek * find length of p
691*d1e4d7ceSDavid van Moolenbroek */
692*d1e4d7ceSDavid van Moolenbroek for (p1 = p; *p1++;)
693*d1e4d7ceSDavid van Moolenbroek continue;
694*d1e4d7ceSDavid van Moolenbroek if (*slink != '/') {
695*d1e4d7ceSDavid van Moolenbroek /*
696*d1e4d7ceSDavid van Moolenbroek * Relative path, expand it between the "yyy/" and the
697*d1e4d7ceSDavid van Moolenbroek * "/..". First, back sp up to the character past "yyy/".
698*d1e4d7ceSDavid van Moolenbroek */
699*d1e4d7ceSDavid van Moolenbroek while (*--sp != '/')
700*d1e4d7ceSDavid van Moolenbroek continue;
701*d1e4d7ceSDavid van Moolenbroek sp++;
702*d1e4d7ceSDavid van Moolenbroek *sp = 0;
703*d1e4d7ceSDavid van Moolenbroek /*
704*d1e4d7ceSDavid van Moolenbroek * New length is "yyy/" + slink + "/.." and rest
705*d1e4d7ceSDavid van Moolenbroek */
706*d1e4d7ceSDavid van Moolenbroek p1 = newcp = xmalloc(
707*d1e4d7ceSDavid van Moolenbroek (size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char));
708*d1e4d7ceSDavid van Moolenbroek /*
709*d1e4d7ceSDavid van Moolenbroek * Copy new path into newcp
710*d1e4d7ceSDavid van Moolenbroek */
711*d1e4d7ceSDavid van Moolenbroek for (p2 = cp; (*p1++ = *p2++) != '\0';)
712*d1e4d7ceSDavid van Moolenbroek continue;
713*d1e4d7ceSDavid van Moolenbroek for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';)
714*d1e4d7ceSDavid van Moolenbroek continue;
715*d1e4d7ceSDavid van Moolenbroek for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
716*d1e4d7ceSDavid van Moolenbroek continue;
717*d1e4d7ceSDavid van Moolenbroek /*
718*d1e4d7ceSDavid van Moolenbroek * Restart canonicalization at expanded "/xxx".
719*d1e4d7ceSDavid van Moolenbroek */
720*d1e4d7ceSDavid van Moolenbroek p = sp - cp - 1 + newcp;
721*d1e4d7ceSDavid van Moolenbroek }
722*d1e4d7ceSDavid van Moolenbroek else {
723*d1e4d7ceSDavid van Moolenbroek /*
724*d1e4d7ceSDavid van Moolenbroek * New length is slink + "/.." and rest
725*d1e4d7ceSDavid van Moolenbroek */
726*d1e4d7ceSDavid van Moolenbroek p1 = newcp = xmalloc(
727*d1e4d7ceSDavid van Moolenbroek (size_t)(cc + (p1 - p)) * sizeof(Char));
728*d1e4d7ceSDavid van Moolenbroek /*
729*d1e4d7ceSDavid van Moolenbroek * Copy new path into newcp
730*d1e4d7ceSDavid van Moolenbroek */
731*d1e4d7ceSDavid van Moolenbroek for (p2 = slink; (*p1++ = *p2++) != '\0';)
732*d1e4d7ceSDavid van Moolenbroek continue;
733*d1e4d7ceSDavid van Moolenbroek for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
734*d1e4d7ceSDavid van Moolenbroek continue;
735*d1e4d7ceSDavid van Moolenbroek /*
736*d1e4d7ceSDavid van Moolenbroek * Restart canonicalization at beginning
737*d1e4d7ceSDavid van Moolenbroek */
738*d1e4d7ceSDavid van Moolenbroek p = newcp;
739*d1e4d7ceSDavid van Moolenbroek }
740*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
741*d1e4d7ceSDavid van Moolenbroek cp = newcp;
742*d1e4d7ceSDavid van Moolenbroek continue; /* canonicalize the link */
743*d1e4d7ceSDavid van Moolenbroek }
744*d1e4d7ceSDavid van Moolenbroek *sp = '/';
745*d1e4d7ceSDavid van Moolenbroek if (sp != cp)
746*d1e4d7ceSDavid van Moolenbroek while (*--sp != '/')
747*d1e4d7ceSDavid van Moolenbroek continue;
748*d1e4d7ceSDavid van Moolenbroek if (slash) {
749*d1e4d7ceSDavid van Moolenbroek for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
750*d1e4d7ceSDavid van Moolenbroek continue;
751*d1e4d7ceSDavid van Moolenbroek p = sp;
752*d1e4d7ceSDavid van Moolenbroek }
753*d1e4d7ceSDavid van Moolenbroek else if (cp == sp)
754*d1e4d7ceSDavid van Moolenbroek *++sp = '\0';
755*d1e4d7ceSDavid van Moolenbroek else
756*d1e4d7ceSDavid van Moolenbroek *sp = '\0';
757*d1e4d7ceSDavid van Moolenbroek }
758*d1e4d7ceSDavid van Moolenbroek else { /* normal dir name (not . or .. or nothing) */
759*d1e4d7ceSDavid van Moolenbroek
760*d1e4d7ceSDavid van Moolenbroek if (sp != cp && adrof(STRchase_symlinks) &&
761*d1e4d7ceSDavid van Moolenbroek !adrof(STRignore_symlinks) &&
762*d1e4d7ceSDavid van Moolenbroek (cc = readlink(short2str(cp), tlink, sizeof(tlink)-1)) >= 0) {
763*d1e4d7ceSDavid van Moolenbroek tlink[cc] = '\0';
764*d1e4d7ceSDavid van Moolenbroek (void)Strcpy(slink, str2short(tlink));
765*d1e4d7ceSDavid van Moolenbroek
766*d1e4d7ceSDavid van Moolenbroek /*
767*d1e4d7ceSDavid van Moolenbroek * restore the '/'.
768*d1e4d7ceSDavid van Moolenbroek */
769*d1e4d7ceSDavid van Moolenbroek if (slash)
770*d1e4d7ceSDavid van Moolenbroek *p = '/';
771*d1e4d7ceSDavid van Moolenbroek
772*d1e4d7ceSDavid van Moolenbroek /*
773*d1e4d7ceSDavid van Moolenbroek * point sp to p (rather than backing up).
774*d1e4d7ceSDavid van Moolenbroek */
775*d1e4d7ceSDavid van Moolenbroek sp = p;
776*d1e4d7ceSDavid van Moolenbroek
777*d1e4d7ceSDavid van Moolenbroek /*
778*d1e4d7ceSDavid van Moolenbroek * find length of p
779*d1e4d7ceSDavid van Moolenbroek */
780*d1e4d7ceSDavid van Moolenbroek for (p1 = p; *p1++;)
781*d1e4d7ceSDavid van Moolenbroek continue;
782*d1e4d7ceSDavid van Moolenbroek if (*slink != '/') {
783*d1e4d7ceSDavid van Moolenbroek /*
784*d1e4d7ceSDavid van Moolenbroek * Relative path, expand it between the "yyy/" and the
785*d1e4d7ceSDavid van Moolenbroek * remainder. First, back sp up to the character past
786*d1e4d7ceSDavid van Moolenbroek * "yyy/".
787*d1e4d7ceSDavid van Moolenbroek */
788*d1e4d7ceSDavid van Moolenbroek while (*--sp != '/')
789*d1e4d7ceSDavid van Moolenbroek continue;
790*d1e4d7ceSDavid van Moolenbroek sp++;
791*d1e4d7ceSDavid van Moolenbroek *sp = 0;
792*d1e4d7ceSDavid van Moolenbroek /*
793*d1e4d7ceSDavid van Moolenbroek * New length is "yyy/" + slink + "/.." and rest
794*d1e4d7ceSDavid van Moolenbroek */
795*d1e4d7ceSDavid van Moolenbroek p1 = newcp = xmalloc(
796*d1e4d7ceSDavid van Moolenbroek (size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char));
797*d1e4d7ceSDavid van Moolenbroek /*
798*d1e4d7ceSDavid van Moolenbroek * Copy new path into newcp
799*d1e4d7ceSDavid van Moolenbroek */
800*d1e4d7ceSDavid van Moolenbroek for (p2 = cp; (*p1++ = *p2++) != '\0';)
801*d1e4d7ceSDavid van Moolenbroek continue;
802*d1e4d7ceSDavid van Moolenbroek for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';)
803*d1e4d7ceSDavid van Moolenbroek continue;
804*d1e4d7ceSDavid van Moolenbroek for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
805*d1e4d7ceSDavid van Moolenbroek continue;
806*d1e4d7ceSDavid van Moolenbroek /*
807*d1e4d7ceSDavid van Moolenbroek * Restart canonicalization at expanded "/xxx".
808*d1e4d7ceSDavid van Moolenbroek */
809*d1e4d7ceSDavid van Moolenbroek p = sp - cp - 1 + newcp;
810*d1e4d7ceSDavid van Moolenbroek }
811*d1e4d7ceSDavid van Moolenbroek else {
812*d1e4d7ceSDavid van Moolenbroek /*
813*d1e4d7ceSDavid van Moolenbroek * New length is slink + the rest
814*d1e4d7ceSDavid van Moolenbroek */
815*d1e4d7ceSDavid van Moolenbroek p1 = newcp = xmalloc(
816*d1e4d7ceSDavid van Moolenbroek (size_t)(cc + (p1 - p)) * sizeof(Char));
817*d1e4d7ceSDavid van Moolenbroek /*
818*d1e4d7ceSDavid van Moolenbroek * Copy new path into newcp
819*d1e4d7ceSDavid van Moolenbroek */
820*d1e4d7ceSDavid van Moolenbroek for (p2 = slink; (*p1++ = *p2++) != '\0';)
821*d1e4d7ceSDavid van Moolenbroek continue;
822*d1e4d7ceSDavid van Moolenbroek for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
823*d1e4d7ceSDavid van Moolenbroek continue;
824*d1e4d7ceSDavid van Moolenbroek /*
825*d1e4d7ceSDavid van Moolenbroek * Restart canonicalization at beginning
826*d1e4d7ceSDavid van Moolenbroek */
827*d1e4d7ceSDavid van Moolenbroek p = newcp;
828*d1e4d7ceSDavid van Moolenbroek }
829*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
830*d1e4d7ceSDavid van Moolenbroek cp = newcp;
831*d1e4d7ceSDavid van Moolenbroek continue; /* canonicalize the link */
832*d1e4d7ceSDavid van Moolenbroek }
833*d1e4d7ceSDavid van Moolenbroek if (slash)
834*d1e4d7ceSDavid van Moolenbroek *p = '/';
835*d1e4d7ceSDavid van Moolenbroek }
836*d1e4d7ceSDavid van Moolenbroek }
837*d1e4d7ceSDavid van Moolenbroek
838*d1e4d7ceSDavid van Moolenbroek /*
839*d1e4d7ceSDavid van Moolenbroek * fix home...
840*d1e4d7ceSDavid van Moolenbroek */
841*d1e4d7ceSDavid van Moolenbroek p1 = value(STRhome);
842*d1e4d7ceSDavid van Moolenbroek len = Strlen(p1);
843*d1e4d7ceSDavid van Moolenbroek /*
844*d1e4d7ceSDavid van Moolenbroek * See if we're not in a subdir of STRhome
845*d1e4d7ceSDavid van Moolenbroek */
846*d1e4d7ceSDavid van Moolenbroek if (p1 && *p1 == '/' &&
847*d1e4d7ceSDavid van Moolenbroek (Strncmp(p1, cp, len) != 0 || (cp[len] != '/' && cp[len] != '\0'))) {
848*d1e4d7ceSDavid van Moolenbroek static ino_t home_ino;
849*d1e4d7ceSDavid van Moolenbroek static dev_t home_dev = NODEV;
850*d1e4d7ceSDavid van Moolenbroek static Char *home_ptr = NULL;
851*d1e4d7ceSDavid van Moolenbroek struct stat statbuf;
852*d1e4d7ceSDavid van Moolenbroek
853*d1e4d7ceSDavid van Moolenbroek /*
854*d1e4d7ceSDavid van Moolenbroek * Get dev and ino of STRhome
855*d1e4d7ceSDavid van Moolenbroek */
856*d1e4d7ceSDavid van Moolenbroek if (home_ptr != p1 &&
857*d1e4d7ceSDavid van Moolenbroek stat(short2str(p1), &statbuf) != -1) {
858*d1e4d7ceSDavid van Moolenbroek home_dev = statbuf.st_dev;
859*d1e4d7ceSDavid van Moolenbroek home_ino = statbuf.st_ino;
860*d1e4d7ceSDavid van Moolenbroek home_ptr = p1;
861*d1e4d7ceSDavid van Moolenbroek }
862*d1e4d7ceSDavid van Moolenbroek /*
863*d1e4d7ceSDavid van Moolenbroek * Start comparing dev & ino backwards
864*d1e4d7ceSDavid van Moolenbroek */
865*d1e4d7ceSDavid van Moolenbroek p2 = Strcpy(slink, cp);
866*d1e4d7ceSDavid van Moolenbroek for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) {
867*d1e4d7ceSDavid van Moolenbroek if (statbuf.st_dev == home_dev &&
868*d1e4d7ceSDavid van Moolenbroek statbuf.st_ino == home_ino) {
869*d1e4d7ceSDavid van Moolenbroek sp = (Char *) - 1;
870*d1e4d7ceSDavid van Moolenbroek break;
871*d1e4d7ceSDavid van Moolenbroek }
872*d1e4d7ceSDavid van Moolenbroek if ((sp = Strrchr(p2, '/')) != NULL)
873*d1e4d7ceSDavid van Moolenbroek *sp = '\0';
874*d1e4d7ceSDavid van Moolenbroek }
875*d1e4d7ceSDavid van Moolenbroek /*
876*d1e4d7ceSDavid van Moolenbroek * See if we found it
877*d1e4d7ceSDavid van Moolenbroek */
878*d1e4d7ceSDavid van Moolenbroek if (*p2 && sp == (Char *) -1) {
879*d1e4d7ceSDavid van Moolenbroek /*
880*d1e4d7ceSDavid van Moolenbroek * Use STRhome to make '~' work
881*d1e4d7ceSDavid van Moolenbroek */
882*d1e4d7ceSDavid van Moolenbroek newcp = Strspl(p1, cp + Strlen(p2));
883*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) cp);
884*d1e4d7ceSDavid van Moolenbroek cp = newcp;
885*d1e4d7ceSDavid van Moolenbroek }
886*d1e4d7ceSDavid van Moolenbroek }
887*d1e4d7ceSDavid van Moolenbroek return cp;
888*d1e4d7ceSDavid van Moolenbroek }
889*d1e4d7ceSDavid van Moolenbroek
890*d1e4d7ceSDavid van Moolenbroek
891*d1e4d7ceSDavid van Moolenbroek /*
892*d1e4d7ceSDavid van Moolenbroek * dnewcwd - make a new directory in the loop the current one
893*d1e4d7ceSDavid van Moolenbroek */
894*d1e4d7ceSDavid van Moolenbroek static void
dnewcwd(struct directory * dp)895*d1e4d7ceSDavid van Moolenbroek dnewcwd(struct directory *dp)
896*d1e4d7ceSDavid van Moolenbroek {
897*d1e4d7ceSDavid van Moolenbroek dcwd = dp;
898*d1e4d7ceSDavid van Moolenbroek dset(dcwd->di_name);
899*d1e4d7ceSDavid van Moolenbroek if (printd && !(adrof(STRpushdsilent)))
900*d1e4d7ceSDavid van Moolenbroek printdirs();
901*d1e4d7ceSDavid van Moolenbroek }
902