package.c revision 47041
1/* 2 * The new sysinstall program. 3 * 4 * This is probably the last program in the `sysinstall' line - the next 5 * generation being essentially a complete rewrite. 6 * 7 * $Id: package.c,v 1.68 1999/05/07 20:31:36 jkh Exp $ 8 * 9 * Copyright (c) 1995 10 * Jordan Hubbard. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer, 17 * verbatim and that no modifications are made prior to this 18 * point in the file. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37#include "sysinstall.h" 38#include <sys/errno.h> 39#include <sys/time.h> 40#include <sys/param.h> 41#include <sys/mount.h> 42#include <sys/stat.h> 43 44static Boolean sigpipe_caught = FALSE; 45 46static void 47catch_pipe(int sig) 48{ 49 sigpipe_caught = TRUE; 50} 51 52/* Like package_extract, but assumes current media device */ 53int 54package_add(char *name) 55{ 56 if (!mediaVerify()) 57 return DITEM_FAILURE; 58 return package_extract(mediaDevice, name, FALSE); 59} 60 61/* For use by dispatch */ 62int 63packageAdd(dialogMenuItem *self) 64{ 65 char *cp; 66 67 cp = variable_get(VAR_PACKAGE); 68 if (!cp) { 69 msgDebug("packageAdd: No package name passed in package variable\n"); 70 return DITEM_FAILURE; 71 } 72 else 73 return package_add(cp); 74} 75 76Boolean 77package_exists(char *name) 78{ 79 char fname[FILENAME_MAX]; 80 int status /* = vsystem("pkg_info -e %s", name) */; 81 82 /* If in "Latest" syntax, ignore; can't tell with these */ 83 if (name[0] == '@') 84 return FALSE; 85 86 /* XXX KLUDGE ALERT! This makes evil assumptions about how XXX 87 * packages register themselves and should *really be done with 88 * `pkg_info -e <name>' except that this it's too slow for an 89 * item check routine.. :-( 90 */ 91 snprintf(fname, FILENAME_MAX, "/var/db/pkg/%s", name); 92 status = access(fname, R_OK); 93 if (isDebug()) 94 msgDebug("package check for %s returns %s.\n", name, status ? "failure" : "success"); 95 return !status; 96} 97 98/* Extract a package based on a namespec and a media device */ 99int 100package_extract(Device *dev, char *name, Boolean depended) 101{ 102 char tmp[200], path[511]; 103 int ret, last_msg = 0; 104 FILE *fp; 105 106 /* Check to make sure it's not already there */ 107 if (package_exists(name)) 108 return DITEM_SUCCESS; 109 110 /* If necessary, initialize the ldconfig hints */ 111 if (!file_readable("/var/run/ld.so.hints")) 112 vsystem("ldconfig /usr/lib /usr/local/lib /usr/X11R6/lib"); 113 114 if (!dev->init(dev)) { 115 msgConfirm("Unable to initialize media type for package extract."); 116 return DITEM_FAILURE; 117 } 118 119 /* Be initially optimistic */ 120 ret = DITEM_SUCCESS | DITEM_RESTORE; 121 /* Make a couple of paranoid locations for temp files to live if user specified none */ 122 if (!variable_get(VAR_PKG_TMPDIR)) { 123 /* Set it to a location with as much space as possible */ 124 variable_set2(VAR_PKG_TMPDIR, "/usr/tmp", 0); 125 } 126 Mkdir(variable_get(VAR_PKG_TMPDIR)); 127 vsystem("chmod 1777 %s", variable_get(VAR_PKG_TMPDIR)); 128 129 if (name[0] == '@') { 130 /* @ at the beginning of the package name means "get latest" */ 131 sprintf(path, "packages/Latest/%s.tgz", ++name); 132 } 133 else if (!index(name, '/')) 134 sprintf(path, "packages/All/%s%s", name, strstr(name, ".tgz") ? "" : ".tgz"); 135 else 136 sprintf(path, "%s%s", name, strstr(name, ".tgz") ? "" : ".tgz"); 137 138 /* Set hints for pkg_add */ 139 snprintf(tmp, sizeof tmp, "%s/Packages/All/", dev->name); 140 setenv("PKG_ADD_BASE", tmp, 1); 141 if (isDebug()) 142 msgDebug("Set PKG_ADD_BASE to %s\n", tmp); 143 fp = dev->get(dev, path, TRUE); 144 if (fp) { 145 int i = 0, tot, pfd[2]; 146 pid_t pid; 147 148 signal(SIGPIPE, catch_pipe); 149 msgNotify("Adding %s%s\nfrom %s", path, depended ? " (as a dependency)" : "", dev->name); 150 pipe(pfd); 151 pid = fork(); 152 if (!pid) { 153 dup2(pfd[0], 0); close(pfd[0]); 154 dup2(DebugFD, 1); 155 close(2); 156 close(pfd[1]); 157 i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-", 0); 158 if (isDebug()) 159 msgDebug("pkg_add returns %d status\n", i); 160 } 161 else { 162 char buf[BUFSIZ]; 163 WINDOW *w = savescr(); 164 struct timeval start, stop; 165 166 close(pfd[0]); 167 tot = 0; 168 (void)gettimeofday(&start, (struct timezone *)0); 169 170 while (!sigpipe_caught && (i = fread(buf, 1, BUFSIZ, fp)) > 0) { 171 int seconds; 172 173 tot += i; 174 /* Print statistics about how we're doing */ 175 (void) gettimeofday(&stop, (struct timezone *)0); 176 stop.tv_sec = stop.tv_sec - start.tv_sec; 177 stop.tv_usec = stop.tv_usec - start.tv_usec; 178 if (stop.tv_usec < 0) 179 stop.tv_sec--, stop.tv_usec += 1000000; 180 seconds = stop.tv_sec + (stop.tv_usec / 1000000.0); 181 if (!seconds) 182 seconds = 1; 183 if (seconds != last_msg) { 184 last_msg = seconds; 185 msgInfo("%10d bytes read from package %s @ %4.1f KBytes/second", tot, name, (tot / seconds) / 1024.0); 186 } 187 /* Write it out */ 188 if (sigpipe_caught || write(pfd[1], buf, i) != i) { 189 msgInfo("Write failure to pkg_add! Package may be corrupt."); 190 break; 191 } 192 } 193 close(pfd[1]); 194 fclose(fp); 195 if (sigpipe_caught) 196 msgInfo("pkg_add(1) apparently did not like the %s package.", name); 197 else if (i == -1) 198 msgInfo("I/O error while reading in the %s package.", name); 199 else 200 msgInfo("Package %s read successfully - waiting for pkg_add(1)", name); 201 refresh(); 202 i = waitpid(pid, &tot, 0); 203 if (sigpipe_caught || i < 0 || WEXITSTATUS(tot)) { 204 ret = DITEM_FAILURE | DITEM_RESTORE; 205 if (variable_get(VAR_NO_CONFIRM)) 206 msgNotify("Add of package %s aborted, error code %d -\n" 207 "Please check the debug screen for more info.", name, WEXITSTATUS(tot)); 208 else 209 msgConfirm("Add of package %s aborted, error code %d -\n" 210 "Please check the debug screen for more info.", name, WEXITSTATUS(tot)); 211 } 212 else 213 msgNotify("Package %s was added successfully", name); 214 215 /* Now catch any stragglers */ 216 while (wait3(&tot, WNOHANG, NULL) > 0); 217 218 sleep(1); 219 restorescr(w); 220 sigpipe_caught = FALSE; 221 } 222 } 223 else { 224 dialog_clear_norefresh(); 225 if (variable_get(VAR_NO_CONFIRM)) 226 msgNotify("Unable to fetch package %s from selected media.\n" 227 "No package add will be done.", name); 228 else 229 msgConfirm("Unable to fetch package %s from selected media.\n" 230 "No package add will be done.", name); 231 ret = DITEM_FAILURE | DITEM_RESTORE; 232 } 233 return ret; 234} 235