1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2015 PALO, Richard. 24 */ 25 26 /* 27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 32 /* All Rights Reserved */ 33 34 35 /* 36 * UNIX shell 37 */ 38 39 #include "mac.h" 40 #include <errno.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <limits.h> 44 #include "defs.h" 45 46 #define DOT '.' 47 #define NULLCHAR '\0' 48 #define SLASH '/' 49 #define PARTLY 2 50 51 static void rmslash(unsigned char *string); 52 #ifdef __STDC__ 53 extern const char longpwd[]; 54 #else 55 extern char longpwd[]; 56 #endif 57 extern char *getcwd(); 58 59 unsigned char cwdname[PATH_MAX+1]; 60 61 static int didpwd = FALSE; 62 63 void 64 cwd(unsigned char *dir) 65 { 66 unsigned char *pcwd; 67 unsigned char *pdir; 68 69 /* First remove extra /'s */ 70 71 rmslash(dir); 72 73 /* Now remove any .'s */ 74 75 pdir = dir; 76 if (*dir == SLASH) 77 pdir++; 78 while (*pdir) { /* remove /./ by itself */ 79 if ((*pdir == DOT) && (*(pdir+1) == SLASH)) { 80 movstr(pdir+2, pdir); 81 continue; 82 } 83 pdir++; 84 while ((*pdir) && (*pdir != SLASH)) 85 pdir++; 86 if (*pdir) 87 pdir++; 88 } 89 /* take care of trailing /. */ 90 if (*(--pdir) == DOT && pdir > dir && *(--pdir) == SLASH) { 91 if (pdir > dir) { 92 *pdir = NULLCHAR; 93 } else { 94 *(pdir+1) = NULLCHAR; 95 } 96 97 } 98 99 /* Remove extra /'s */ 100 101 rmslash(dir); 102 103 /* Now that the dir is canonicalized, process it */ 104 105 if (*dir == DOT && *(dir+1) == NULLCHAR) { 106 return; 107 } 108 109 110 if (*dir == SLASH) { 111 /* Absolute path */ 112 113 pcwd = cwdname; 114 *pcwd++ = *dir++; 115 didpwd = PARTLY; 116 } 117 else 118 { 119 /* Relative path */ 120 121 if (didpwd == FALSE) 122 return; 123 didpwd = PARTLY; 124 pcwd = cwdname + length(cwdname) - 1; 125 if (pcwd != cwdname+1) 126 *pcwd++ = SLASH; 127 } 128 while (*dir) { 129 if (*dir == DOT && 130 *(dir+1) == DOT && 131 (*(dir+2) == SLASH || *(dir+2) == NULLCHAR)) { 132 /* Parent directory, so backup one */ 133 134 if (pcwd > cwdname+2) 135 --pcwd; 136 while (*(--pcwd) != SLASH) 137 ; 138 pcwd++; 139 dir += 2; 140 if (*dir == SLASH) { 141 dir++; 142 } 143 continue; 144 } 145 if (pcwd >= &cwdname[PATH_MAX+1]) { 146 didpwd = FALSE; 147 return; 148 } 149 *pcwd++ = *dir++; 150 while ((*dir) && (*dir != SLASH)) { 151 if (pcwd >= &cwdname[PATH_MAX+1]) { 152 didpwd = FALSE; 153 return; 154 } 155 *pcwd++ = *dir++; 156 } 157 if (*dir) { 158 if (pcwd >= &cwdname[PATH_MAX+1]) { 159 didpwd = FALSE; 160 return; 161 } 162 *pcwd++ = *dir++; 163 } 164 } 165 if (pcwd >= &cwdname[PATH_MAX+1]) { 166 didpwd = FALSE; 167 return; 168 } 169 *pcwd = NULLCHAR; 170 171 --pcwd; 172 if (pcwd > cwdname && *pcwd == SLASH) { 173 /* Remove trailing / */ 174 175 *pcwd = NULLCHAR; 176 } 177 } 178 179 void 180 cwd2() 181 { 182 struct stat stat1, stat2; 183 unsigned char *pcwd; 184 /* check if there are any symbolic links in pathname */ 185 186 if (didpwd == FALSE) 187 return; 188 pcwd = cwdname + 1; 189 if (didpwd == PARTLY) { 190 while (*pcwd) { 191 char c; 192 do { 193 c = *pcwd++; 194 } while (c != SLASH && c != NULLCHAR); 195 *--pcwd = NULLCHAR; 196 if (lstat((char *)cwdname, &stat1) == -1 || 197 (stat1.st_mode & S_IFMT) == S_IFLNK) { 198 didpwd = FALSE; 199 *pcwd = c; 200 return; 201 } 202 *pcwd = c; 203 if (c) 204 pcwd++; 205 } 206 didpwd = TRUE; 207 } else 208 if (stat((char *)cwdname, &stat1) == -1) { 209 didpwd = FALSE; 210 return; 211 } 212 /* 213 * check if ino's and dev's match; pathname could 214 * consist of symbolic links with ".." 215 */ 216 217 if (stat(".", &stat2) == -1 || 218 stat1.st_dev != stat2.st_dev || 219 stat1.st_ino != stat2.st_ino) 220 didpwd = FALSE; 221 } 222 223 unsigned char * 224 cwdget() 225 { 226 cwd2(); 227 if (didpwd == FALSE) { 228 if (getcwd((char *)cwdname, PATH_MAX+1) == NULL) 229 *cwdname = NULLCHAR; 230 didpwd = TRUE; 231 } 232 return (cwdname); 233 } 234 235 /* 236 * Print the current working directory. 237 */ 238 239 void 240 cwdprint(void) 241 { 242 unsigned char *cp; 243 244 cwd2(); 245 if (didpwd == FALSE) { 246 if (getcwd((char *)cwdname, PATH_MAX+1) == NULL) { 247 if (errno && errno != ERANGE) 248 error(badpwd); 249 else 250 error(longpwd); 251 } 252 didpwd = TRUE; 253 } 254 255 for (cp = cwdname; *cp; cp++) { 256 prc_buff(*cp); 257 } 258 259 prc_buff(NL); 260 } 261 262 /* 263 * This routine will remove repeated slashes from string. 264 */ 265 266 static void 267 rmslash(unsigned char *string) 268 { 269 unsigned char *pstring; 270 271 pstring = string; 272 while (*pstring) { 273 if (*pstring == SLASH && *(pstring+1) == SLASH) { 274 /* Remove repeated SLASH's */ 275 276 movstr(pstring+1, pstring); 277 continue; 278 } 279 pstring++; 280 } 281 282 --pstring; 283 if (pstring > string && *pstring == SLASH) { 284 /* Remove trailing / */ 285 286 *pstring = NULLCHAR; 287 } 288 } 289