119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: ex_cd.c,v 10.13 2012/04/12 06:28:27 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/queue.h> 17254225Speter#include <sys/time.h> 1819304Speter 1919304Speter#include <bitstring.h> 2019304Speter#include <errno.h> 2119304Speter#include <limits.h> 2219304Speter#include <pwd.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter#include <unistd.h> 2719304Speter 2819304Speter#include "../common/common.h" 2919304Speter 3019304Speter/* 3119304Speter * ex_cd -- :cd[!] [directory] 3219304Speter * Change directories. 3319304Speter * 3419304Speter * PUBLIC: int ex_cd __P((SCR *, EXCMD *)); 3519304Speter */ 3619304Speterint 37254225Speterex_cd(SCR *sp, EXCMD *cmdp) 3819304Speter{ 3919304Speter struct passwd *pw; 4019304Speter ARGS *ap; 41254225Speter int savech; 42254225Speter char *dir, *p, *t; 43254225Speter char *buf; 44254225Speter size_t dlen; 4519304Speter 4619304Speter /* 4719304Speter * !!! 4819304Speter * Historic practice is that the cd isn't attempted if the file has 4919304Speter * been modified, unless its name begins with a leading '/' or the 5019304Speter * force flag is set. 5119304Speter */ 5219304Speter if (F_ISSET(sp->ep, F_MODIFIED) && 5319304Speter !FL_ISSET(cmdp->iflags, E_C_FORCE) && sp->frp->name[0] != '/') { 5419304Speter msgq(sp, M_ERR, 5519304Speter "120|File modified since last complete write; write or use ! to override"); 5619304Speter return (1); 5719304Speter } 5819304Speter 5919304Speter switch (cmdp->argc) { 6019304Speter case 0: 6119304Speter /* If no argument, change to the user's home directory. */ 6219304Speter if ((dir = getenv("HOME")) == NULL) { 6319304Speter if ((pw = getpwuid(getuid())) == NULL || 6419304Speter pw->pw_dir == NULL || pw->pw_dir[0] == '\0') { 6519304Speter msgq(sp, M_ERR, 6619304Speter "121|Unable to find home directory location"); 6719304Speter return (1); 6819304Speter } 6919304Speter dir = pw->pw_dir; 7019304Speter } 7119304Speter break; 7219304Speter case 1: 73254225Speter INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, 74254225Speter dir, dlen); 7519304Speter break; 7619304Speter default: 7719304Speter abort(); 7819304Speter } 7919304Speter 8019304Speter /* 8119304Speter * Try the current directory first. If this succeeds, don't display 8219304Speter * a message, vi didn't historically, and it should be obvious to the 8319304Speter * user where they are. 8419304Speter */ 8519304Speter if (!chdir(dir)) 8619304Speter return (0); 8719304Speter 8819304Speter /* 8919304Speter * If moving to the user's home directory, or, the path begins with 9019304Speter * "/", "./" or "../", it's the only place we try. 9119304Speter */ 9219304Speter if (cmdp->argc == 0 || 9319304Speter (ap = cmdp->argv[0])->bp[0] == '/' || 94254225Speter (ap->len == 1 && ap->bp[0] == '.') || 95254225Speter (ap->len >= 2 && ap->bp[0] == '.' && ap->bp[1] == '.' && 96254225Speter (ap->bp[2] == '/' || ap->bp[2] == '\0'))) 9719304Speter goto err; 9819304Speter 9919304Speter /* Try the O_CDPATH option values. */ 10019304Speter for (p = t = O_STR(sp, O_CDPATH);; ++p) 10119304Speter if (*p == '\0' || *p == ':') { 10219304Speter /* 103254225Speter * Ignore the empty strings and ".", since we've already 104254225Speter * tried the current directory. 10519304Speter */ 106254225Speter if (t < p && (p - t != 1 || *t != '.')) { 10719304Speter savech = *p; 10819304Speter *p = '\0'; 109254225Speter if ((buf = join(t, dir)) == NULL) { 110254225Speter msgq(sp, M_SYSERR, NULL); 111254225Speter return (1); 112254225Speter } 11319304Speter *p = savech; 11419304Speter if (!chdir(buf)) { 115254225Speter free(buf); 116254225Speter if ((buf = getcwd(NULL, 0)) != NULL) { 11719304Speter msgq_str(sp, M_INFO, buf, "122|New current directory: %s"); 118254225Speter free(buf); 119254225Speter } 12019304Speter return (0); 12119304Speter } 122254225Speter free(buf); 12319304Speter } 12419304Speter t = p + 1; 12519304Speter if (*p == '\0') 12619304Speter break; 12719304Speter } 12819304Speter 12919304Spetererr: msgq_str(sp, M_SYSERR, dir, "%s"); 13019304Speter return (1); 13119304Speter} 132