b2cf18da4492e9a7eb8ff4e6126c6589d92c4bb7
[platform/upstream/nss.git] / nss / coreconf / nsinstall / pathsub.c
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 ** Pathname subroutines.
7 */
8 #include <assert.h>
9 #if defined(FREEBSD) || defined(BSDI) || defined(DARWIN)
10 #include <sys/types.h>
11 #endif /* FREEBSD */
12 #include <dirent.h>
13 #include <errno.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include "pathsub.h"
22 #ifdef USE_REENTRANT_LIBC
23 #include "libc_r.h"
24 #endif /* USE_REENTRANT_LIBC */
25
26 char *program;
27
28 void
29 fail(char *format, ...)
30 {
31     int error;
32     va_list ap;
33
34 #ifdef USE_REENTRANT_LIBC
35     R_STRERROR_INIT_R();
36 #endif
37
38     error = errno;
39     fprintf(stderr, "%s: ", program);
40     va_start(ap, format);
41     vfprintf(stderr, format, ap);
42     va_end(ap);
43     if (error) {
44
45 #ifdef USE_REENTRANT_LIBC
46     R_STRERROR_R(errno);
47         fprintf(stderr, ": %s", r_strerror_r);
48 #else
49         fprintf(stderr, ": %s", strerror(errno));
50 #endif
51     }
52  
53     putc('\n', stderr);
54     abort();
55     exit(1);
56 }
57
58 char *
59 getcomponent(char *path, char *name)
60 {
61     if (*path == '\0')
62         return 0;
63     if (*path == '/') {
64         *name++ = '/';
65     } else {
66         do {
67             *name++ = *path++;
68         } while (*path != '/' && *path != '\0');
69     }
70     *name = '\0';
71     while (*path == '/')
72         path++;
73     return path;
74 }
75
76 #ifdef UNIXWARE
77 /* The static buffer in Unixware's readdir is too small. */
78 struct dirent * readdir(DIR *d)
79 {
80     static struct dirent *buf = NULL;
81 #define MAX_PATH_LEN 1024
82
83     if (buf == NULL)
84         buf = (struct dirent *)xmalloc(sizeof(struct dirent) + MAX_PATH_LEN) ;
85     return readdir_r(d, buf);
86 }
87 #endif
88
89 /* APPARENT BUG - ignores argument "dir", uses ".." instead. */
90 char *
91 ino2name(ino_t ino, char *dir)
92 {
93     DIR *dp;
94     struct dirent *ep;
95     char *name;
96
97     dp = opendir("..");         /* XXX */
98     if (!dp)
99         fail("cannot read parent directory");
100     for (;;) {
101         if (!(ep = readdir(dp)))
102             fail("cannot find current directory");
103         if (ep->d_ino == ino)
104             break;
105     }
106     name = xstrdup(ep->d_name);
107     closedir(dp);
108     return name;
109 }
110
111 void *
112 xmalloc(size_t size)
113 {
114     void *p;
115
116     if (size <= 0)
117         fail("attempted to allocate %u bytes", size);
118     p = malloc(size);
119     if (!p)
120         fail("cannot allocate %u bytes", size);
121     return p;
122 }
123
124 char *
125 xstrdup(char *s)
126 {
127     if (!s || !s[0]) 
128         fail("Null pointer or empty string passed to xstrdup()");
129     return strcpy((char*)xmalloc(strlen(s) + 1), s);
130 }
131
132 char *
133 xbasename(char *path)
134 {
135     char *cp;
136
137     if (!path || !path[0]) 
138         fail("Null pointer or empty string passed to xbasename()");
139     while ((cp = strrchr(path, '/')) && cp[1] == '\0')
140         *cp = '\0';
141     if (!cp) return path;
142     return cp + 1;
143 }
144
145 void
146 xchdir(char *dir)
147 {
148     if (!dir || !dir[0]) 
149         fail("Null pointer or empty string passed to xchdir()");
150     if (chdir(dir) < 0)
151         fail("cannot change directory to %s", dir);
152 }
153
154 int
155 relatepaths(char *from, char *to, char *outpath)
156 {
157     char *cp, *cp2;
158     int len;
159     char buf[NAME_MAX];
160
161     assert(*from == '/' && *to == '/');
162     if (!from || *from != '/')
163         fail("relatepaths: from path does not start with /");
164     if (!to || *to != '/')
165         fail("relatepaths: to   path does not start with /");
166
167     for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
168         if (*cp == '\0')
169             break;
170     while (cp[-1] != '/')
171         cp--, cp2--;
172     if (cp - 1 == to) {
173         /* closest common ancestor is /, so use full pathname */
174         len = strlen(strcpy(outpath, to));
175         if (outpath[len] != '/') {
176             outpath[len++] = '/';
177             outpath[len] = '\0';
178         }
179     } else {
180         len = 0;
181         while ((cp2 = getcomponent(cp2, buf)) != 0) {
182             strcpy(outpath + len, "../");
183             len += 3;
184         }
185         while ((cp = getcomponent(cp, buf)) != 0) {
186             sprintf(outpath + len, "%s/", buf);
187             len += strlen(outpath + len);
188         }
189     }
190     return len;
191 }
192
193 void
194 reversepath(char *inpath, char *name, int len, char *outpath)
195 {
196     char *cp, *cp2;
197     char buf[NAME_MAX];
198     struct stat sb;
199
200     cp = strcpy(outpath + PATH_MAX - (len + 1), name);
201     cp2 = inpath;
202     while ((cp2 = getcomponent(cp2, buf)) != 0) {
203         if (strcmp(buf, ".") == 0)
204             continue;
205         if (strcmp(buf, "..") == 0) {
206             if (stat(".", &sb) < 0)
207                 fail("cannot stat current directory");
208             name = ino2name(sb.st_ino, "..");
209             len = strlen(name);
210             cp -= len + 1;
211             strcpy(cp, name);
212             cp[len] = '/';
213             free(name);
214             xchdir("..");
215         } else {
216             cp -= 3;
217             strncpy(cp, "../", 3);
218             xchdir(buf);
219         }
220     }
221     strcpy(outpath, cp);
222 }
223
224 void
225 diagnosePath(const char * path)
226 {
227     char *      myPath;
228     char *      slash;
229     int         rv;
230     struct stat sb;
231     char        buf[BUFSIZ];
232
233     if (!path || !path[0]) 
234         fail("Null pointer or empty string passed to mkdirs()");
235     myPath = strdup(path);
236     if (!myPath)
237         fail("strdup() failed!");
238     do {
239         rv = lstat(myPath, &sb);
240         if (rv < 0) {
241             perror(myPath);
242         } else if (S_ISLNK(sb.st_mode)) {
243             rv = readlink(myPath, buf, sizeof buf);
244             if (rv < 0) {
245                 perror("readlink");
246                 buf[0] = 0;
247             } else {
248                 buf[rv] = 0;
249             }
250             fprintf(stderr, "%s is a link to %s\n", myPath, buf);
251         } else if (S_ISDIR(sb.st_mode)) {
252             fprintf(stderr, "%s is a directory\n", myPath);
253             rv = access(myPath, X_OK);
254             if (rv < 0) {
255                 fprintf(stderr, "%s: no search permission\n", myPath);
256             }
257         } else {
258             fprintf(stderr, "%s is a file !?!\n", myPath);
259             rv = access(myPath, F_OK);
260             if (rv < 0) {
261                 fprintf(stderr, "%s does not exist\n", myPath);
262             }
263         }
264
265         /* chop path off one level. */
266         slash = strrchr(myPath, '/');
267         if (!slash)
268             slash = strrchr(myPath, '\\');
269         if (!slash)
270             slash = myPath;
271         *slash = 0;
272     } while (myPath[0]);
273     free(myPath);
274 }