1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1989, 1991, 1993
3*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
4*7c478bd9Sstevel@tonic-gate *
5*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
6*7c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions
7*7c478bd9Sstevel@tonic-gate * are met:
8*7c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
9*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
10*7c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
11*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
12*7c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15*7c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*7c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18*7c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*7c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*7c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*7c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*7c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*7c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*7c478bd9Sstevel@tonic-gate * SUCH DAMAGE.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #include "includes.h"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate #if !defined(HAVE_GETCWD)
30*7c478bd9Sstevel@tonic-gate
31*7c478bd9Sstevel@tonic-gate #if defined(LIBC_SCCS) && !defined(lint)
32*7c478bd9Sstevel@tonic-gate static char rcsid[] = "$OpenBSD: getcwd.c,v 1.6 2000/07/19 15:25:13 deraadt Exp $";
33*7c478bd9Sstevel@tonic-gate #endif /* LIBC_SCCS and not lint */
34*7c478bd9Sstevel@tonic-gate
35*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
37*7c478bd9Sstevel@tonic-gate #include <errno.h>
38*7c478bd9Sstevel@tonic-gate #include <dirent.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/dir.h>
40*7c478bd9Sstevel@tonic-gate #include <stdio.h>
41*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
42*7c478bd9Sstevel@tonic-gate #include <string.h>
43*7c478bd9Sstevel@tonic-gate #include "includes.h"
44*7c478bd9Sstevel@tonic-gate
45*7c478bd9Sstevel@tonic-gate #define ISDOT(dp) \
46*7c478bd9Sstevel@tonic-gate (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
47*7c478bd9Sstevel@tonic-gate (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
48*7c478bd9Sstevel@tonic-gate
49*7c478bd9Sstevel@tonic-gate char *
getcwd(char * pt,size_t size)50*7c478bd9Sstevel@tonic-gate getcwd(char *pt,size_t size)
51*7c478bd9Sstevel@tonic-gate {
52*7c478bd9Sstevel@tonic-gate register struct dirent *dp;
53*7c478bd9Sstevel@tonic-gate register DIR *dir = NULL;
54*7c478bd9Sstevel@tonic-gate register dev_t dev;
55*7c478bd9Sstevel@tonic-gate register ino_t ino;
56*7c478bd9Sstevel@tonic-gate register int first;
57*7c478bd9Sstevel@tonic-gate register char *bpt, *bup;
58*7c478bd9Sstevel@tonic-gate struct stat s;
59*7c478bd9Sstevel@tonic-gate dev_t root_dev;
60*7c478bd9Sstevel@tonic-gate ino_t root_ino;
61*7c478bd9Sstevel@tonic-gate size_t ptsize, upsize;
62*7c478bd9Sstevel@tonic-gate int save_errno;
63*7c478bd9Sstevel@tonic-gate char *ept, *eup, *up;
64*7c478bd9Sstevel@tonic-gate
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate * If no buffer specified by the user, allocate one as necessary.
67*7c478bd9Sstevel@tonic-gate * If a buffer is specified, the size has to be non-zero. The path
68*7c478bd9Sstevel@tonic-gate * is built from the end of the buffer backwards.
69*7c478bd9Sstevel@tonic-gate */
70*7c478bd9Sstevel@tonic-gate if (pt) {
71*7c478bd9Sstevel@tonic-gate ptsize = 0;
72*7c478bd9Sstevel@tonic-gate if (!size) {
73*7c478bd9Sstevel@tonic-gate errno = EINVAL;
74*7c478bd9Sstevel@tonic-gate return (NULL);
75*7c478bd9Sstevel@tonic-gate }
76*7c478bd9Sstevel@tonic-gate ept = pt + size;
77*7c478bd9Sstevel@tonic-gate } else {
78*7c478bd9Sstevel@tonic-gate if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
79*7c478bd9Sstevel@tonic-gate return (NULL);
80*7c478bd9Sstevel@tonic-gate ept = pt + ptsize;
81*7c478bd9Sstevel@tonic-gate }
82*7c478bd9Sstevel@tonic-gate bpt = ept - 1;
83*7c478bd9Sstevel@tonic-gate *bpt = '\0';
84*7c478bd9Sstevel@tonic-gate
85*7c478bd9Sstevel@tonic-gate /*
86*7c478bd9Sstevel@tonic-gate * Allocate bytes (1024 - malloc space) for the string of "../"'s.
87*7c478bd9Sstevel@tonic-gate * Should always be enough (it's 340 levels). If it's not, allocate
88*7c478bd9Sstevel@tonic-gate * as necessary. Special * case the first stat, it's ".", not "..".
89*7c478bd9Sstevel@tonic-gate */
90*7c478bd9Sstevel@tonic-gate if ((up = malloc(upsize = 1024 - 4)) == NULL)
91*7c478bd9Sstevel@tonic-gate goto err;
92*7c478bd9Sstevel@tonic-gate eup = up + MAXPATHLEN;
93*7c478bd9Sstevel@tonic-gate bup = up;
94*7c478bd9Sstevel@tonic-gate up[0] = '.';
95*7c478bd9Sstevel@tonic-gate up[1] = '\0';
96*7c478bd9Sstevel@tonic-gate
97*7c478bd9Sstevel@tonic-gate /* Save root values, so know when to stop. */
98*7c478bd9Sstevel@tonic-gate if (stat("/", &s))
99*7c478bd9Sstevel@tonic-gate goto err;
100*7c478bd9Sstevel@tonic-gate root_dev = s.st_dev;
101*7c478bd9Sstevel@tonic-gate root_ino = s.st_ino;
102*7c478bd9Sstevel@tonic-gate
103*7c478bd9Sstevel@tonic-gate errno = 0; /* XXX readdir has no error return. */
104*7c478bd9Sstevel@tonic-gate
105*7c478bd9Sstevel@tonic-gate for (first = 1;; first = 0) {
106*7c478bd9Sstevel@tonic-gate /* Stat the current level. */
107*7c478bd9Sstevel@tonic-gate if (lstat(up, &s))
108*7c478bd9Sstevel@tonic-gate goto err;
109*7c478bd9Sstevel@tonic-gate
110*7c478bd9Sstevel@tonic-gate /* Save current node values. */
111*7c478bd9Sstevel@tonic-gate ino = s.st_ino;
112*7c478bd9Sstevel@tonic-gate dev = s.st_dev;
113*7c478bd9Sstevel@tonic-gate
114*7c478bd9Sstevel@tonic-gate /* Check for reaching root. */
115*7c478bd9Sstevel@tonic-gate if (root_dev == dev && root_ino == ino) {
116*7c478bd9Sstevel@tonic-gate *--bpt = '/';
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate * It's unclear that it's a requirement to copy the
119*7c478bd9Sstevel@tonic-gate * path to the beginning of the buffer, but it's always
120*7c478bd9Sstevel@tonic-gate * been that way and stuff would probably break.
121*7c478bd9Sstevel@tonic-gate */
122*7c478bd9Sstevel@tonic-gate memmove(pt, bpt, ept - bpt);
123*7c478bd9Sstevel@tonic-gate free(up);
124*7c478bd9Sstevel@tonic-gate return (pt);
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate * Build pointer to the parent directory, allocating memory
129*7c478bd9Sstevel@tonic-gate * as necessary. Max length is 3 for "../", the largest
130*7c478bd9Sstevel@tonic-gate * possible component name, plus a trailing NULL.
131*7c478bd9Sstevel@tonic-gate */
132*7c478bd9Sstevel@tonic-gate if (bup + 3 + MAXNAMLEN + 1 >= eup) {
133*7c478bd9Sstevel@tonic-gate char *nup;
134*7c478bd9Sstevel@tonic-gate
135*7c478bd9Sstevel@tonic-gate if ((nup = realloc(up, upsize *= 2)) == NULL)
136*7c478bd9Sstevel@tonic-gate goto err;
137*7c478bd9Sstevel@tonic-gate up = nup;
138*7c478bd9Sstevel@tonic-gate bup = up;
139*7c478bd9Sstevel@tonic-gate eup = up + upsize;
140*7c478bd9Sstevel@tonic-gate }
141*7c478bd9Sstevel@tonic-gate *bup++ = '.';
142*7c478bd9Sstevel@tonic-gate *bup++ = '.';
143*7c478bd9Sstevel@tonic-gate *bup = '\0';
144*7c478bd9Sstevel@tonic-gate
145*7c478bd9Sstevel@tonic-gate /* Open and stat parent directory.
146*7c478bd9Sstevel@tonic-gate * RACE?? - replaced fstat(dirfd(dir), &s) w/ lstat(up,&s)
147*7c478bd9Sstevel@tonic-gate */
148*7c478bd9Sstevel@tonic-gate if (!(dir = opendir(up)) || lstat(up,&s))
149*7c478bd9Sstevel@tonic-gate goto err;
150*7c478bd9Sstevel@tonic-gate
151*7c478bd9Sstevel@tonic-gate /* Add trailing slash for next directory. */
152*7c478bd9Sstevel@tonic-gate *bup++ = '/';
153*7c478bd9Sstevel@tonic-gate
154*7c478bd9Sstevel@tonic-gate /*
155*7c478bd9Sstevel@tonic-gate * If it's a mount point, have to stat each element because
156*7c478bd9Sstevel@tonic-gate * the inode number in the directory is for the entry in the
157*7c478bd9Sstevel@tonic-gate * parent directory, not the inode number of the mounted file.
158*7c478bd9Sstevel@tonic-gate */
159*7c478bd9Sstevel@tonic-gate save_errno = 0;
160*7c478bd9Sstevel@tonic-gate if (s.st_dev == dev) {
161*7c478bd9Sstevel@tonic-gate for (;;) {
162*7c478bd9Sstevel@tonic-gate if (!(dp = readdir(dir)))
163*7c478bd9Sstevel@tonic-gate goto notfound;
164*7c478bd9Sstevel@tonic-gate if (dp->d_fileno == ino)
165*7c478bd9Sstevel@tonic-gate break;
166*7c478bd9Sstevel@tonic-gate }
167*7c478bd9Sstevel@tonic-gate } else
168*7c478bd9Sstevel@tonic-gate for (;;) {
169*7c478bd9Sstevel@tonic-gate if (!(dp = readdir(dir)))
170*7c478bd9Sstevel@tonic-gate goto notfound;
171*7c478bd9Sstevel@tonic-gate if (ISDOT(dp))
172*7c478bd9Sstevel@tonic-gate continue;
173*7c478bd9Sstevel@tonic-gate memmove(bup, dp->d_name, dp->d_namlen + 1);
174*7c478bd9Sstevel@tonic-gate
175*7c478bd9Sstevel@tonic-gate /* Save the first error for later. */
176*7c478bd9Sstevel@tonic-gate if (lstat(up, &s)) {
177*7c478bd9Sstevel@tonic-gate if (!save_errno)
178*7c478bd9Sstevel@tonic-gate save_errno = errno;
179*7c478bd9Sstevel@tonic-gate errno = 0;
180*7c478bd9Sstevel@tonic-gate continue;
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate if (s.st_dev == dev && s.st_ino == ino)
183*7c478bd9Sstevel@tonic-gate break;
184*7c478bd9Sstevel@tonic-gate }
185*7c478bd9Sstevel@tonic-gate
186*7c478bd9Sstevel@tonic-gate /*
187*7c478bd9Sstevel@tonic-gate * Check for length of the current name, preceding slash,
188*7c478bd9Sstevel@tonic-gate * leading slash.
189*7c478bd9Sstevel@tonic-gate */
190*7c478bd9Sstevel@tonic-gate if (bpt - pt < dp->d_namlen + (first ? 1 : 2)) {
191*7c478bd9Sstevel@tonic-gate size_t len, off;
192*7c478bd9Sstevel@tonic-gate char *npt;
193*7c478bd9Sstevel@tonic-gate
194*7c478bd9Sstevel@tonic-gate if (!ptsize) {
195*7c478bd9Sstevel@tonic-gate errno = ERANGE;
196*7c478bd9Sstevel@tonic-gate goto err;
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate off = bpt - pt;
199*7c478bd9Sstevel@tonic-gate len = ept - bpt;
200*7c478bd9Sstevel@tonic-gate if ((npt = realloc(pt, ptsize *= 2)) == NULL)
201*7c478bd9Sstevel@tonic-gate goto err;
202*7c478bd9Sstevel@tonic-gate pt = npt;
203*7c478bd9Sstevel@tonic-gate bpt = pt + off;
204*7c478bd9Sstevel@tonic-gate ept = pt + ptsize;
205*7c478bd9Sstevel@tonic-gate memmove(ept - len, bpt, len);
206*7c478bd9Sstevel@tonic-gate bpt = ept - len;
207*7c478bd9Sstevel@tonic-gate }
208*7c478bd9Sstevel@tonic-gate if (!first)
209*7c478bd9Sstevel@tonic-gate *--bpt = '/';
210*7c478bd9Sstevel@tonic-gate bpt -= dp->d_namlen;
211*7c478bd9Sstevel@tonic-gate memmove(bpt, dp->d_name, dp->d_namlen);
212*7c478bd9Sstevel@tonic-gate (void)closedir(dir);
213*7c478bd9Sstevel@tonic-gate
214*7c478bd9Sstevel@tonic-gate /* Truncate any file name. */
215*7c478bd9Sstevel@tonic-gate *bup = '\0';
216*7c478bd9Sstevel@tonic-gate }
217*7c478bd9Sstevel@tonic-gate
218*7c478bd9Sstevel@tonic-gate notfound:
219*7c478bd9Sstevel@tonic-gate /*
220*7c478bd9Sstevel@tonic-gate * If readdir set errno, use it, not any saved error; otherwise,
221*7c478bd9Sstevel@tonic-gate * didn't find the current directory in its parent directory, set
222*7c478bd9Sstevel@tonic-gate * errno to ENOENT.
223*7c478bd9Sstevel@tonic-gate */
224*7c478bd9Sstevel@tonic-gate if (!errno)
225*7c478bd9Sstevel@tonic-gate errno = save_errno ? save_errno : ENOENT;
226*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
227*7c478bd9Sstevel@tonic-gate err:
228*7c478bd9Sstevel@tonic-gate if (ptsize)
229*7c478bd9Sstevel@tonic-gate free(pt);
230*7c478bd9Sstevel@tonic-gate if (up)
231*7c478bd9Sstevel@tonic-gate free(up);
232*7c478bd9Sstevel@tonic-gate if (dir)
233*7c478bd9Sstevel@tonic-gate (void)closedir(dir);
234*7c478bd9Sstevel@tonic-gate return (NULL);
235*7c478bd9Sstevel@tonic-gate }
236*7c478bd9Sstevel@tonic-gate
237*7c478bd9Sstevel@tonic-gate #endif /* !defined(HAVE_GETCWD) */
238*7c478bd9Sstevel@tonic-gate
239*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
240