cd.c revision 25222
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 353044Sdg * 3625222Ssteve * $Id: cd.c,v 1.14 1997/02/22 13:58:22 peter Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 4020425Sstevestatic char const sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95"; 411556Srgrimes#endif /* not lint */ 421556Srgrimes 4317987Speter#include <sys/types.h> 4417987Speter#include <sys/stat.h> 4517987Speter#include <stdlib.h> 4620425Ssteve#include <string.h> 4717987Speter#include <unistd.h> 4817987Speter#include <errno.h> 4917987Speter 501556Srgrimes/* 511556Srgrimes * The cd and pwd commands. 521556Srgrimes */ 531556Srgrimes 541556Srgrimes#include "shell.h" 551556Srgrimes#include "var.h" 561556Srgrimes#include "nodes.h" /* for jobs.h */ 571556Srgrimes#include "jobs.h" 581556Srgrimes#include "options.h" 591556Srgrimes#include "output.h" 601556Srgrimes#include "memalloc.h" 611556Srgrimes#include "error.h" 6220425Ssteve#include "exec.h" 6317987Speter#include "redir.h" 641556Srgrimes#include "mystring.h" 6517987Speter#include "show.h" 6620425Ssteve#include "cd.h" 671556Srgrimes 6817987SpeterSTATIC int docd __P((char *, int)); 6917987SpeterSTATIC char *getcomponent __P((void)); 7017987SpeterSTATIC void updatepwd __P((char *)); 711556Srgrimes 7220425Sstevechar *curdir = NULL; /* current working directory */ 731556Srgrimeschar *prevdir; /* previous working directory */ 741556SrgrimesSTATIC char *cdcomppath; 751556Srgrimes 761556Srgrimesint 7717987Spetercdcmd(argc, argv) 7817987Speter int argc; 7920425Ssteve char **argv; 8017987Speter{ 811556Srgrimes char *dest; 821556Srgrimes char *path; 831556Srgrimes char *p; 841556Srgrimes struct stat statb; 851556Srgrimes int print = 0; 861556Srgrimes 871556Srgrimes nextopt(nullstr); 881556Srgrimes if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) 891556Srgrimes error("HOME not set"); 905234Sbde if (*dest == '\0') 915234Sbde dest = "."; 921556Srgrimes if (dest[0] == '-' && dest[1] == '\0') { 931556Srgrimes dest = prevdir ? prevdir : curdir; 9412273Speter if (dest) 9512273Speter print = 1; 9612273Speter else 9712273Speter dest = "."; 981556Srgrimes } 991556Srgrimes if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL) 1001556Srgrimes path = nullstr; 1011556Srgrimes while ((p = padvance(&path, dest)) != NULL) { 10217987Speter if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 1031556Srgrimes if (!print) { 1041556Srgrimes /* 1051556Srgrimes * XXX - rethink 1061556Srgrimes */ 1071556Srgrimes if (p[0] == '.' && p[1] == '/') 1081556Srgrimes p += 2; 1091556Srgrimes print = strcmp(p, dest); 1101556Srgrimes } 1111556Srgrimes if (docd(p, print) >= 0) 1121556Srgrimes return 0; 1131556Srgrimes 1141556Srgrimes } 1151556Srgrimes } 1161556Srgrimes error("can't cd to %s", dest); 11717987Speter /*NOTREACHED*/ 11817987Speter return 0; 1191556Srgrimes} 1201556Srgrimes 1211556Srgrimes 1221556Srgrimes/* 12320774Ssteve * Actually do the chdir. In an interactive shell, print the 12420774Ssteve * directory name if "print" is nonzero. 1251556Srgrimes */ 1261556SrgrimesSTATIC int 1271556Srgrimesdocd(dest, print) 1281556Srgrimes char *dest; 12917987Speter int print; 13020425Ssteve{ 13120425Ssteve 13220425Ssteve TRACE(("docd(\"%s\", %d) called\n", dest, print)); 1331556Srgrimes INTOFF; 13421301Ssteve updatepwd(dest); 13521301Ssteve if (chdir(stackblock()) < 0) { 1361556Srgrimes INTON; 1371556Srgrimes return -1; 1381556Srgrimes } 13921301Ssteve hashcd(); /* update command hash table */ 14021301Ssteve if (prevdir) 14121301Ssteve ckfree(prevdir); 14221301Ssteve prevdir = curdir; 14321301Ssteve curdir = savestr(stackblock()); 1441556Srgrimes INTON; 1451556Srgrimes if (print && iflag) 1461556Srgrimes out1fmt("%s\n", stackblock()); 1471556Srgrimes return 0; 1481556Srgrimes} 1491556Srgrimes 1501556Srgrimes 1511556Srgrimes/* 1521556Srgrimes * Get the next component of the path name pointed to by cdcomppath. 1531556Srgrimes * This routine overwrites the string pointed to by cdcomppath. 1541556Srgrimes */ 1551556SrgrimesSTATIC char * 15620774Sstevegetcomponent() 15720774Ssteve{ 15825222Ssteve char *p; 1591556Srgrimes char *start; 1601556Srgrimes 1611556Srgrimes if ((p = cdcomppath) == NULL) 1621556Srgrimes return NULL; 1631556Srgrimes start = cdcomppath; 1641556Srgrimes while (*p != '/' && *p != '\0') 1651556Srgrimes p++; 1661556Srgrimes if (*p == '\0') { 1671556Srgrimes cdcomppath = NULL; 1681556Srgrimes } else { 1691556Srgrimes *p++ = '\0'; 1701556Srgrimes cdcomppath = p; 1711556Srgrimes } 1721556Srgrimes return start; 1731556Srgrimes} 1741556Srgrimes 1751556Srgrimes 1761556Srgrimes/* 17721301Ssteve * Determine the new working directory, but don't actually enforce 17821301Ssteve * any changes. 1791556Srgrimes */ 1801556SrgrimesSTATIC void 1811556Srgrimesupdatepwd(dir) 1821556Srgrimes char *dir; 18320774Ssteve{ 1841556Srgrimes char *new; 1851556Srgrimes char *p; 1861556Srgrimes 1871556Srgrimes cdcomppath = stalloc(strlen(dir) + 1); 1881556Srgrimes scopy(dir, cdcomppath); 1891556Srgrimes STARTSTACKSTR(new); 1901556Srgrimes if (*dir != '/') { 1911556Srgrimes if (curdir == NULL) 1921556Srgrimes return; 1931556Srgrimes p = curdir; 1941556Srgrimes while (*p) 1951556Srgrimes STPUTC(*p++, new); 1961556Srgrimes if (p[-1] == '/') 1971556Srgrimes STUNPUTC(new); 1981556Srgrimes } 1991556Srgrimes while ((p = getcomponent()) != NULL) { 2001556Srgrimes if (equal(p, "..")) { 2011556Srgrimes while (new > stackblock() && (STUNPUTC(new), *new) != '/'); 2021556Srgrimes } else if (*p != '\0' && ! equal(p, ".")) { 2031556Srgrimes STPUTC('/', new); 2041556Srgrimes while (*p) 2051556Srgrimes STPUTC(*p++, new); 2061556Srgrimes } 2071556Srgrimes } 2081556Srgrimes if (new == stackblock()) 2091556Srgrimes STPUTC('/', new); 2101556Srgrimes STACKSTRNUL(new); 2111556Srgrimes} 2121556Srgrimes 2131556Srgrimes 2141556Srgrimesint 21517987Speterpwdcmd(argc, argv) 21617987Speter int argc; 21720425Ssteve char **argv; 21817987Speter{ 21921301Ssteve if (!getpwd()) 22020774Ssteve error("getcwd() failed: %s", strerror(errno)); 2211556Srgrimes out1str(curdir); 2221556Srgrimes out1c('\n'); 2231556Srgrimes return 0; 2241556Srgrimes} 2251556Srgrimes 2261556Srgrimes 2271556Srgrimes/* 22820774Ssteve * Find out what the current directory is. If we already know the current 2291556Srgrimes * directory, this routine returns immediately. 2301556Srgrimes */ 23120774Sstevechar * 23220425Sstevegetpwd() 23320425Ssteve{ 2341556Srgrimes if (curdir) 23520774Ssteve return (curdir); 23620887Ssteve return ((curdir = getcwd(NULL, 0))); 2371556Srgrimes} 238