url.c revision 167972
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: head/usr.sbin/pkg_install/lib/url.c 167972 2007-03-28 05:33:52Z njl $");
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 */
35char *
36fileGetURL(const char *base, const char *spec, int keep_package)
37{
38    char *cp, *rp, *tmp;
39    char fname[FILENAME_MAX];
40    char pen[FILENAME_MAX];
41    char pkg[FILENAME_MAX];
42    char buf[8192];
43    FILE *ftp;
44    pid_t tpid;
45    int pfd[2], pstat, r, w = 0;
46    char *hint;
47    int fd, pkgfd = 0;
48
49    rp = NULL;
50    /* Special tip that sysinstall left for us */
51    hint = getenv("PKG_ADD_BASE");
52    if (!isURL(spec)) {
53	if (!base && !hint)
54	    return NULL;
55	/*
56	 * We've been given an existing URL (that's known-good) and now we need
57	 * to construct a composite one out of that and the basename we were
58	 * handed as a dependency.
59	 */
60	if (base) {
61	    strcpy(fname, base);
62	    /*
63	     * Advance back two slashes to get to the root of the package
64	     * hierarchy
65	     */
66	    cp = strrchr(fname, '/');
67	    if (cp) {
68		*cp = '\0';	/* chop name */
69		cp = strrchr(fname, '/');
70	    }
71	    if (cp) {
72		*(cp + 1) = '\0';
73		strcat(cp, "All/");
74		strcat(cp, spec);
75#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039
76		strcat(cp, ".tbz");
77#else
78		strcat(cp, ".tgz");
79#endif
80	    }
81	    else
82		return NULL;
83	}
84	else {
85	    /*
86	     * Otherwise, we've been given an environment variable hinting
87	     * at the right location from sysinstall
88	     */
89	    strcpy(fname, hint);
90	    strcat(fname, spec);
91#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039
92	    strcat(fname, ".tbz");
93#else
94	    strcat(fname, ".tgz");
95#endif
96	}
97    }
98    else
99	strcpy(fname, spec);
100
101    if (keep_package) {
102	tmp = getenv("PKGDIR");
103	strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg));
104	tmp = basename(fname);
105	strlcat(pkg, "/", sizeof(pkg));
106	strlcat(pkg, tmp, sizeof(pkg));
107	if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
108	    printf("Error: Unable to open %s\n", pkg);
109	    perror("open");
110	    return NULL;
111	}
112    }
113
114    fetchDebug = (Verbose > 0);
115    if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) {
116	printf("Error: FTP Unable to get %s: %s\n",
117	       fname, fetchLastErrString);
118	return NULL;
119    }
120
121    if (isatty(0) || Verbose)
122	printf("Fetching %s...", fname), fflush(stdout);
123    pen[0] = '\0';
124    if ((rp = make_playpen(pen, 0)) == NULL) {
125	printf("Error: Unable to construct a new playpen for FTP!\n");
126	fclose(ftp);
127	return NULL;
128    }
129    if (pipe(pfd) == -1) {
130	warn("pipe()");
131	cleanup(0);
132	exit(2);
133    }
134    if ((tpid = fork()) == -1) {
135	warn("pipe()");
136	cleanup(0);
137	exit(2);
138    }
139    if (!tpid) {
140	dup2(pfd[0], 0);
141	for (fd = getdtablesize() - 1; fd >= 3; --fd)
142	    close(fd);
143	execl("/usr/bin/tar", "tar",
144#if defined(__FreeBSD_version) && __FreeBSD_version >= 500039
145	    Verbose ? "-xpjvf" : "-xpjf",
146#else
147	    Verbose ? "-xpzvf" : "-xpzf",
148#endif
149	    "-", (char *)0);
150	_exit(2);
151    }
152    close(pfd[0]);
153    for (;;) {
154	if ((r = fread(buf, 1, sizeof buf, ftp)) < 1)
155	    break;
156	if ((w = write(pfd[1], buf, r)) != r)
157	    break;
158	if (keep_package) {
159	    if ((w = write(pkgfd, buf, r)) != r)
160		break;
161	}
162    }
163    if (ferror(ftp))
164	warn("warning: error reading from server");
165    fclose(ftp);
166    if (keep_package) {
167	close(pkgfd);
168    }
169    close(pfd[1]);
170    if (w == -1)
171	warn("warning: error writing to tar");
172    tpid = waitpid(tpid, &pstat, 0);
173    if (Verbose)
174	printf("tar command returns %d status\n", WEXITSTATUS(pstat));
175    if (rp && (isatty(0) || Verbose))
176	printf(" Done.\n");
177    return rp;
178}
179