111499Sjkh/*
211499Sjkh * The new sysinstall program.
311499Sjkh *
411499Sjkh * This is probably the last program in the `sysinstall' line - the next
511499Sjkh * generation being essentially a complete rewrite.
611499Sjkh *
711499Sjkh * Copyright (c) 1995
811499Sjkh *	Jordan Hubbard.  All rights reserved.
911499Sjkh *
1011499Sjkh * Redistribution and use in source and binary forms, with or without
1111499Sjkh * modification, are permitted provided that the following conditions
1211499Sjkh * are met:
1311499Sjkh * 1. Redistributions of source code must retain the above copyright
1411499Sjkh *    notice, this list of conditions and the following disclaimer,
1511499Sjkh *    verbatim and that no modifications are made prior to this
1611499Sjkh *    point in the file.
1711499Sjkh * 2. Redistributions in binary form must reproduce the above copyright
1811499Sjkh *    notice, this list of conditions and the following disclaimer in the
1911499Sjkh *    documentation and/or other materials provided with the distribution.
2011499Sjkh *
2111499Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
2211499Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2311499Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2411499Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
2511499Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2611499Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2711499Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
2811499Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2911499Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3011499Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3111499Sjkh * SUCH DAMAGE.
3211499Sjkh *
33124068Sobrien * $FreeBSD$
3411499Sjkh */
3511499Sjkh
3621243Sjkh#include "sysinstall.h"
3711499Sjkh#include <sys/errno.h>
3815883Sjkh#include <sys/time.h>
3911499Sjkh#include <sys/param.h>
4011499Sjkh#include <sys/mount.h>
4111499Sjkh#include <sys/stat.h>
4211499Sjkh
4350780Sjkhstatic Boolean sigpipe_caught;
4424106Sjkh
4524106Sjkhstatic void
4624106Sjkhcatch_pipe(int sig)
4724106Sjkh{
4824106Sjkh    sigpipe_caught = TRUE;
4924106Sjkh}
5024106Sjkh
5147055Sjkhextern PkgNode Top;
5247055Sjkh
5347055Sjkh/* Like package_extract, but assumes current media device and chases deps */
5411650Sjkhint
5511650Sjkhpackage_add(char *name)
5611650Sjkh{
5789775Ssteve    PkgNodePtr tmp;
58184180Skensmith    int i, current, low, high;
5947055Sjkh
6011650Sjkh    if (!mediaVerify())
6115242Sjkh	return DITEM_FAILURE;
6250780Sjkh
6379065Sdd    if (!DEVICE_INIT(mediaDevice))
6450780Sjkh	return DITEM_FAILURE;
6550780Sjkh
6647055Sjkh    i = index_initialize("packages/INDEX");
6747055Sjkh    if (DITEM_STATUS(i) != DITEM_SUCCESS)
6847055Sjkh	return i;
6950780Sjkh
7089775Ssteve    tmp = index_search(&Top, name, &tmp);
71184180Skensmith    if (tmp) {
72184180Skensmith	if (have_volumes) {
73184180Skensmith	    low = low_volume;
74184180Skensmith	    high = high_volume;
75184180Skensmith	} else
76184180Skensmith	    low = high = 0;
77184180Skensmith	for (current = low; current <= high; current++)
78184180Skensmith	    i = index_extract(mediaDevice, &Top, tmp, FALSE, current);
79184180Skensmith	return i;
80184180Skensmith    } else {
8147055Sjkh	msgConfirm("Sorry, package %s was not found in the INDEX.", name);
8254587Sjkh	return DITEM_FAILURE;
8347055Sjkh    }
8411650Sjkh}
8511650Sjkh
8626613Sjkh/* For use by dispatch */
8726613Sjkhint
8826613SjkhpackageAdd(dialogMenuItem *self)
8926613Sjkh{
9026613Sjkh    char *cp;
9126613Sjkh
9229539Spst    cp = variable_get(VAR_PACKAGE);
9326613Sjkh    if (!cp) {
9426613Sjkh	msgDebug("packageAdd:  No package name passed in package variable\n");
9526613Sjkh	return DITEM_FAILURE;
9626613Sjkh    }
9726613Sjkh    else
9826613Sjkh	return package_add(cp);
9926613Sjkh}
10026613Sjkh
10115788SjkhBoolean
102124068Sobrienpackage_installed(char *name)
10315788Sjkh{
10416688Sjkh    char fname[FILENAME_MAX];
10516688Sjkh    int status /* = vsystem("pkg_info -e %s", name) */;
10615788Sjkh
10716688Sjkh    /* XXX KLUDGE ALERT!  This makes evil assumptions about how XXX
10816688Sjkh     * packages register themselves and should *really be done with
109252600Sdteske     * `pkg_info -e <name>' except that this is too slow for an
11016688Sjkh     * item check routine.. :-(
11116688Sjkh     */
11216688Sjkh    snprintf(fname, FILENAME_MAX, "/var/db/pkg/%s", name);
11316688Sjkh    status = access(fname, R_OK);
11422102Sjkh    if (isDebug())
11522102Sjkh	msgDebug("package check for %s returns %s.\n", name, status ? "failure" : "success");
11615788Sjkh    return !status;
11715788Sjkh}
11815788Sjkh
11911499Sjkh/* Extract a package based on a namespec and a media device */
12011499Sjkhint
12114738Sjkhpackage_extract(Device *dev, char *name, Boolean depended)
12211499Sjkh{
12395825Sobrien    char path[MAXPATHLEN];
12495825Sobrien    const char *PkgExts[] = { "", ".tbz", ".tbz2", ".tgz" };
125156123Sjhb    int last_msg, pathend, ret;
126156123Sjhb    size_t ext;
12720315Sjkh    FILE *fp;
12811499Sjkh
12995825Sobrien    last_msg = 0;
13095825Sobrien
13119385Sjkh    /* Check to make sure it's not already there */
132124070Sobrien    if (package_installed(name))
13319385Sjkh	return DITEM_SUCCESS;
13419385Sjkh
13579065Sdd    if (!DEVICE_INIT(dev)) {
13611672Sjkh	msgConfirm("Unable to initialize media type for package extract.");
13715242Sjkh	return DITEM_FAILURE;
13811553Sjkh    }
13911499Sjkh
14047179Sjkh    /* If necessary, initialize the ldconfig hints */
14176521Solgeni    if (!file_readable("/var/run/ld-elf.so.hints"))
142203690Sbrucec	vsystem("ldconfig /usr/lib /usr/lib/compat /usr/local/lib");
14347179Sjkh
14414738Sjkh    /* Be initially optimistic */
14554587Sjkh    ret = DITEM_SUCCESS;
14612129Sjkh    /* Make a couple of paranoid locations for temp files to live if user specified none */
14730424Sjkh    if (!variable_get(VAR_PKG_TMPDIR)) {
14814670Sjkh	/* Set it to a location with as much space as possible */
14993595Sobrien	variable_set2(VAR_PKG_TMPDIR, "/var/tmp", 0);
15012129Sjkh    }
15130424Sjkh    Mkdir(variable_get(VAR_PKG_TMPDIR));
15230424Sjkh    vsystem("chmod 1777 %s", variable_get(VAR_PKG_TMPDIR));
15312129Sjkh
15447179Sjkh    if (!index(name, '/')) {
15547179Sjkh	if (!strpbrk(name, "-_"))
15695825Sobrien	    pathend = snprintf(path, sizeof path, "packages/Latest/%s", name);
15747179Sjkh	else
15895825Sobrien	    pathend = snprintf(path, sizeof path, "packages/All/%s", name);
15947179Sjkh    }
16016823Sjkh    else
16195825Sobrien	pathend = snprintf(path, sizeof path, "%s", name);
16247041Sjkh
16347047Sjkh    /* We have a path, call the device strategy routine to get the file */
16495825Sobrien    for (ext = 0 ; ext < sizeof PkgExts / sizeof PkgExts[0]; ++ext) {
16595825Sobrien	strlcpy(path + pathend, PkgExts[ext], sizeof path - pathend);
16695825Sobrien	if ((fp = DEVICE_GET(dev, path, TRUE)))
16795825Sobrien	    break;
16895825Sobrien    }
16995825Sobrien
17020315Sjkh    if (fp) {
17124106Sjkh	int i = 0, tot, pfd[2];
17214670Sjkh	pid_t pid;
17354722Sjkh	WINDOW *w = savescr();
17412184Sjkh
17547221Sjkh	sigpipe_caught = FALSE;
17624106Sjkh	signal(SIGPIPE, catch_pipe);
17747221Sjkh
17854767Sjkh        dialog_clear_norefresh();
17914738Sjkh	msgNotify("Adding %s%s\nfrom %s", path, depended ? " (as a dependency)" : "", dev->name);
18014670Sjkh	pipe(pfd);
18114670Sjkh	pid = fork();
18214670Sjkh	if (!pid) {
18314670Sjkh	    dup2(pfd[0], 0); close(pfd[0]);
18494051Sobrien	    dup2(DebugFD, 1); dup2(1, 2);
18514670Sjkh	    close(pfd[1]);
18668552Sjkh
18768552Sjkh	    /* Prevent pkg_add from wanting to interact in bad ways */
18868552Sjkh	    setenv("BATCH", "t", 1);
18968552Sjkh
19011499Sjkh	    if (isDebug())
19179452Sbrian		i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-v", "-",
19279452Sbrian		    (char *)0);
19347181Sjkh	    else
19479452Sbrian		i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-",
19579452Sbrian		    (char *)0);
19611499Sjkh	}
19711672Sjkh	else {
19814670Sjkh	    char buf[BUFSIZ];
19915883Sjkh	    struct timeval start, stop;
20014670Sjkh
20115470Sjkh	    close(pfd[0]);
20214670Sjkh	    tot = 0;
20315883Sjkh	    (void)gettimeofday(&start, (struct timezone *)0);
20415883Sjkh
20524106Sjkh	    while (!sigpipe_caught && (i = fread(buf, 1, BUFSIZ, fp)) > 0) {
20615883Sjkh		int seconds;
20715242Sjkh
20814670Sjkh		tot += i;
20915883Sjkh		/* Print statistics about how we're doing */
21015883Sjkh		(void) gettimeofday(&stop, (struct timezone *)0);
21115883Sjkh		stop.tv_sec = stop.tv_sec - start.tv_sec;
21215883Sjkh		stop.tv_usec = stop.tv_usec - start.tv_usec;
21315883Sjkh		if (stop.tv_usec < 0)
21415883Sjkh		    stop.tv_sec--, stop.tv_usec += 1000000;
21515883Sjkh		seconds = stop.tv_sec + (stop.tv_usec / 1000000.0);
21615883Sjkh		if (!seconds)
21715883Sjkh		    seconds = 1;
21829501Sjkh		if (seconds != last_msg) {
21929501Sjkh		    last_msg = seconds;
22075322Sjkh		    msgInfo("%10d bytes read from package %s @ %4.1f KBytes/second", tot, name, (tot / seconds) / 1000.0);
22129501Sjkh		}
22215883Sjkh		/* Write it out */
22324106Sjkh		if (sigpipe_caught || write(pfd[1], buf, i) != i) {
22415883Sjkh		    msgInfo("Write failure to pkg_add!  Package may be corrupt.");
22515883Sjkh		    break;
22615883Sjkh		}
22714670Sjkh	    }
22814670Sjkh	    close(pfd[1]);
22920315Sjkh	    fclose(fp);
23024106Sjkh	    if (sigpipe_caught)
23124106Sjkh		msgInfo("pkg_add(1) apparently did not like the %s package.", name);
23224106Sjkh	    else if (i == -1)
23324106Sjkh		msgInfo("I/O error while reading in the %s package.", name);
23415942Sjkh	    else
23524106Sjkh		msgInfo("Package %s read successfully - waiting for pkg_add(1)", name);
23614738Sjkh	    refresh();
23714670Sjkh	    i = waitpid(pid, &tot, 0);
23854805Sjkh	    dialog_clear_norefresh();
23924106Sjkh	    if (sigpipe_caught || i < 0 || WEXITSTATUS(tot)) {
24054587Sjkh		ret = DITEM_FAILURE;
24148482Sjkh		if (variable_get(VAR_NO_CONFIRM))
24248482Sjkh		    msgNotify("Add of package %s aborted, error code %d -\n"
24348482Sjkh			       "Please check the debug screen for more info.", name, WEXITSTATUS(tot));
24448482Sjkh		else
24548482Sjkh		    msgConfirm("Add of package %s aborted, error code %d -\n"
24648482Sjkh			       "Please check the debug screen for more info.", name, WEXITSTATUS(tot));
24714670Sjkh	    }
24814670Sjkh	    else
24914670Sjkh		msgNotify("Package %s was added successfully", name);
25018706Sjkh
25118706Sjkh	    /* Now catch any stragglers */
25218890Sjkh	    while (wait3(&tot, WNOHANG, NULL) > 0);
25318706Sjkh
25415419Sjkh	    sleep(1);
25515419Sjkh	    restorescr(w);
25611672Sjkh	}
25711499Sjkh    }
25811672Sjkh    else {
25954805Sjkh	dialog_clear_norefresh();
26048482Sjkh	if (variable_get(VAR_NO_CONFIRM))
26148482Sjkh	    msgNotify("Unable to fetch package %s from selected media.\n"
26248482Sjkh		      "No package add will be done.", name);
26348482Sjkh	else
26448482Sjkh	    msgConfirm("Unable to fetch package %s from selected media.\n"
26548482Sjkh		       "No package add will be done.", name);
26654587Sjkh	ret = DITEM_FAILURE;
26711672Sjkh    }
26847221Sjkh    signal(SIGPIPE, SIG_IGN);
26954854Sjkh    return ret;
27011499Sjkh}
271