package.c revision 54854
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 *
750479Speter * $FreeBSD: head/usr.sbin/sysinstall/package.c 54854 1999-12-20 00:16:10Z jkh $
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
4450780Sjkhstatic Boolean sigpipe_caught;
4524106Sjkh
4624106Sjkhstatic void
4724106Sjkhcatch_pipe(int sig)
4824106Sjkh{
4924106Sjkh    sigpipe_caught = TRUE;
5024106Sjkh}
5124106Sjkh
5247055Sjkhextern PkgNode Top;
5347055Sjkh
5447055Sjkh/* Like package_extract, but assumes current media device and chases deps */
5511650Sjkhint
5611650Sjkhpackage_add(char *name)
5711650Sjkh{
5847184Sjkh    PkgNodePtr tmp, tmp2, *tmp3;
5947055Sjkh    int i;
6047055Sjkh
6111650Sjkh    if (!mediaVerify())
6215242Sjkh	return DITEM_FAILURE;
6350780Sjkh
6450780Sjkh    if (!mediaDevice->init(mediaDevice))
6550780Sjkh	return DITEM_FAILURE;
6650780Sjkh
6747055Sjkh    i = index_initialize("packages/INDEX");
6847055Sjkh    if (DITEM_STATUS(i) != DITEM_SUCCESS)
6947055Sjkh	return i;
7050780Sjkh
7148624Sjkh    tmp3 = strpbrk(name, "-") ? NULL : &tmp2;
7247184Sjkh    tmp = index_search(&Top, name, tmp3);
7347055Sjkh    if (tmp)
7447221Sjkh	return index_extract(mediaDevice, &Top, tmp, FALSE);
7547055Sjkh    else {
7647055Sjkh	msgConfirm("Sorry, package %s was not found in the INDEX.", name);
7754587Sjkh	return DITEM_FAILURE;
7847055Sjkh    }
7911650Sjkh}
8011650Sjkh
8126613Sjkh/* For use by dispatch */
8226613Sjkhint
8326613SjkhpackageAdd(dialogMenuItem *self)
8426613Sjkh{
8526613Sjkh    char *cp;
8626613Sjkh
8729539Spst    cp = variable_get(VAR_PACKAGE);
8826613Sjkh    if (!cp) {
8926613Sjkh	msgDebug("packageAdd:  No package name passed in package variable\n");
9026613Sjkh	return DITEM_FAILURE;
9126613Sjkh    }
9226613Sjkh    else
9326613Sjkh	return package_add(cp);
9426613Sjkh}
9526613Sjkh
9615788SjkhBoolean
9715788Sjkhpackage_exists(char *name)
9815788Sjkh{
9916688Sjkh    char fname[FILENAME_MAX];
10016688Sjkh    int status /* = vsystem("pkg_info -e %s", name) */;
10115788Sjkh
10216688Sjkh    /* XXX KLUDGE ALERT!  This makes evil assumptions about how XXX
10316688Sjkh     * packages register themselves and should *really be done with
10416688Sjkh     * `pkg_info -e <name>' except that this it's too slow for an
10516688Sjkh     * item check routine.. :-(
10616688Sjkh     */
10716688Sjkh    snprintf(fname, FILENAME_MAX, "/var/db/pkg/%s", name);
10816688Sjkh    status = access(fname, R_OK);
10922102Sjkh    if (isDebug())
11022102Sjkh	msgDebug("package check for %s returns %s.\n", name, status ? "failure" : "success");
11115788Sjkh    return !status;
11215788Sjkh}
11315788Sjkh
11411499Sjkh/* Extract a package based on a namespec and a media device */
11511499Sjkhint
11614738Sjkhpackage_extract(Device *dev, char *name, Boolean depended)
11711499Sjkh{
11847047Sjkh    char path[511];
11929501Sjkh    int ret, last_msg = 0;
12020315Sjkh    FILE *fp;
12111499Sjkh
12219385Sjkh    /* Check to make sure it's not already there */
12319385Sjkh    if (package_exists(name))
12419385Sjkh	return DITEM_SUCCESS;
12519385Sjkh
12611553Sjkh    if (!dev->init(dev)) {
12711672Sjkh	msgConfirm("Unable to initialize media type for package extract.");
12815242Sjkh	return DITEM_FAILURE;
12911553Sjkh    }
13011499Sjkh
13147179Sjkh    /* If necessary, initialize the ldconfig hints */
13247179Sjkh    if (!file_readable("/var/run/ld.so.hints"))
13354835Sjkh	vsystem("ldconfig /usr/lib /usr/lib/compat /usr/local/lib /usr/X11R6/lib");
13447179Sjkh
13514738Sjkh    /* Be initially optimistic */
13654587Sjkh    ret = DITEM_SUCCESS;
13712129Sjkh    /* Make a couple of paranoid locations for temp files to live if user specified none */
13830424Sjkh    if (!variable_get(VAR_PKG_TMPDIR)) {
13914670Sjkh	/* Set it to a location with as much space as possible */
14043685Sjkh	variable_set2(VAR_PKG_TMPDIR, "/usr/tmp", 0);
14112129Sjkh    }
14230424Sjkh    Mkdir(variable_get(VAR_PKG_TMPDIR));
14330424Sjkh    vsystem("chmod 1777 %s", variable_get(VAR_PKG_TMPDIR));
14412129Sjkh
14547179Sjkh    if (!index(name, '/')) {
14647179Sjkh	if (!strpbrk(name, "-_"))
14747179Sjkh	    sprintf(path, "packages/Latest/%s.tgz", name);
14847179Sjkh	else
14947179Sjkh	    sprintf(path, "packages/All/%s%s", name, strstr(name, ".tgz") ? "" : ".tgz");
15047179Sjkh    }
15116823Sjkh    else
15216823Sjkh	sprintf(path, "%s%s", name, strstr(name, ".tgz") ? "" : ".tgz");
15347041Sjkh
15447047Sjkh    /* We have a path, call the device strategy routine to get the file */
15520315Sjkh    fp = dev->get(dev, path, TRUE);
15620315Sjkh    if (fp) {
15724106Sjkh	int i = 0, tot, pfd[2];
15814670Sjkh	pid_t pid;
15954722Sjkh	WINDOW *w = savescr();
16012184Sjkh
16147221Sjkh	sigpipe_caught = FALSE;
16224106Sjkh	signal(SIGPIPE, catch_pipe);
16347221Sjkh
16454767Sjkh        dialog_clear_norefresh();
16514738Sjkh	msgNotify("Adding %s%s\nfrom %s", path, depended ? " (as a dependency)" : "", dev->name);
16614670Sjkh	pipe(pfd);
16714670Sjkh	pid = fork();
16814670Sjkh	if (!pid) {
16914670Sjkh	    dup2(pfd[0], 0); close(pfd[0]);
17014670Sjkh	    dup2(DebugFD, 1);
17123647Sjkh	    close(2);
17214670Sjkh	    close(pfd[1]);
17311499Sjkh	    if (isDebug())
17447181Sjkh		i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-v", "-", 0);
17547181Sjkh	    else
17647181Sjkh		i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-", 0);
17711499Sjkh	}
17811672Sjkh	else {
17914670Sjkh	    char buf[BUFSIZ];
18015883Sjkh	    struct timeval start, stop;
18114670Sjkh
18215470Sjkh	    close(pfd[0]);
18314670Sjkh	    tot = 0;
18415883Sjkh	    (void)gettimeofday(&start, (struct timezone *)0);
18515883Sjkh
18624106Sjkh	    while (!sigpipe_caught && (i = fread(buf, 1, BUFSIZ, fp)) > 0) {
18715883Sjkh		int seconds;
18815242Sjkh
18914670Sjkh		tot += i;
19015883Sjkh		/* Print statistics about how we're doing */
19115883Sjkh		(void) gettimeofday(&stop, (struct timezone *)0);
19215883Sjkh		stop.tv_sec = stop.tv_sec - start.tv_sec;
19315883Sjkh		stop.tv_usec = stop.tv_usec - start.tv_usec;
19415883Sjkh		if (stop.tv_usec < 0)
19515883Sjkh		    stop.tv_sec--, stop.tv_usec += 1000000;
19615883Sjkh		seconds = stop.tv_sec + (stop.tv_usec / 1000000.0);
19715883Sjkh		if (!seconds)
19815883Sjkh		    seconds = 1;
19929501Sjkh		if (seconds != last_msg) {
20029501Sjkh		    last_msg = seconds;
20129501Sjkh		    msgInfo("%10d bytes read from package %s @ %4.1f KBytes/second", tot, name, (tot / seconds) / 1024.0);
20229501Sjkh		}
20315883Sjkh		/* Write it out */
20424106Sjkh		if (sigpipe_caught || write(pfd[1], buf, i) != i) {
20515883Sjkh		    msgInfo("Write failure to pkg_add!  Package may be corrupt.");
20615883Sjkh		    break;
20715883Sjkh		}
20814670Sjkh	    }
20914670Sjkh	    close(pfd[1]);
21020315Sjkh	    fclose(fp);
21124106Sjkh	    if (sigpipe_caught)
21224106Sjkh		msgInfo("pkg_add(1) apparently did not like the %s package.", name);
21324106Sjkh	    else if (i == -1)
21424106Sjkh		msgInfo("I/O error while reading in the %s package.", name);
21515942Sjkh	    else
21624106Sjkh		msgInfo("Package %s read successfully - waiting for pkg_add(1)", name);
21714738Sjkh	    refresh();
21814670Sjkh	    i = waitpid(pid, &tot, 0);
21954805Sjkh	    dialog_clear_norefresh();
22024106Sjkh	    if (sigpipe_caught || i < 0 || WEXITSTATUS(tot)) {
22154587Sjkh		ret = DITEM_FAILURE;
22248482Sjkh		if (variable_get(VAR_NO_CONFIRM))
22348482Sjkh		    msgNotify("Add of package %s aborted, error code %d -\n"
22448482Sjkh			       "Please check the debug screen for more info.", name, WEXITSTATUS(tot));
22548482Sjkh		else
22648482Sjkh		    msgConfirm("Add of package %s aborted, error code %d -\n"
22748482Sjkh			       "Please check the debug screen for more info.", name, WEXITSTATUS(tot));
22814670Sjkh	    }
22914670Sjkh	    else
23014670Sjkh		msgNotify("Package %s was added successfully", name);
23118706Sjkh
23218706Sjkh	    /* Now catch any stragglers */
23318890Sjkh	    while (wait3(&tot, WNOHANG, NULL) > 0);
23418706Sjkh
23515419Sjkh	    sleep(1);
23615419Sjkh	    restorescr(w);
23711672Sjkh	}
23811499Sjkh    }
23911672Sjkh    else {
24054805Sjkh	dialog_clear_norefresh();
24148482Sjkh	if (variable_get(VAR_NO_CONFIRM))
24248482Sjkh	    msgNotify("Unable to fetch package %s from selected media.\n"
24348482Sjkh		      "No package add will be done.", name);
24448482Sjkh	else
24548482Sjkh	    msgConfirm("Unable to fetch package %s from selected media.\n"
24648482Sjkh		       "No package add will be done.", name);
24754587Sjkh	ret = DITEM_FAILURE;
24811672Sjkh    }
24947221Sjkh    signal(SIGPIPE, SIG_IGN);
25054854Sjkh    return ret;
25111499Sjkh}
252