package.c revision 29501
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 *
729501Sjkh * $Id: package.c,v 1.62 1997/06/13 17:55:32 jkh Exp $
811499Sjkh *
911499Sjkh * Copyright (c) 1995
1011499Sjkh *	Jordan Hubbard.  All rights reserved.
1111499Sjkh *
1211499Sjkh * Redistribution and use in source and binary forms, with or without
1311499Sjkh * modification, are permitted provided that the following conditions
1411499Sjkh * are met:
1511499Sjkh * 1. Redistributions of source code must retain the above copyright
1611499Sjkh *    notice, this list of conditions and the following disclaimer,
1711499Sjkh *    verbatim and that no modifications are made prior to this
1811499Sjkh *    point in the file.
1911499Sjkh * 2. Redistributions in binary form must reproduce the above copyright
2011499Sjkh *    notice, this list of conditions and the following disclaimer in the
2111499Sjkh *    documentation and/or other materials provided with the distribution.
2211499Sjkh *
2311499Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
2411499Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2511499Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2611499Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
2711499Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2811499Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2911499Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
3011499Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3111499Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3211499Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3311499Sjkh * SUCH DAMAGE.
3411499Sjkh *
3511499Sjkh */
3611499Sjkh
3721243Sjkh#include "sysinstall.h"
3811499Sjkh#include <sys/errno.h>
3915883Sjkh#include <sys/time.h>
4011499Sjkh#include <sys/param.h>
4111499Sjkh#include <sys/mount.h>
4211499Sjkh#include <sys/stat.h>
4311499Sjkh
4424106Sjkhstatic Boolean sigpipe_caught = FALSE;
4524106Sjkh
4624106Sjkhstatic void
4724106Sjkhcatch_pipe(int sig)
4824106Sjkh{
4924106Sjkh    sigpipe_caught = TRUE;
5024106Sjkh}
5124106Sjkh
5211650Sjkh/* Like package_extract, but assumes current media device */
5311650Sjkhint
5411650Sjkhpackage_add(char *name)
5511650Sjkh{
5611650Sjkh    if (!mediaVerify())
5715242Sjkh	return DITEM_FAILURE;
5814738Sjkh    return package_extract(mediaDevice, name, FALSE);
5911650Sjkh}
6011650Sjkh
6126613Sjkh/* For use by dispatch */
6226613Sjkhint
6326613SjkhpackageAdd(dialogMenuItem *self)
6426613Sjkh{
6526613Sjkh    char *cp;
6626613Sjkh
6726613Sjkh    cp = variable_get("package");
6826613Sjkh    if (!cp) {
6926613Sjkh	msgDebug("packageAdd:  No package name passed in package variable\n");
7026613Sjkh	return DITEM_FAILURE;
7126613Sjkh    }
7226613Sjkh    else
7326613Sjkh	return package_add(cp);
7426613Sjkh}
7526613Sjkh
7615788SjkhBoolean
7715788Sjkhpackage_exists(char *name)
7815788Sjkh{
7916688Sjkh    char fname[FILENAME_MAX];
8016688Sjkh    int status /* = vsystem("pkg_info -e %s", name) */;
8115788Sjkh
8216688Sjkh    /* XXX KLUDGE ALERT!  This makes evil assumptions about how XXX
8316688Sjkh     * packages register themselves and should *really be done with
8416688Sjkh     * `pkg_info -e <name>' except that this it's too slow for an
8516688Sjkh     * item check routine.. :-(
8616688Sjkh     */
8716688Sjkh    snprintf(fname, FILENAME_MAX, "/var/db/pkg/%s", name);
8816688Sjkh    status = access(fname, R_OK);
8922102Sjkh    if (isDebug())
9022102Sjkh	msgDebug("package check for %s returns %s.\n", name, status ? "failure" : "success");
9115788Sjkh    return !status;
9215788Sjkh}
9315788Sjkh
9411499Sjkh/* Extract a package based on a namespec and a media device */
9511499Sjkhint
9614738Sjkhpackage_extract(Device *dev, char *name, Boolean depended)
9711499Sjkh{
9811499Sjkh    char path[511];
9929501Sjkh    int ret, last_msg = 0;
10020315Sjkh    FILE *fp;
10111499Sjkh
10219385Sjkh    /* Check to make sure it's not already there */
10319385Sjkh    if (package_exists(name))
10419385Sjkh	return DITEM_SUCCESS;
10519385Sjkh
10612232Sjkh    /* If necessary, initialize the ldconfig hints */
10712232Sjkh    if (!file_readable("/var/run/ld.so.hints"))
10812232Sjkh	vsystem("ldconfig /usr/lib /usr/local/lib /usr/X11R6/lib");
10912232Sjkh
11011553Sjkh    if (!dev->init(dev)) {
11111672Sjkh	msgConfirm("Unable to initialize media type for package extract.");
11215242Sjkh	return DITEM_FAILURE;
11311553Sjkh    }
11411499Sjkh
11514738Sjkh    /* Be initially optimistic */
11615467Sjkh    ret = DITEM_SUCCESS | DITEM_RESTORE;
11712129Sjkh    /* Make a couple of paranoid locations for temp files to live if user specified none */
11812129Sjkh    if (!variable_get("PKG_TMPDIR")) {
11914670Sjkh	/* Set it to a location with as much space as possible */
12014670Sjkh	variable_set2("PKG_TMPDIR", "/usr/tmp");
12112129Sjkh    }
12218734Sjkh    Mkdir(variable_get("PKG_TMPDIR"));
12312129Sjkh
12416823Sjkh    if (!index(name, '/'))
12516823Sjkh	sprintf(path, "packages/All/%s%s", name, strstr(name, ".tgz") ? "" : ".tgz");
12616823Sjkh    else
12716823Sjkh	sprintf(path, "%s%s", name, strstr(name, ".tgz") ? "" : ".tgz");
12820315Sjkh    fp = dev->get(dev, path, TRUE);
12920315Sjkh    if (fp) {
13024106Sjkh	int i = 0, tot, pfd[2];
13114670Sjkh	pid_t pid;
13212184Sjkh
13324106Sjkh	signal(SIGPIPE, catch_pipe);
13414738Sjkh	msgNotify("Adding %s%s\nfrom %s", path, depended ? " (as a dependency)" : "", dev->name);
13514670Sjkh	pipe(pfd);
13614670Sjkh	pid = fork();
13714670Sjkh	if (!pid) {
13814670Sjkh	    dup2(pfd[0], 0); close(pfd[0]);
13914670Sjkh	    dup2(DebugFD, 1);
14023647Sjkh	    close(2);
14114670Sjkh	    close(pfd[1]);
14214670Sjkh	    i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-", 0);
14311499Sjkh	    if (isDebug())
14414670Sjkh		msgDebug("pkg_add returns %d status\n", i);
14511499Sjkh	}
14611672Sjkh	else {
14714670Sjkh	    char buf[BUFSIZ];
14815419Sjkh	    WINDOW *w = savescr();
14915883Sjkh	    struct timeval start, stop;
15014670Sjkh
15115470Sjkh	    close(pfd[0]);
15214670Sjkh	    tot = 0;
15315883Sjkh	    (void)gettimeofday(&start, (struct timezone *)0);
15415883Sjkh
15524106Sjkh	    while (!sigpipe_caught && (i = fread(buf, 1, BUFSIZ, fp)) > 0) {
15615883Sjkh		int seconds;
15715242Sjkh
15814670Sjkh		tot += i;
15915883Sjkh		/* Print statistics about how we're doing */
16015883Sjkh		(void) gettimeofday(&stop, (struct timezone *)0);
16115883Sjkh		stop.tv_sec = stop.tv_sec - start.tv_sec;
16215883Sjkh		stop.tv_usec = stop.tv_usec - start.tv_usec;
16315883Sjkh		if (stop.tv_usec < 0)
16415883Sjkh		    stop.tv_sec--, stop.tv_usec += 1000000;
16515883Sjkh		seconds = stop.tv_sec + (stop.tv_usec / 1000000.0);
16615883Sjkh		if (!seconds)
16715883Sjkh		    seconds = 1;
16829501Sjkh		if (seconds != last_msg) {
16929501Sjkh		    last_msg = seconds;
17029501Sjkh		    msgInfo("%10d bytes read from package %s @ %4.1f KBytes/second", tot, name, (tot / seconds) / 1024.0);
17129501Sjkh		}
17215883Sjkh		/* Write it out */
17324106Sjkh		if (sigpipe_caught || write(pfd[1], buf, i) != i) {
17415883Sjkh		    msgInfo("Write failure to pkg_add!  Package may be corrupt.");
17515883Sjkh		    break;
17615883Sjkh		}
17714670Sjkh	    }
17814670Sjkh	    close(pfd[1]);
17920315Sjkh	    fclose(fp);
18024106Sjkh	    if (sigpipe_caught)
18124106Sjkh		msgInfo("pkg_add(1) apparently did not like the %s package.", name);
18224106Sjkh	    else if (i == -1)
18324106Sjkh		msgInfo("I/O error while reading in the %s package.", name);
18415942Sjkh	    else
18524106Sjkh		msgInfo("Package %s read successfully - waiting for pkg_add(1)", name);
18614738Sjkh	    refresh();
18714670Sjkh	    i = waitpid(pid, &tot, 0);
18824106Sjkh	    if (sigpipe_caught || i < 0 || WEXITSTATUS(tot)) {
18915942Sjkh		if (variable_get(VAR_NO_CONFIRM))
19022721Sjkh		    msgNotify("Add of package %s aborted, error code %d -\n"
19122721Sjkh			      "Please check the debug screen for more info.", name, WEXITSTATUS(tot));
19215942Sjkh		else
19322721Sjkh		    msgConfirm("Add of package %s aborted, error code %d -\n"
19423647Sjkh			       "Please check the debug screen for more info.", name, WEXITSTATUS(tot));
19514670Sjkh	    }
19614670Sjkh	    else
19714670Sjkh		msgNotify("Package %s was added successfully", name);
19818706Sjkh
19918706Sjkh	    /* Now catch any stragglers */
20018890Sjkh	    while (wait3(&tot, WNOHANG, NULL) > 0);
20118706Sjkh
20215419Sjkh	    sleep(1);
20315419Sjkh	    restorescr(w);
20424106Sjkh	    sigpipe_caught = FALSE;
20511672Sjkh	}
20611499Sjkh    }
20711672Sjkh    else {
20817404Sjkh	dialog_clear_norefresh();
20911672Sjkh	if (variable_get(VAR_NO_CONFIRM))
21011672Sjkh	    msgNotify("Unable to fetch package %s from selected media.\n"
21111799Sjkh		      "No package add will be done.", name);
21223516Sjkh	else
21311672Sjkh	    msgConfirm("Unable to fetch package %s from selected media.\n"
21411799Sjkh		       "No package add will be done.", name);
21515467Sjkh	ret = DITEM_FAILURE | DITEM_RESTORE;
21611672Sjkh    }
21715419Sjkh    return ret;
21811499Sjkh}
219