File: | pr/Linux6.7_x86_64_gcc_glibc_PTH_64_DBG.OBJ/config/../../config/nsinstall.c |
Warning: | line 425, column 13 Access to field 'd_ino' results in a dereference of a null pointer (loaded from variable 'ep') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
5 | ||||
6 | /* | |||
7 | ** Netscape portable install command. | |||
8 | ** | |||
9 | ** Brendan Eich, 7/20/95 | |||
10 | */ | |||
11 | #include <stdio.h> /* OSF/1 requires this before grp.h, so put it first */ | |||
12 | #include <assert.h> | |||
13 | #include <fcntl.h> | |||
14 | #include <grp.h> | |||
15 | #include <pwd.h> | |||
16 | #include <stdlib.h> | |||
17 | #include <string.h> | |||
18 | #include <unistd.h> | |||
19 | #include <utime.h> | |||
20 | #include <sys/types.h> | |||
21 | #include <sys/stat.h> | |||
22 | #include <dirent.h> | |||
23 | #include <errno(*__errno_location ()).h> | |||
24 | #include <stdarg.h> | |||
25 | #ifdef USE_REENTRANT_LIBC | |||
26 | #include "libc_r.h" | |||
27 | #endif /* USE_REENTRANT_LIBC */ | |||
28 | ||||
29 | #include "pathsub.h" | |||
30 | ||||
31 | #define HAVE_FCHMOD | |||
32 | ||||
33 | ||||
34 | /* | |||
35 | * Does getcwd() take NULL as the first argument and malloc | |||
36 | * the result buffer? | |||
37 | */ | |||
38 | #if !defined(DARWIN) | |||
39 | #define GETCWD_CAN_MALLOC | |||
40 | #endif | |||
41 | ||||
42 | #if defined(LINUX1) || defined(__GNU__) || defined(__GLIBC__2) | |||
43 | #include <getopt.h> | |||
44 | #endif | |||
45 | ||||
46 | #ifdef QNX | |||
47 | #define d_ino d_stat.st_ino | |||
48 | #endif | |||
49 | ||||
50 | static void | |||
51 | usage(void) | |||
52 | { | |||
53 | fprintf(stderrstderr, | |||
54 | "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" | |||
55 | " %*s [-DdltR] file [file ...] directory\n", | |||
56 | program, (int)strlen(program), ""); | |||
57 | exit(2); | |||
58 | } | |||
59 | ||||
60 | static int | |||
61 | mkdirs(char *path, mode_t mode) | |||
62 | { | |||
63 | char *cp; | |||
64 | struct stat sb; | |||
65 | int res; | |||
66 | ||||
67 | while (*path == '/' && path[1] == '/') { | |||
68 | path++; | |||
69 | } | |||
70 | for (cp = strrchr(path, '/'); cp && cp != path && cp[-1] == '/'; cp--) | |||
71 | ; | |||
72 | if (cp && cp != path) { | |||
73 | *cp = '\0'; | |||
74 | if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) && | |||
75 | mkdirs(path, mode) < 0) { | |||
76 | return -1; | |||
77 | } | |||
78 | *cp = '/'; | |||
79 | } | |||
80 | res = mkdir(path, mode); | |||
81 | if ((res != 0) && (errno(*__errno_location ()) == EEXIST17)) { | |||
82 | return 0; | |||
83 | } | |||
84 | else { | |||
85 | return res; | |||
86 | } | |||
87 | } | |||
88 | ||||
89 | static uid_t | |||
90 | touid(char *owner) | |||
91 | { | |||
92 | struct passwd *pw; | |||
93 | uid_t uid; | |||
94 | char *cp; | |||
95 | ||||
96 | pw = getpwnam(owner); | |||
97 | if (pw) { | |||
98 | return pw->pw_uid; | |||
99 | } | |||
100 | uid = strtol(owner, &cp, 0); | |||
101 | if (uid == 0 && cp == owner) { | |||
102 | fail("cannot find uid for %s", owner); | |||
103 | } | |||
104 | return uid; | |||
105 | } | |||
106 | ||||
107 | static gid_t | |||
108 | togid(char *group) | |||
109 | { | |||
110 | struct group *gr; | |||
111 | gid_t gid; | |||
112 | char *cp; | |||
113 | ||||
114 | gr = getgrnam(group); | |||
115 | if (gr) { | |||
116 | return gr->gr_gid; | |||
117 | } | |||
118 | gid = strtol(group, &cp, 0); | |||
119 | if (gid == 0 && cp == group) { | |||
120 | fail("cannot find gid for %s", group); | |||
121 | } | |||
122 | return gid; | |||
123 | } | |||
124 | ||||
125 | int | |||
126 | main(int argc, char **argv) | |||
127 | { | |||
128 | int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; | |||
129 | mode_t mode = 0755; | |||
130 | char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ8192]; | |||
131 | uid_t uid; | |||
132 | gid_t gid; | |||
133 | struct stat sb, tosb; | |||
134 | struct utimbuf utb; | |||
135 | ||||
136 | program = argv[0]; | |||
137 | cwd = linkname = linkprefix = owner = group = 0; | |||
138 | onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; | |||
139 | ||||
140 | while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF(-1)) { | |||
141 | switch (opt) { | |||
142 | case 'C': | |||
143 | cwd = optarg; | |||
144 | break; | |||
145 | case 'D': | |||
146 | onlydir = 1; | |||
147 | break; | |||
148 | case 'd': | |||
149 | dodir = 1; | |||
150 | break; | |||
151 | case 'l': | |||
152 | dolink = 1; | |||
153 | break; | |||
154 | case 'L': | |||
155 | linkprefix = optarg; | |||
156 | lplen = strlen(linkprefix); | |||
157 | dolink = 1; | |||
158 | break; | |||
159 | case 'R': | |||
160 | dolink = dorelsymlink = 1; | |||
161 | break; | |||
162 | case 'm': | |||
163 | mode = strtoul(optarg, &cp, 8); | |||
164 | if (mode == 0 && cp == optarg) { | |||
165 | usage(); | |||
166 | } | |||
167 | break; | |||
168 | case 'o': | |||
169 | owner = optarg; | |||
170 | break; | |||
171 | case 'g': | |||
172 | group = optarg; | |||
173 | break; | |||
174 | case 't': | |||
175 | dotimes = 1; | |||
176 | break; | |||
177 | default: | |||
178 | usage(); | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | argc -= optind; | |||
183 | argv += optind; | |||
184 | if (argc < 2 - onlydir) { | |||
185 | usage(); | |||
186 | } | |||
187 | ||||
188 | todir = argv[argc-1]; | |||
189 | if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) && | |||
190 | mkdirs(todir, 0777) < 0) { | |||
191 | fail("cannot make directory %s", todir); | |||
192 | } | |||
193 | if (onlydir) { | |||
194 | return 0; | |||
195 | } | |||
196 | ||||
197 | if (!cwd) { | |||
198 | #ifdef GETCWD_CAN_MALLOC | |||
199 | cwd = getcwd(0, PATH_MAX4096); | |||
200 | #else | |||
201 | cwd = malloc(PATH_MAX4096 + 1); | |||
202 | cwd = getcwd(cwd, PATH_MAX4096); | |||
203 | #endif | |||
204 | } | |||
205 | xchdir(todir); | |||
206 | #ifdef GETCWD_CAN_MALLOC | |||
207 | todir = getcwd(0, PATH_MAX4096); | |||
208 | #else | |||
209 | todir = malloc(PATH_MAX4096 + 1); | |||
210 | todir = getcwd(todir, PATH_MAX4096); | |||
211 | #endif | |||
212 | xchdir(cwd); | |||
213 | tdlen = strlen(todir); | |||
214 | ||||
215 | uid = owner ? touid(owner) : -1; | |||
216 | gid = group ? togid(group) : -1; | |||
217 | ||||
218 | while (--argc > 0) { | |||
219 | name = *argv++; | |||
220 | len = strlen(name); | |||
221 | base = xbasename(name); | |||
222 | bnlen = strlen(base); | |||
223 | toname = (char*)xmalloc(tdlen + 1 + bnlen + 1); | |||
224 | sprintf(toname, "%s/%s", todir, base); | |||
225 | exists = (lstat(toname, &tosb) == 0); | |||
226 | ||||
227 | if (dodir) { | |||
228 | /* -d means create a directory, always */ | |||
229 | if (exists && !S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000))) { | |||
230 | (void) unlink(toname); | |||
231 | exists = 0; | |||
232 | } | |||
233 | if (!exists && mkdir(toname, mode) < 0) { | |||
234 | fail("cannot make directory %s", toname); | |||
235 | } | |||
236 | if ((owner || group) && chown(toname, uid, gid) < 0) { | |||
237 | fail("cannot change owner of %s", toname); | |||
238 | } | |||
239 | } else if (dolink) { | |||
240 | if (*name == '/') { | |||
241 | /* source is absolute pathname, link to it directly */ | |||
242 | linkname = 0; | |||
243 | } else { | |||
244 | if (linkprefix) { | |||
245 | /* -L implies -l and prefixes names with a $cwd arg. */ | |||
246 | len += lplen + 1; | |||
247 | linkname = (char*)xmalloc(len + 1); | |||
248 | sprintf(linkname, "%s/%s", linkprefix, name); | |||
249 | } else if (dorelsymlink) { | |||
250 | /* Symlink the relative path from todir to source name. */ | |||
251 | linkname = (char*)xmalloc(PATH_MAX4096); | |||
252 | ||||
253 | if (*todir == '/') { | |||
254 | /* todir is absolute: skip over common prefix. */ | |||
255 | lplen = relatepaths(todir, cwd, linkname); | |||
256 | strcpy(linkname + lplen, name); | |||
257 | } else { | |||
258 | /* todir is named by a relative path: reverse it. */ | |||
259 | reversepath(todir, name, len, linkname); | |||
260 | xchdir(cwd); | |||
261 | } | |||
262 | ||||
263 | len = strlen(linkname); | |||
264 | } | |||
265 | name = linkname; | |||
266 | } | |||
267 | ||||
268 | /* Check for a pre-existing symlink with identical content. */ | |||
269 | if (exists && | |||
270 | (!S_ISLNK(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0120000)) || | |||
271 | readlink(toname, buf, sizeof buf) != len || | |||
272 | strncmp(buf, name, len) != 0)) { | |||
273 | (void) (S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000)) ? rmdir : unlink)(toname); | |||
274 | exists = 0; | |||
275 | } | |||
276 | if (!exists && symlink(name, toname) < 0) { | |||
277 | fail("cannot make symbolic link %s", toname); | |||
278 | } | |||
279 | #ifdef HAVE_LCHOWN1 | |||
280 | if ((owner || group) && lchown(toname, uid, gid) < 0) { | |||
281 | fail("cannot change owner of %s", toname); | |||
282 | } | |||
283 | #endif | |||
284 | ||||
285 | if (linkname) { | |||
286 | free(linkname); | |||
287 | linkname = 0; | |||
288 | } | |||
289 | } else { | |||
290 | /* Copy from name to toname, which might be the same file. */ | |||
291 | fromfd = open(name, O_RDONLY00); | |||
292 | if (fromfd < 0 || fstat(fromfd, &sb) < 0) { | |||
293 | fail("cannot access %s", name); | |||
294 | } | |||
295 | if (exists && (!S_ISREG(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0100000)) || access(toname, W_OK2) < 0)) { | |||
296 | (void) (S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000)) ? rmdir : unlink)(toname); | |||
297 | } | |||
298 | tofd = open(toname, O_CREAT0100 | O_WRONLY01, 0666); | |||
299 | if (tofd < 0) { | |||
300 | fail("cannot create %s", toname); | |||
301 | } | |||
302 | ||||
303 | bp = buf; | |||
304 | while ((cc = read(fromfd, bp, sizeof buf)) > 0) { | |||
305 | while ((wc = write(tofd, bp, cc)) > 0) { | |||
306 | if ((cc -= wc) == 0) { | |||
307 | break; | |||
308 | } | |||
309 | bp += wc; | |||
310 | } | |||
311 | if (wc < 0) { | |||
312 | fail("cannot write to %s", toname); | |||
313 | } | |||
314 | } | |||
315 | if (cc < 0) { | |||
316 | fail("cannot read from %s", name); | |||
317 | } | |||
318 | ||||
319 | if (ftruncate(tofd, sb.st_size) < 0) { | |||
320 | fail("cannot truncate %s", toname); | |||
321 | } | |||
322 | if (dotimes) { | |||
323 | utb.actime = sb.st_atimest_atim.tv_sec; | |||
324 | utb.modtime = sb.st_mtimest_mtim.tv_sec; | |||
325 | if (utime(toname, &utb) < 0) { | |||
326 | fail("cannot set times of %s", toname); | |||
327 | } | |||
328 | } | |||
329 | #ifdef HAVE_FCHMOD | |||
330 | if (fchmod(tofd, mode) < 0) | |||
331 | #else | |||
332 | if (chmod(toname, mode) < 0) | |||
333 | #endif | |||
334 | fail("cannot change mode of %s", toname); | |||
335 | if ((owner || group) && fchown(tofd, uid, gid) < 0) { | |||
336 | fail("cannot change owner of %s", toname); | |||
337 | } | |||
338 | ||||
339 | /* Must check for delayed (NFS) write errors on close. */ | |||
340 | if (close(tofd) < 0) { | |||
341 | fail("cannot write to %s", toname); | |||
342 | } | |||
343 | close(fromfd); | |||
344 | } | |||
345 | ||||
346 | free(toname); | |||
347 | } | |||
348 | ||||
349 | free(cwd); | |||
350 | free(todir); | |||
351 | return 0; | |||
352 | } | |||
353 | ||||
354 | /* | |||
355 | ** Pathname subroutines. | |||
356 | ** | |||
357 | ** Brendan Eich, 8/29/95 | |||
358 | */ | |||
359 | ||||
360 | char *program; | |||
361 | ||||
362 | void | |||
363 | fail(char *format, ...) | |||
364 | { | |||
365 | int error; | |||
366 | va_list ap; | |||
367 | ||||
368 | #ifdef USE_REENTRANT_LIBC | |||
369 | R_STRERROR_INIT_R(); | |||
370 | #endif | |||
371 | ||||
372 | error = errno(*__errno_location ()); | |||
373 | fprintf(stderrstderr, "%s: ", program); | |||
374 | va_start(ap, format)__builtin_va_start(ap, format); | |||
375 | vfprintf(stderrstderr, format, ap); | |||
376 | va_end(ap)__builtin_va_end(ap); | |||
377 | if (error) | |||
378 | ||||
379 | #ifdef USE_REENTRANT_LIBC | |||
380 | R_STRERROR_R(errno(*__errno_location ())); | |||
381 | fprintf(stderrstderr, ": %s", r_strerror_r); | |||
382 | #else | |||
383 | fprintf(stderrstderr, ": %s", strerror(errno(*__errno_location ()))); | |||
384 | #endif | |||
385 | ||||
386 | putc('\n', stderrstderr); | |||
387 | exit(1); | |||
388 | } | |||
389 | ||||
390 | char * | |||
391 | getcomponent(char *path, char *name) | |||
392 | { | |||
393 | if (*path == '\0') { | |||
394 | return 0; | |||
395 | } | |||
396 | if (*path == '/') { | |||
397 | *name++ = '/'; | |||
398 | } else { | |||
399 | do { | |||
400 | *name++ = *path++; | |||
401 | } while (*path != '/' && *path != '\0'); | |||
402 | } | |||
403 | *name = '\0'; | |||
404 | while (*path == '/') { | |||
405 | path++; | |||
406 | } | |||
407 | return path; | |||
408 | } | |||
409 | ||||
410 | char * | |||
411 | ino2name(ino_t ino, char *dir) | |||
412 | { | |||
413 | DIR *dp; | |||
414 | struct dirent *ep; | |||
415 | char *name; | |||
416 | ||||
417 | dp = opendir(".."); | |||
418 | if (!dp) { | |||
419 | fail("cannot read parent directory"); | |||
420 | } | |||
421 | for (;;) { | |||
422 | if (!(ep = readdir(dp))) { | |||
423 | fail("cannot find current directory"); | |||
424 | } | |||
425 | if (ep->d_ino == ino) { | |||
| ||||
426 | break; | |||
427 | } | |||
428 | } | |||
429 | name = xstrdup(ep->d_name); | |||
430 | closedir(dp); | |||
431 | return name; | |||
432 | } | |||
433 | ||||
434 | void * | |||
435 | xmalloc(size_t size) | |||
436 | { | |||
437 | void *p = malloc(size); | |||
438 | if (!p) { | |||
439 | fail("cannot allocate %u bytes", size); | |||
440 | } | |||
441 | return p; | |||
442 | } | |||
443 | ||||
444 | char * | |||
445 | xstrdup(char *s) | |||
446 | { | |||
447 | return strcpy((char*)xmalloc(strlen(s) + 1), s); | |||
448 | } | |||
449 | ||||
450 | char * | |||
451 | xbasename(char *path) | |||
452 | { | |||
453 | char *cp; | |||
454 | ||||
455 | while ((cp = strrchr(path, '/')) && cp[1] == '\0') { | |||
456 | *cp = '\0'; | |||
457 | } | |||
458 | if (!cp) { | |||
459 | return path; | |||
460 | } | |||
461 | return cp + 1; | |||
462 | } | |||
463 | ||||
464 | void | |||
465 | xchdir(char *dir) | |||
466 | { | |||
467 | if (chdir(dir) < 0) { | |||
468 | fail("cannot change directory to %s", dir); | |||
469 | } | |||
470 | } | |||
471 | ||||
472 | int | |||
473 | relatepaths(char *from, char *to, char *outpath) | |||
474 | { | |||
475 | char *cp, *cp2; | |||
476 | int len; | |||
477 | char buf[NAME_MAX256]; | |||
478 | ||||
479 | assert(*from == '/' && *to == '/')((void) sizeof ((*from == '/' && *to == '/') ? 1 : 0) , __extension__ ({ if (*from == '/' && *to == '/') ; else __assert_fail ("*from == '/' && *to == '/'", "../../config/nsinstall.c" , 479, __extension__ __PRETTY_FUNCTION__); })); | |||
480 | for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) | |||
481 | if (*cp == '\0') { | |||
482 | break; | |||
483 | } | |||
484 | while (cp[-1] != '/') { | |||
485 | cp--, cp2--; | |||
486 | } | |||
487 | if (cp - 1 == to) { | |||
488 | /* closest common ancestor is /, so use full pathname */ | |||
489 | len = strlen(strcpy(outpath, to)); | |||
490 | if (outpath[len] != '/') { | |||
491 | outpath[len++] = '/'; | |||
492 | outpath[len] = '\0'; | |||
493 | } | |||
494 | } else { | |||
495 | len = 0; | |||
496 | while ((cp2 = getcomponent(cp2, buf)) != 0) { | |||
497 | strcpy(outpath + len, "../"); | |||
498 | len += 3; | |||
499 | } | |||
500 | while ((cp = getcomponent(cp, buf)) != 0) { | |||
501 | sprintf(outpath + len, "%s/", buf); | |||
502 | len += strlen(outpath + len); | |||
503 | } | |||
504 | } | |||
505 | return len; | |||
506 | } | |||
507 | ||||
508 | void | |||
509 | reversepath(char *inpath, char *name, int len, char *outpath) | |||
510 | { | |||
511 | char *cp, *cp2; | |||
512 | char buf[NAME_MAX256]; | |||
513 | struct stat sb; | |||
514 | ||||
515 | cp = strcpy(outpath + PATH_MAX4096 - (len + 1), name); | |||
516 | cp2 = inpath; | |||
517 | while ((cp2 = getcomponent(cp2, buf)) != 0) { | |||
| ||||
518 | if (strcmp(buf, ".") == 0) { | |||
519 | continue; | |||
520 | } | |||
521 | if (strcmp(buf, "..") == 0) { | |||
522 | if (stat(".", &sb) < 0) { | |||
523 | fail("cannot stat current directory"); | |||
524 | } | |||
525 | name = ino2name(sb.st_ino, ".."); | |||
526 | len = strlen(name); | |||
527 | cp -= len + 1; | |||
528 | strcpy(cp, name); | |||
529 | cp[len] = '/'; | |||
530 | free(name); | |||
531 | xchdir(".."); | |||
532 | } else { | |||
533 | cp -= 3; | |||
534 | memcpy(cp, "../", 3); | |||
535 | xchdir(buf); | |||
536 | } | |||
537 | } | |||
538 | strcpy(outpath, cp); | |||
539 | } |