package.c revision 95825
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 * $FreeBSD: head/usr.sbin/sysinstall/package.c 95825 2002-04-30 22:40:06Z obrien $ 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; 45 46static void 47catch_pipe(int sig) 48{ 49 sigpipe_caught = TRUE; 50} 51 52extern PkgNode Top; 53 54/* Like package_extract, but assumes current media device and chases deps */ 55int 56package_add(char *name) 57{ 58 PkgNodePtr tmp; 59 int i; 60 61 if (!mediaVerify()) 62 return DITEM_FAILURE; 63 64 if (!DEVICE_INIT(mediaDevice)) 65 return DITEM_FAILURE; 66 67 i = index_initialize("packages/INDEX"); 68 if (DITEM_STATUS(i) != DITEM_SUCCESS) 69 return i; 70 71 tmp = index_search(&Top, name, &tmp); 72 if (tmp) 73 return index_extract(mediaDevice, &Top, tmp, FALSE); 74 else { 75 msgConfirm("Sorry, package %s was not found in the INDEX.", name); 76 return DITEM_FAILURE; 77 } 78} 79 80/* For use by dispatch */ 81int 82packageAdd(dialogMenuItem *self) 83{ 84 char *cp; 85 86 cp = variable_get(VAR_PACKAGE); 87 if (!cp) { 88 msgDebug("packageAdd: No package name passed in package variable\n"); 89 return DITEM_FAILURE; 90 } 91 else 92 return package_add(cp); 93} 94 95Boolean 96package_exists(char *name) 97{ 98 char fname[FILENAME_MAX]; 99 int status /* = vsystem("pkg_info -e %s", name) */; 100 101 /* XXX KLUDGE ALERT! This makes evil assumptions about how XXX 102 * packages register themselves and should *really be done with 103 * `pkg_info -e <name>' except that this it's too slow for an 104 * item check routine.. :-( 105 */ 106 snprintf(fname, FILENAME_MAX, "/var/db/pkg/%s", name); 107 status = access(fname, R_OK); 108 if (isDebug()) 109 msgDebug("package check for %s returns %s.\n", name, status ? "failure" : "success"); 110 return !status; 111} 112 113/* Extract a package based on a namespec and a media device */ 114int 115package_extract(Device *dev, char *name, Boolean depended) 116{ 117 char path[MAXPATHLEN]; 118 const char *PkgExts[] = { "", ".tbz", ".tbz2", ".tgz" }; 119 int ext, last_msg, pathend, ret; 120 FILE *fp; 121 122 last_msg = 0; 123 124 /* Check to make sure it's not already there */ 125 if (package_exists(name)) 126 return DITEM_SUCCESS; 127 128 if (!DEVICE_INIT(dev)) { 129 msgConfirm("Unable to initialize media type for package extract."); 130 return DITEM_FAILURE; 131 } 132 133 /* If necessary, initialize the ldconfig hints */ 134 if (!file_readable("/var/run/ld-elf.so.hints")) 135 vsystem("ldconfig /usr/lib /usr/lib/compat /usr/local/lib /usr/X11R6/lib"); 136 if (!file_readable("/var/run/ld.so.hints")) 137 vsystem("ldconfig -aout /usr/lib/aout /usr/lib/compat/aout /usr/local/lib/aout /usr/X11R6/lib/aout"); 138 139 /* Be initially optimistic */ 140 ret = DITEM_SUCCESS; 141 /* Make a couple of paranoid locations for temp files to live if user specified none */ 142 if (!variable_get(VAR_PKG_TMPDIR)) { 143 /* Set it to a location with as much space as possible */ 144 variable_set2(VAR_PKG_TMPDIR, "/var/tmp", 0); 145 } 146 Mkdir(variable_get(VAR_PKG_TMPDIR)); 147 vsystem("chmod 1777 %s", variable_get(VAR_PKG_TMPDIR)); 148 149 if (!index(name, '/')) { 150 if (!strpbrk(name, "-_")) 151 pathend = snprintf(path, sizeof path, "packages/Latest/%s", name); 152 else 153 pathend = snprintf(path, sizeof path, "packages/All/%s", name); 154 } 155 else 156 pathend = snprintf(path, sizeof path, "%s", name); 157 158 /* We have a path, call the device strategy routine to get the file */ 159 for (ext = 0 ; ext < sizeof PkgExts / sizeof PkgExts[0]; ++ext) { 160 strlcpy(path + pathend, PkgExts[ext], sizeof path - pathend); 161 if ((fp = DEVICE_GET(dev, path, TRUE))) 162 break; 163 } 164 165 if (fp) { 166 int i = 0, tot, pfd[2]; 167 pid_t pid; 168 WINDOW *w = savescr(); 169 170 sigpipe_caught = FALSE; 171 signal(SIGPIPE, catch_pipe); 172 173 dialog_clear_norefresh(); 174 msgNotify("Adding %s%s\nfrom %s", path, depended ? " (as a dependency)" : "", dev->name); 175 pipe(pfd); 176 pid = fork(); 177 if (!pid) { 178 dup2(pfd[0], 0); close(pfd[0]); 179 dup2(DebugFD, 1); dup2(1, 2); 180 close(pfd[1]); 181 182 /* Prevent pkg_add from wanting to interact in bad ways */ 183 setenv("PACKAGE_BUILDING", "t", 1); 184 setenv("BATCH", "t", 1); 185 186 if (isDebug()) 187 i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-v", "-", 188 (char *)0); 189 else 190 i = execl("/usr/sbin/pkg_add", "/usr/sbin/pkg_add", "-", 191 (char *)0); 192 } 193 else { 194 char buf[BUFSIZ]; 195 struct timeval start, stop; 196 197 close(pfd[0]); 198 tot = 0; 199 (void)gettimeofday(&start, (struct timezone *)0); 200 201 while (!sigpipe_caught && (i = fread(buf, 1, BUFSIZ, fp)) > 0) { 202 int seconds; 203 204 tot += i; 205 /* Print statistics about how we're doing */ 206 (void) gettimeofday(&stop, (struct timezone *)0); 207 stop.tv_sec = stop.tv_sec - start.tv_sec; 208 stop.tv_usec = stop.tv_usec - start.tv_usec; 209 if (stop.tv_usec < 0) 210 stop.tv_sec--, stop.tv_usec += 1000000; 211 seconds = stop.tv_sec + (stop.tv_usec / 1000000.0); 212 if (!seconds) 213 seconds = 1; 214 if (seconds != last_msg) { 215 last_msg = seconds; 216 msgInfo("%10d bytes read from package %s @ %4.1f KBytes/second", tot, name, (tot / seconds) / 1000.0); 217 } 218 /* Write it out */ 219 if (sigpipe_caught || write(pfd[1], buf, i) != i) { 220 msgInfo("Write failure to pkg_add! Package may be corrupt."); 221 break; 222 } 223 } 224 close(pfd[1]); 225 fclose(fp); 226 if (sigpipe_caught) 227 msgInfo("pkg_add(1) apparently did not like the %s package.", name); 228 else if (i == -1) 229 msgInfo("I/O error while reading in the %s package.", name); 230 else 231 msgInfo("Package %s read successfully - waiting for pkg_add(1)", name); 232 refresh(); 233 i = waitpid(pid, &tot, 0); 234 dialog_clear_norefresh(); 235 if (sigpipe_caught || i < 0 || WEXITSTATUS(tot)) { 236 ret = DITEM_FAILURE; 237 if (variable_get(VAR_NO_CONFIRM)) 238 msgNotify("Add of package %s aborted, error code %d -\n" 239 "Please check the debug screen for more info.", name, WEXITSTATUS(tot)); 240 else 241 msgConfirm("Add of package %s aborted, error code %d -\n" 242 "Please check the debug screen for more info.", name, WEXITSTATUS(tot)); 243 } 244 else 245 msgNotify("Package %s was added successfully", name); 246 247 /* Now catch any stragglers */ 248 while (wait3(&tot, WNOHANG, NULL) > 0); 249 250 sleep(1); 251 restorescr(w); 252 } 253 } 254 else { 255 dialog_clear_norefresh(); 256 if (variable_get(VAR_NO_CONFIRM)) 257 msgNotify("Unable to fetch package %s from selected media.\n" 258 "No package add will be done.", name); 259 else 260 msgConfirm("Unable to fetch package %s from selected media.\n" 261 "No package add will be done.", name); 262 ret = DITEM_FAILURE; 263 } 264 signal(SIGPIPE, SIG_IGN); 265 return ret; 266} 267