]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/utils/chroot_realpath.c
Inital import
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / utils / chroot_realpath.c
1 /*
2  * chroot_realpath.c -- resolve pathname as if inside chroot
3  * Based on realpath.c Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; see the file COPYING.LIB.  If not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * 2005/09/12: Dan Howell (modified from realpath.c to emulate chroot)
21  */
22
23 #include "porting.h"
24
25 #define MAX_READLINKS 32
26
27 char *chroot_realpath(const char *root, const char *path,
28                       char resolved_path[]);
29
30 char *chroot_realpath(const char *root, const char *path,
31                       char resolved_path[])
32 {
33         char copy_path[PATH_MAX];
34         char link_path[PATH_MAX];
35         char got_path[PATH_MAX];
36         char *got_path_root = got_path;
37         char *new_path = got_path;
38         char *max_path;
39         int readlinks = 0;
40         int n;
41         int chroot_len;
42
43         /* Trivial case. */
44         if (root == NULL || *root == '\0' ||
45             (*root == '/' && root[1] == '\0')) {
46                 strcpy(resolved_path, path);
47                 return resolved_path;
48         }
49
50         chroot_len = strlen(root);
51
52         if (chroot_len + strlen(path) >= PATH_MAX - 3) {
53                 errno = ENAMETOOLONG;
54                 return NULL;
55         }
56
57         /* Make a copy of the source path since we may need to modify it. */
58         strcpy(copy_path, path);
59         path = copy_path;
60         max_path = copy_path + PATH_MAX - chroot_len - 3;
61
62         /* Start with the chroot path. */
63         strcpy(new_path, root);
64         new_path += chroot_len;
65         while (*new_path == '/' && new_path > got_path)
66                 new_path--;
67         got_path_root = new_path;
68         *new_path++ = '/';
69
70         /* Expand each slash-separated pathname component. */
71         while (*path != '\0') {
72                 /* Ignore stray "/". */
73                 if (*path == '/') {
74                         path++;
75                         continue;
76                 }
77                 if (*path == '.') {
78                         /* Ignore ".". */
79                         if (path[1] == '\0' || path[1] == '/') {
80                                 path++;
81                                 continue;
82                         }
83                         if (path[1] == '.') {
84                                 if (path[2] == '\0' || path[2] == '/') {
85                                         path += 2;
86                                         /* Ignore ".." at root. */
87                                         if (new_path == got_path_root + 1)
88                                                 continue;
89                                         /* Handle ".." by backing up. */
90                                         while ((--new_path)[-1] != '/') ;
91                                         continue;
92                                 }
93                         }
94                 }
95                 /* Safely copy the next pathname component. */
96                 while (*path != '\0' && *path != '/') {
97                         if (path > max_path) {
98                                 errno = ENAMETOOLONG;
99                                 return NULL;
100                         }
101                         *new_path++ = *path++;
102                 }
103                 if (*path == '\0')
104                         /* Don't follow symlink for last pathname component. */
105                         break;
106 #ifdef S_IFLNK
107                 /* Protect against infinite loops. */
108                 if (readlinks++ > MAX_READLINKS) {
109                         errno = ELOOP;
110                         return NULL;
111                 }
112                 /* See if latest pathname component is a symlink. */
113                 *new_path = '\0';
114                 n = readlink(got_path, link_path, PATH_MAX - 1);
115                 if (n < 0) {
116                         /* EINVAL means the file exists but isn't a symlink. */
117                         if (errno != EINVAL) {
118                                 /* Make sure it's null terminated. */
119                                 *new_path = '\0';
120                                 strcpy(resolved_path, got_path);
121                                 return NULL;
122                         }
123                 } else {
124                         /* Note: readlink doesn't add the null byte. */
125                         link_path[n] = '\0';
126                         if (*link_path == '/')
127                                 /* Start over for an absolute symlink. */
128                                 new_path = got_path_root;
129                         else
130                                 /* Otherwise back up over this component. */
131                                 while (*(--new_path) != '/') ;
132                         /* Safe sex check. */
133                         if (strlen(path) + n >= PATH_MAX - 2) {
134                                 errno = ENAMETOOLONG;
135                                 return NULL;
136                         }
137                         /* Insert symlink contents into path. */
138                         strcat(link_path, path);
139                         strcpy(copy_path, link_path);
140                         path = copy_path;
141                 }
142 #endif                          /* S_IFLNK */
143                 *new_path++ = '/';
144         }
145         /* Delete trailing slash but don't whomp a lone slash. */
146         if (new_path != got_path + 1 && new_path[-1] == '/')
147                 new_path--;
148         /* Make sure it's null terminated. */
149         *new_path = '\0';
150         strcpy(resolved_path, got_path);
151         return resolved_path;
152 }