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