1*3496Scth /*
2*3496Scth * CDDL HEADER START
3*3496Scth *
4*3496Scth * The contents of this file are subject to the terms of the
5*3496Scth * Common Development and Distribution License (the "License").
6*3496Scth * You may not use this file except in compliance with the License.
7*3496Scth *
8*3496Scth * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3496Scth * or http://www.opensolaris.org/os/licensing.
10*3496Scth * See the License for the specific language governing permissions
11*3496Scth * and limitations under the License.
12*3496Scth *
13*3496Scth * When distributing Covered Code, include this CDDL HEADER in each
14*3496Scth * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3496Scth * If applicable, add the following below this CDDL HEADER, with the
16*3496Scth * fields enclosed by brackets "[]" replaced with your own identifying
17*3496Scth * information: Portions Copyright [yyyy] [name of copyright owner]
18*3496Scth *
19*3496Scth * CDDL HEADER END
20*3496Scth */
21*3496Scth /*
22*3496Scth * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23*3496Scth * Use is subject to license terms.
24*3496Scth */
25*3496Scth
26*3496Scth #pragma ident "%Z%%M% %I% %E% SMI"
27*3496Scth
28*3496Scth /*
29*3496Scth * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
30*3496Scth *
31*3496Scth * Redistribution and use in source and binary forms, with or without
32*3496Scth * modification, are permitted provided that the following conditions
33*3496Scth * are met:
34*3496Scth * 1. Redistributions of source code must retain the above copyright
35*3496Scth * notice, this list of conditions and the following disclaimer.
36*3496Scth * 2. Redistributions in binary form must reproduce the above copyright
37*3496Scth * notice, this list of conditions and the following disclaimer in the
38*3496Scth * documentation and/or other materials provided with the distribution.
39*3496Scth * 3. The names of the authors may not be used to endorse or promote
40*3496Scth * products derived from this software without specific prior written
41*3496Scth * permission.
42*3496Scth *
43*3496Scth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44*3496Scth * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45*3496Scth * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46*3496Scth * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
47*3496Scth * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48*3496Scth * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49*3496Scth * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50*3496Scth * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51*3496Scth * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52*3496Scth * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53*3496Scth * SUCH DAMAGE.
54*3496Scth */
55*3496Scth /*
56*3496Scth * http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/realpath.c
57*3496Scth * $OpenBSD: realpath.c,v 1.13 2005/08/08 08:05:37 espie Exp $
58*3496Scth */
59*3496Scth
60*3496Scth #include <stdio.h>
61*3496Scth #include <unistd.h>
62*3496Scth #include <string.h>
63*3496Scth #include <limits.h>
64*3496Scth #include <errno.h>
65*3496Scth #include <sys/types.h>
66*3496Scth #include <sys/stat.h>
67*3496Scth #include <sys/param.h>
68*3496Scth
69*3496Scth /*
70*3496Scth * char *s_realpath(const char *path, char resolved_path[MAXPATHLEN]);
71*3496Scth *
72*3496Scth * Find the real name of path, by removing all ".", ".." and symlink
73*3496Scth * components. Returns (resolved) on success, or (NULL) on failure,
74*3496Scth * in which case the path which caused trouble is left in (resolved).
75*3496Scth *
76*3496Scth * DEVINFO: For libdevinfo we have added code to special case symlinks into
77*3496Scth * /devices - the path below that point is known to not point to any
78*3496Scth * additional symlinks. This knowledge allows us to avoid causing attach.
79*3496Scth */
80*3496Scth char *
s_realpath(const char * path,char * resolved)81*3496Scth s_realpath(const char *path, char *resolved)
82*3496Scth {
83*3496Scth struct stat sb;
84*3496Scth char *p, *q, *s;
85*3496Scth size_t left_len, resolved_len;
86*3496Scth unsigned symlinks;
87*3496Scth int serrno, slen;
88*3496Scth char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
89*3496Scth
90*3496Scth serrno = errno;
91*3496Scth symlinks = 0;
92*3496Scth if (path[0] == '/') {
93*3496Scth resolved[0] = '/';
94*3496Scth resolved[1] = '\0';
95*3496Scth if (path[1] == '\0')
96*3496Scth return (resolved);
97*3496Scth resolved_len = 1;
98*3496Scth left_len = strlcpy(left, path + 1, sizeof (left));
99*3496Scth } else {
100*3496Scth if (getcwd(resolved, PATH_MAX) == NULL) {
101*3496Scth (void) strlcpy(resolved, ".", PATH_MAX);
102*3496Scth return (NULL);
103*3496Scth }
104*3496Scth resolved_len = strlen(resolved);
105*3496Scth left_len = strlcpy(left, path, sizeof (left));
106*3496Scth }
107*3496Scth if (left_len >= sizeof (left) || resolved_len >= PATH_MAX) {
108*3496Scth errno = ENAMETOOLONG;
109*3496Scth return (NULL);
110*3496Scth }
111*3496Scth
112*3496Scth /*
113*3496Scth * Iterate over path components in `left'.
114*3496Scth */
115*3496Scth while (left_len != 0) {
116*3496Scth /*
117*3496Scth * Extract the next path component and adjust `left'
118*3496Scth * and its length.
119*3496Scth */
120*3496Scth p = strchr(left, '/');
121*3496Scth s = p ? p : left + left_len;
122*3496Scth if (s - left >= sizeof (next_token)) {
123*3496Scth errno = ENAMETOOLONG;
124*3496Scth return (NULL);
125*3496Scth }
126*3496Scth (void) memcpy(next_token, left, s - left);
127*3496Scth next_token[s - left] = '\0';
128*3496Scth left_len -= s - left;
129*3496Scth if (p != NULL)
130*3496Scth (void) memmove(left, s + 1, left_len + 1);
131*3496Scth if (resolved[resolved_len - 1] != '/') {
132*3496Scth if (resolved_len + 1 >= PATH_MAX) {
133*3496Scth errno = ENAMETOOLONG;
134*3496Scth return (NULL);
135*3496Scth }
136*3496Scth resolved[resolved_len++] = '/';
137*3496Scth resolved[resolved_len] = '\0';
138*3496Scth }
139*3496Scth if (next_token[0] == '\0')
140*3496Scth continue;
141*3496Scth else if (strcmp(next_token, ".") == 0)
142*3496Scth continue;
143*3496Scth else if (strcmp(next_token, "..") == 0) {
144*3496Scth /*
145*3496Scth * Strip the last path component except when we have
146*3496Scth * single "/"
147*3496Scth */
148*3496Scth if (resolved_len > 1) {
149*3496Scth resolved[resolved_len - 1] = '\0';
150*3496Scth q = strrchr(resolved, '/') + 1;
151*3496Scth *q = '\0';
152*3496Scth resolved_len = q - resolved;
153*3496Scth }
154*3496Scth continue;
155*3496Scth }
156*3496Scth
157*3496Scth /*
158*3496Scth * Append the next path component and lstat() it. If
159*3496Scth * lstat() fails we still can return successfully if
160*3496Scth * there are no more path components left.
161*3496Scth */
162*3496Scth resolved_len = strlcat(resolved, next_token, PATH_MAX);
163*3496Scth if (resolved_len >= PATH_MAX) {
164*3496Scth errno = ENAMETOOLONG;
165*3496Scth return (NULL);
166*3496Scth }
167*3496Scth
168*3496Scth /*
169*3496Scth * DEVINFO: Check if link points into /devices and resolve
170*3496Scth * without causing attach if that is the case - there are no
171*3496Scth * further symlinks in /devices.
172*3496Scth */
173*3496Scth if (strcmp(resolved, "/devices") == 0) {
174*3496Scth resolved[resolved_len] = '/';
175*3496Scth resolved_len = strlcat(resolved, left, sizeof (left));
176*3496Scth left_len = 0;
177*3496Scth continue;
178*3496Scth }
179*3496Scth
180*3496Scth if (lstat(resolved, &sb) != 0) {
181*3496Scth if (errno == ENOENT && p == NULL) {
182*3496Scth errno = serrno;
183*3496Scth return (resolved);
184*3496Scth }
185*3496Scth return (NULL);
186*3496Scth }
187*3496Scth
188*3496Scth if (S_ISLNK(sb.st_mode)) {
189*3496Scth if (symlinks++ > MAXSYMLINKS) {
190*3496Scth errno = ELOOP;
191*3496Scth return (NULL);
192*3496Scth }
193*3496Scth slen = readlink(resolved, symlink,
194*3496Scth sizeof (symlink) - 1);
195*3496Scth if (slen < 0)
196*3496Scth return (NULL);
197*3496Scth symlink[slen] = '\0';
198*3496Scth
199*3496Scth if (symlink[0] == '/') {
200*3496Scth resolved[1] = 0;
201*3496Scth resolved_len = 1;
202*3496Scth } else if (resolved_len > 1) {
203*3496Scth /* Strip the last path component. */
204*3496Scth resolved[resolved_len - 1] = '\0';
205*3496Scth q = strrchr(resolved, '/') + 1;
206*3496Scth *q = '\0';
207*3496Scth resolved_len = q - resolved;
208*3496Scth }
209*3496Scth
210*3496Scth /*
211*3496Scth * If there are any path components left, then
212*3496Scth * append them to symlink. The result is placed
213*3496Scth * in `left'.
214*3496Scth */
215*3496Scth if (p != NULL) {
216*3496Scth if (symlink[slen - 1] != '/') {
217*3496Scth if (slen + 1 >= sizeof (symlink)) {
218*3496Scth errno = ENAMETOOLONG;
219*3496Scth return (NULL);
220*3496Scth }
221*3496Scth symlink[slen] = '/';
222*3496Scth symlink[slen + 1] = 0;
223*3496Scth }
224*3496Scth left_len = strlcat(symlink, left,
225*3496Scth sizeof (left));
226*3496Scth if (left_len >= sizeof (left)) {
227*3496Scth errno = ENAMETOOLONG;
228*3496Scth return (NULL);
229*3496Scth }
230*3496Scth }
231*3496Scth left_len = strlcpy(left, symlink, sizeof (left));
232*3496Scth }
233*3496Scth }
234*3496Scth
235*3496Scth /*
236*3496Scth * Remove trailing slash except when the resolved pathname
237*3496Scth * is a single "/".
238*3496Scth */
239*3496Scth if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
240*3496Scth resolved[resolved_len - 1] = '\0';
241*3496Scth return (resolved);
242*3496Scth }
243