1106491Sobrien/*
2228990Suqs * FreeBSD install - a package for the installation and maintenance
3106491Sobrien * of non-core utilities.
4106491Sobrien *
5106491Sobrien * Redistribution and use in source and binary forms, with or without
6106491Sobrien * modification, are permitted provided that the following conditions
7106491Sobrien * are met:
8106491Sobrien * 1. Redistributions of source code must retain the above copyright
9106491Sobrien *    notice, this list of conditions and the following disclaimer.
10106491Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11106491Sobrien *    notice, this list of conditions and the following disclaimer in the
12106491Sobrien *    documentation and/or other materials provided with the distribution.
13106491Sobrien *
14106491Sobrien * Jordan K. Hubbard
15106491Sobrien * 18 July 1993
16106491Sobrien *
17106491Sobrien * URL file access utilities.
18106491Sobrien *
19106491Sobrien */
20106491Sobrien
21106491Sobrien#include <sys/cdefs.h>
22106491Sobrien__FBSDID("$FreeBSD$");
23106491Sobrien
24106491Sobrien#include "lib.h"
25106491Sobrien#include <err.h>
26106491Sobrien#include <fetch.h>
27154145Sflz#include <libgen.h>
28106491Sobrien#include <sys/wait.h>
29154145Sflz#include <stdio.h>
30106491Sobrien
31106491Sobrien/*
32106491Sobrien * Try and fetch a file by URL, returning the directory name for where
33106491Sobrien * it's unpacked, if successful.
34106491Sobrien */
35194497Sbrianconst char *
36154145SflzfileGetURL(const char *base, const char *spec, int keep_package)
37106491Sobrien{
38194497Sbrian    const char *rp;
39194497Sbrian    char *cp, *tmp;
40106491Sobrien    char fname[FILENAME_MAX];
41106491Sobrien    char pen[FILENAME_MAX];
42154145Sflz    char pkg[FILENAME_MAX];
43106491Sobrien    char buf[8192];
44106491Sobrien    FILE *ftp;
45106491Sobrien    pid_t tpid;
46131285Seik    int pfd[2], pstat, r, w = 0;
47106491Sobrien    char *hint;
48154145Sflz    int fd, pkgfd = 0;
49106491Sobrien
50106491Sobrien    rp = NULL;
51106491Sobrien    /* Special tip that sysinstall left for us */
52106491Sobrien    hint = getenv("PKG_ADD_BASE");
53106491Sobrien    if (!isURL(spec)) {
54106491Sobrien	if (!base && !hint)
55106491Sobrien	    return NULL;
56106491Sobrien	/*
57106491Sobrien	 * We've been given an existing URL (that's known-good) and now we need
58106491Sobrien	 * to construct a composite one out of that and the basename we were
59106491Sobrien	 * handed as a dependency.
60106491Sobrien	 */
61106491Sobrien	if (base) {
62106491Sobrien	    strcpy(fname, base);
63106491Sobrien	    /*
64106491Sobrien	     * Advance back two slashes to get to the root of the package
65106491Sobrien	     * hierarchy
66106491Sobrien	     */
67106491Sobrien	    cp = strrchr(fname, '/');
68106491Sobrien	    if (cp) {
69106491Sobrien		*cp = '\0';	/* chop name */
70106491Sobrien		cp = strrchr(fname, '/');
71106491Sobrien	    }
72106491Sobrien	    if (cp) {
73106491Sobrien		*(cp + 1) = '\0';
74106491Sobrien		strcat(cp, "All/");
75106491Sobrien		strcat(cp, spec);
76236333Sjpaetzel		if (getenv("PACKAGESUFFIX"))
77236333Sjpaetzel		   strcat(cp, getenv("PACKAGESUFFIX"));
78236333Sjpaetzel                else
79236333Sjpaetzel		   strcat(cp, ".tbz");
80106491Sobrien	    }
81106491Sobrien	    else
82106491Sobrien		return NULL;
83106491Sobrien	}
84106491Sobrien	else {
85106491Sobrien	    /*
86106491Sobrien	     * Otherwise, we've been given an environment variable hinting
87106491Sobrien	     * at the right location from sysinstall
88106491Sobrien	     */
89106491Sobrien	    strcpy(fname, hint);
90106491Sobrien	    strcat(fname, spec);
91236333Sjpaetzel	    if (getenv("PACKAGESUFFIX"))
92236333Sjpaetzel	       strcat(fname, getenv("PACKAGESUFFIX"));
93236333Sjpaetzel            else
94236333Sjpaetzel	       strcat(fname, ".tbz");
95106491Sobrien	}
96106491Sobrien    }
97106491Sobrien    else
98106491Sobrien	strcpy(fname, spec);
99106491Sobrien
100161212Sdes    if (keep_package) {
101167972Snjl	tmp = getenv("PKGDIR");
102154145Sflz	strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg));
103154145Sflz	tmp = basename(fname);
104154145Sflz	strlcat(pkg, "/", sizeof(pkg));
105154145Sflz	strlcat(pkg, tmp, sizeof(pkg));
106167972Snjl	if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
107167972Snjl	    printf("Error: Unable to open %s\n", pkg);
108154145Sflz	    perror("open");
109154145Sflz	    return NULL;
110154145Sflz	}
111161212Sdes    }
112154145Sflz
113160178Sdes    fetchDebug = (Verbose > 0);
114113587Srwatson    if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) {
115195212Sbrian	printf("Error: Unable to get %s: %s\n",
116106491Sobrien	       fname, fetchLastErrString);
117206043Sflz	/* If the fetch fails, yank the package. */
118206043Sflz	if (keep_package && unlink(pkg) < 0 && Verbose) {
119206043Sflz	    warnx("failed to remove partially fetched package: %s", pkg);
120206043Sflz	}
121106491Sobrien	return NULL;
122106491Sobrien    }
123106491Sobrien
124106491Sobrien    if (isatty(0) || Verbose)
125106491Sobrien	printf("Fetching %s...", fname), fflush(stdout);
126106491Sobrien    pen[0] = '\0';
127106491Sobrien    if ((rp = make_playpen(pen, 0)) == NULL) {
128106491Sobrien	printf("Error: Unable to construct a new playpen for FTP!\n");
129106491Sobrien	fclose(ftp);
130106491Sobrien	return NULL;
131106491Sobrien    }
132106491Sobrien    if (pipe(pfd) == -1) {
133106491Sobrien	warn("pipe()");
134106491Sobrien	cleanup(0);
135106491Sobrien	exit(2);
136106491Sobrien    }
137106491Sobrien    if ((tpid = fork()) == -1) {
138106491Sobrien	warn("pipe()");
139106491Sobrien	cleanup(0);
140106491Sobrien	exit(2);
141106491Sobrien    }
142106491Sobrien    if (!tpid) {
143106491Sobrien	dup2(pfd[0], 0);
144106491Sobrien	for (fd = getdtablesize() - 1; fd >= 3; --fd)
145106491Sobrien	    close(fd);
146131285Seik	execl("/usr/bin/tar", "tar",
147167270Sru	    Verbose ? "-xpjvf" : "-xpjf",
148131285Seik	    "-", (char *)0);
149106491Sobrien	_exit(2);
150106491Sobrien    }
151106491Sobrien    close(pfd[0]);
152106491Sobrien    for (;;) {
153106491Sobrien	if ((r = fread(buf, 1, sizeof buf, ftp)) < 1)
154106491Sobrien	    break;
155106491Sobrien	if ((w = write(pfd[1], buf, r)) != r)
156106491Sobrien	    break;
157154145Sflz	if (keep_package) {
158154145Sflz	    if ((w = write(pkgfd, buf, r)) != r)
159154145Sflz		break;
160154145Sflz	}
161106491Sobrien    }
162106491Sobrien    if (ferror(ftp))
163106491Sobrien	warn("warning: error reading from server");
164106491Sobrien    fclose(ftp);
165154145Sflz    if (keep_package) {
166154145Sflz	close(pkgfd);
167154145Sflz    }
168106491Sobrien    close(pfd[1]);
169106491Sobrien    if (w == -1)
170106491Sobrien	warn("warning: error writing to tar");
171106491Sobrien    tpid = waitpid(tpid, &pstat, 0);
172106491Sobrien    if (Verbose)
173106491Sobrien	printf("tar command returns %d status\n", WEXITSTATUS(pstat));
174106491Sobrien    if (rp && (isatty(0) || Verbose))
175106491Sobrien	printf(" Done.\n");
176106491Sobrien    return rp;
177106491Sobrien}
178