]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - usr.sbin/pkg_install/lib/url.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / usr.sbin / pkg_install / lib / url.c
1 /*
2  * FreeBSD install - a package for the installation and maintainance
3  * of non-core utilities.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * Jordan K. Hubbard
15  * 18 July 1993
16  *
17  * URL file access utilities.
18  *
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include "lib.h"
25 #include <err.h>
26 #include <fetch.h>
27 #include <libgen.h>
28 #include <sys/wait.h>
29 #include <stdio.h>
30
31 /*
32  * Try and fetch a file by URL, returning the directory name for where
33  * it's unpacked, if successful.
34  */
35 const char *
36 fileGetURL(const char *base, const char *spec, int keep_package)
37 {
38     const char *rp;
39     char *cp, *tmp;
40     char fname[FILENAME_MAX];
41     char pen[FILENAME_MAX];
42     char pkg[FILENAME_MAX];
43     char buf[8192];
44     FILE *ftp;
45     pid_t tpid;
46     int pfd[2], pstat, r, w = 0;
47     char *hint;
48     int fd, pkgfd = 0;
49
50     rp = NULL;
51     /* Special tip that sysinstall left for us */
52     hint = getenv("PKG_ADD_BASE");
53     if (!isURL(spec)) {
54         if (!base && !hint)
55             return NULL;
56         /*
57          * We've been given an existing URL (that's known-good) and now we need
58          * to construct a composite one out of that and the basename we were
59          * handed as a dependency.
60          */
61         if (base) {
62             strcpy(fname, base);
63             /*
64              * Advance back two slashes to get to the root of the package
65              * hierarchy
66              */
67             cp = strrchr(fname, '/');
68             if (cp) {
69                 *cp = '\0';     /* chop name */
70                 cp = strrchr(fname, '/');
71             }
72             if (cp) {
73                 *(cp + 1) = '\0';
74                 strcat(cp, "All/");
75                 strcat(cp, spec);
76                 strcat(cp, ".tbz");
77             }
78             else
79                 return NULL;
80         }
81         else {
82             /*
83              * Otherwise, we've been given an environment variable hinting
84              * at the right location from sysinstall
85              */
86             strcpy(fname, hint);
87             strcat(fname, spec);
88             strcat(fname, ".tbz");
89         }
90     }
91     else
92         strcpy(fname, spec);
93
94     if (keep_package) {
95         tmp = getenv("PKGDIR");
96         strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg));
97         tmp = basename(fname);
98         strlcat(pkg, "/", sizeof(pkg));
99         strlcat(pkg, tmp, sizeof(pkg));
100         if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
101             printf("Error: Unable to open %s\n", pkg);
102             perror("open");
103             return NULL;
104         }
105     }
106
107     fetchDebug = (Verbose > 0);
108     if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) {
109         printf("Error: Unable to get %s: %s\n",
110                fname, fetchLastErrString);
111         /* If the fetch fails, yank the package. */
112         if (keep_package && unlink(pkg) < 0 && Verbose) {
113             warnx("failed to remove partially fetched package: %s", pkg);
114         }
115         return NULL;
116     }
117
118     if (isatty(0) || Verbose)
119         printf("Fetching %s...", fname), fflush(stdout);
120     pen[0] = '\0';
121     if ((rp = make_playpen(pen, 0)) == NULL) {
122         printf("Error: Unable to construct a new playpen for FTP!\n");
123         fclose(ftp);
124         return NULL;
125     }
126     if (pipe(pfd) == -1) {
127         warn("pipe()");
128         cleanup(0);
129         exit(2);
130     }
131     if ((tpid = fork()) == -1) {
132         warn("pipe()");
133         cleanup(0);
134         exit(2);
135     }
136     if (!tpid) {
137         dup2(pfd[0], 0);
138         for (fd = getdtablesize() - 1; fd >= 3; --fd)
139             close(fd);
140         execl("/usr/bin/tar", "tar",
141             Verbose ? "-xpjvf" : "-xpjf",
142             "-", (char *)0);
143         _exit(2);
144     }
145     close(pfd[0]);
146     for (;;) {
147         if ((r = fread(buf, 1, sizeof buf, ftp)) < 1)
148             break;
149         if ((w = write(pfd[1], buf, r)) != r)
150             break;
151         if (keep_package) {
152             if ((w = write(pkgfd, buf, r)) != r)
153                 break;
154         }    
155     }
156     if (ferror(ftp))
157         warn("warning: error reading from server");
158     fclose(ftp);
159     if (keep_package) {
160         close(pkgfd);
161     } 
162     close(pfd[1]);
163     if (w == -1)
164         warn("warning: error writing to tar");
165     tpid = waitpid(tpid, &pstat, 0);
166     if (Verbose)
167         printf("tar command returns %d status\n", WEXITSTATUS(pstat));
168     if (rp && (isatty(0) || Verbose))
169         printf(" Done.\n");
170     return rp;
171 }