home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / ASH / ASH-LINU.2 / ASH-LINU / ash-linux-0.2 / cd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-04  |  8.3 KB  |  375 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. /*static char sccsid[] = "from: @(#)cd.c    5.2 (Berkeley) 3/13/91";*/
  39. static char rcsid[] = "cd.c,v 1.5 1993/08/01 18:58:22 mycroft Exp";
  40. #endif /* not lint */
  41.  
  42. /*
  43.  * The cd and pwd commands.
  44.  */
  45.  
  46. #include "shell.h"
  47. #include "var.h"
  48. #include "nodes.h"    /* for jobs.h */
  49. #include "jobs.h"
  50. #include "options.h"
  51. #include "output.h"
  52. #include "memalloc.h"
  53. #include "error.h"
  54. #include "mystring.h"
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57. #include <errno.h>
  58.  
  59.  
  60. #ifdef __STDC__
  61. STATIC int docd(char *, int);
  62. STATIC void updatepwd(char *);
  63. STATIC void getpwd(void);
  64. STATIC char *getcomponent(void);
  65. #else
  66. STATIC int docd();
  67. STATIC void updatepwd();
  68. STATIC void getpwd();
  69. STATIC char *getcomponent();
  70. #endif
  71.  
  72.  
  73. char *curdir;            /* current working directory */
  74. STATIC char *cdcomppath;
  75.  
  76. #if UDIR
  77. extern int didudir;        /* set if /u/logname expanded */
  78. #endif
  79.  
  80.  
  81. int
  82. cdcmd(argc, argv)  char **argv; {
  83.     char *dest;
  84.     char *path;
  85.     char *p;
  86.     struct stat statb;
  87.     char *padvance();
  88.  
  89.     nextopt(nullstr);
  90.     if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
  91.         error("HOME not set");
  92.     if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
  93.         path = nullstr;
  94.     while ((p = padvance(&path, dest)) != NULL) {
  95.         if (stat(p, &statb) >= 0
  96.          && (statb.st_mode & S_IFMT) == S_IFDIR
  97.          && docd(p, strcmp(p, dest)) >= 0)
  98.             return 0;
  99.     }
  100.     error("can't cd to %s", dest);
  101. }
  102.  
  103.  
  104. /*
  105.  * Actually do the chdir.  If the name refers to symbolic links, we
  106.  * compute the actual directory name before doing the cd.  In an
  107.  * interactive shell, print the directory name if "print" is nonzero
  108.  * or if the name refers to a symbolic link.  We also print the name
  109.  * if "/u/logname" was expanded in it, since this is similar to a
  110.  * symbolic link.  (The check for this breaks if the user gives the
  111.  * cd command some additional, unused arguments.)
  112.  */
  113.  
  114. #if SYMLINKS == 0
  115. STATIC int
  116. docd(dest, print)
  117.     char *dest;
  118.     {
  119. #if UDIR
  120.     if (didudir)
  121.         print = 1;
  122. #endif
  123.     INTOFF;
  124.     if (dest[0] != '\0' && chdir(dest) < 0) {
  125.         INTON;
  126.         return -1;
  127.     }
  128.     updatepwd(dest);
  129.     INTON;
  130. #ifdef not
  131.     if (print && iflag)
  132.         out1fmt("%s\n", stackblock());
  133. #endif
  134.     return 0;
  135. }
  136.  
  137. #else
  138.  
  139.  
  140.  
  141. STATIC int
  142. docd(dest, print)
  143.     char *dest;
  144.     {
  145.     register char *p;
  146.     register char *q;
  147.     char *symlink;
  148.     char *component;
  149.     struct stat statb;
  150.     int first;
  151.     int i;
  152.  
  153.     TRACE(("docd(\"%s\", %d) called\n", dest, print));
  154. #if UDIR
  155.     if (didudir)
  156.         print = 1;
  157. #endif
  158.  
  159. top:
  160.     cdcomppath = dest;
  161.     STARTSTACKSTR(p);
  162.     if (*dest == '/') {
  163.         STPUTC('/', p);
  164.         cdcomppath++;
  165.     }
  166.     first = 1;
  167.     while ((q = getcomponent()) != NULL) {
  168.         if (q[0] == '\0' || q[0] == '.' && q[1] == '\0')
  169.             continue;
  170.         if (! first)
  171.             STPUTC('/', p);
  172.         first = 0;
  173.         component = q;
  174.         while (*q)
  175.             STPUTC(*q++, p);
  176.         if (equal(component, ".."))
  177.             continue;
  178.         STACKSTRNUL(p);
  179.         if (lstat(stackblock(), &statb) < 0)
  180.             error("lstat %s failed", stackblock());
  181.         if ((statb.st_mode & S_IFMT) != S_IFLNK)
  182.             continue;
  183.  
  184.         /* Hit a symbolic link.  We have to start all over again. */
  185.         print = 1;
  186.         STPUTC('\0', p);
  187.         symlink = grabstackstr(p);
  188.         i = (int)statb.st_size + 2;        /* 2 for '/' and '\0' */
  189.         if (cdcomppath != NULL)
  190.             i += strlen(cdcomppath);
  191.         p = stalloc(i);
  192.         if (readlink(symlink, p, (int)statb.st_size) < 0) {
  193.             error("readlink %s failed", stackblock());
  194.         }
  195.         if (cdcomppath != NULL) {
  196.             p[(int)statb.st_size] = '/';
  197.             scopy(cdcomppath, p + (int)statb.st_size + 1);
  198.         } else {
  199.             p[(int)statb.st_size] = '\0';
  200.         }
  201.         if (p[0] != '/') {    /* relative path name */
  202.             char *r;
  203.             q = r = symlink;
  204.             while (*q) {
  205.                 if (*q++ == '/')
  206.                     r = q;
  207.             }
  208.             *r = '\0';
  209.             dest = stalloc(strlen(symlink) + strlen(p) + 1);
  210.             scopy(symlink, dest);
  211.             strcat(dest, p);
  212.         } else {
  213.             dest = p;
  214.         }
  215.         goto top;
  216.     }
  217.     STPUTC('\0', p);
  218.     p = grabstackstr(p);
  219.     INTOFF;
  220.     if (p[0] != '\0' && chdir(p) < 0) {
  221.         INTON;
  222.         return -1;
  223.     }
  224.     updatepwd(p);
  225.     INTON;
  226. #ifdef not
  227.     if (print && iflag)
  228.         out1fmt("%s\n", p);
  229. #endif
  230.     return 0;
  231. }
  232. #endif /* SYMLINKS */
  233.  
  234.  
  235.  
  236. /*
  237.  * Get the next component of the path name pointed to by cdcomppath.
  238.  * This routine overwrites the string pointed to by cdcomppath.
  239.  */
  240.  
  241. STATIC char *
  242. getcomponent() {
  243.     register char *p;
  244.     char *start;
  245.  
  246.     if ((p = cdcomppath) == NULL)
  247.         return NULL;
  248.     start = cdcomppath;
  249.     while (*p != '/' && *p != '\0')
  250.         p++;
  251.     if (*p == '\0') {
  252.         cdcomppath = NULL;
  253.     } else {
  254.         *p++ = '\0';
  255.         cdcomppath = p;
  256.     }
  257.     return start;
  258. }
  259.  
  260.  
  261.  
  262. /*
  263.  * Update curdir (the name of the current directory) in response to a
  264.  * cd command.  We also call hashcd to let the routines in exec.c know
  265.  * that the current directory has changed.
  266.  */
  267.  
  268. void hashcd();
  269.  
  270. STATIC void
  271. updatepwd(dir)
  272.     char *dir;
  273.     {
  274.     char *new;
  275.     char *p;
  276.  
  277.     hashcd();                /* update command hash table */
  278.     cdcomppath = stalloc(strlen(dir) + 1);
  279.     scopy(dir, cdcomppath);
  280.     STARTSTACKSTR(new);
  281.     if (*dir != '/') {
  282.         if (curdir == NULL)
  283.             return;
  284.         p = curdir;
  285.         while (*p)
  286.             STPUTC(*p++, new);
  287.         if (p[-1] == '/')
  288.             STUNPUTC(new);
  289.     }
  290.     while ((p = getcomponent()) != NULL) {
  291.         if (equal(p, "..")) {
  292.             while (new > stackblock() && (STUNPUTC(new), *new) != '/');
  293.         } else if (*p != '\0' && ! equal(p, ".")) {
  294.             STPUTC('/', new);
  295.             while (*p)
  296.                 STPUTC(*p++, new);
  297.         }
  298.     }
  299.     if (new == stackblock())
  300.         STPUTC('/', new);
  301.     STACKSTRNUL(new);
  302.     if (curdir)
  303.         ckfree(curdir);
  304.     curdir = savestr(stackblock());
  305. }
  306.  
  307.  
  308.  
  309. int
  310. pwdcmd(argc, argv)  char **argv; {
  311.     getpwd();
  312.     out1str(curdir);
  313.     out1c('\n');
  314.     return 0;
  315. }
  316.  
  317.  
  318.  
  319. /*
  320.  * Run /bin/pwd to find out what the current directory is.  We suppress
  321.  * interrupts throughout most of this, but the user can still break out
  322.  * of it by killing the pwd program.  If we already know the current
  323.  * directory, this routine returns immediately.
  324.  */
  325.  
  326. #define MAXPWD 256
  327.  
  328. STATIC void
  329. getpwd() {
  330.     char buf[MAXPWD];
  331.     char *p;
  332.     int i;
  333.     int status;
  334.     struct job *jp;
  335.     int pip[2];
  336.  
  337.     if (curdir)
  338.         return;
  339.     INTOFF;
  340.     if (pipe(pip) < 0)
  341.         error("Pipe call failed");
  342.     jp = makejob((union node *)NULL, 1);
  343.     if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
  344.         close(pip[0]);
  345.         if (pip[1] != 1) {
  346.             close(1);
  347.             copyfd(pip[1], 1);
  348.             close(pip[1]);
  349.         }
  350.         execl("/bin/pwd", "pwd", (char *)0);
  351.         /* error("Cannot exec /bin/pwd");*/
  352.         out2str("Cannot exec /bin/pwd\n");        /* 22 Aug 92*/
  353.         flushall();
  354.         _exit(1);
  355.     }
  356.     close(pip[1]);
  357.     pip[1] = -1;
  358.     p = buf;
  359.     while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0
  360.          || i == -1 && errno == EINTR) {
  361.         if (i > 0)
  362.             p += i;
  363.     }
  364.     close(pip[0]);
  365.     pip[0] = -1;
  366.     status = waitforjob(jp);
  367.     if (status != 0)
  368.         error((char *)0);
  369.     if (i < 0 || p == buf || p[-1] != '\n')
  370.         error("pwd command failed");
  371.     p[-1] = '\0';
  372.     curdir = savestr(buf);
  373.     INTON;
  374. }
  375.