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