package.c revision 12129
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.22 1995/10/27 03:07:14 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 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by Jordan Hubbard 25 * for the FreeBSD Project. 26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to 27 * endorse or promote products derived from this software without specific 28 * prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 */ 43 44#include <stdio.h> 45#include <string.h> 46#include <stdlib.h> 47#include <sys/errno.h> 48#include <sys/param.h> 49#include <sys/mount.h> 50#include <sys/stat.h> 51#include "sysinstall.h" 52 53static char *make_playpen(char *pen, size_t sz); 54 55/* Like package_extract, but assumes current media device */ 56int 57package_add(char *name) 58{ 59 if (!mediaVerify()) 60 return RET_FAIL; 61 return package_extract(mediaDevice, name); 62} 63 64/* Extract a package based on a namespec and a media device */ 65int 66package_extract(Device *dev, char *name) 67{ 68 char path[511]; 69 char pen[FILENAME_MAX]; 70 char *where; 71 int fd, ret; 72 73 /* Check to make sure it's not already there */ 74 if (!vsystem("pkg_info -e %s", name)) { 75 msgDebug("package %s marked as already installed - return SUCCESS.\n", name); 76 return RET_SUCCESS; 77 } 78 79 if (!dev->init(dev)) { 80 dialog_clear(); 81 msgConfirm("Unable to initialize media type for package extract."); 82 return RET_FAIL; 83 } 84 85 ret = RET_FAIL; 86 /* Make a couple of paranoid locations for temp files to live if user specified none */ 87 if (!variable_get("PKG_TMPDIR")) { 88 Mkdir("/usr/tmp", NULL); 89 Mkdir("/var/tmp", NULL); 90 } 91 92 sprintf(path, "packages/All/%s%s", name, strstr(name, ".tgz") ? "" : ".tgz"); 93 msgNotify("Adding %s\nfrom %s", path, dev->name); 94 fd = dev->get(dev, path, TRUE); 95 if (fd >= 0) { 96 pen[0] = '\0'; 97 if ((where = make_playpen(pen, 0)) != NULL) { 98 if (mediaExtractDist(pen, fd)) { 99 if (file_readable("+CONTENTS")) { 100 if (vsystem("(pwd; cat +CONTENTS) | pkg_add %s-S", 101 !strcmp(variable_get(VAR_CPIO_VERBOSITY), "high") ? "-v " : "")) { 102 dialog_clear(); 103 if (!variable_get(VAR_NO_CONFIRM)) 104 msgConfirm("An error occurred while trying to pkg_add %s.\n" 105 "Please check debugging screen for possible further details.", name); 106 else 107 msgNotify("An error occurred while trying to pkg_add %s.", name); 108 } 109 else { 110 msgNotify("Package %s added successfully!", name); 111 ret = RET_SUCCESS; 112 } 113 } 114 else { 115 dialog_clear(); 116 if (!variable_get(VAR_NO_CONFIRM)) 117 msgConfirm("The package specified (%s) has no CONTENTS file. This means\n" 118 "that there was either a media error of some sort or the package\n" 119 "file itself is corrupted.\n" 120 "You may wish to look into this and try again.", name); 121 else 122 msgNotify("The package specified (%s) has no CONTENTS file. Skipping.", name); 123 } 124 } 125 else { 126 ret = RET_FAIL; 127 if (!variable_get(VAR_NO_CONFIRM)) 128 msgConfirm("Unable to extract the contents of package %s. This means\n" 129 "that there was either a media error of some sort or the package\n" 130 "file itself is corrupted.\n" 131 "You may wish to look into this and try again.", name); 132 else 133 msgNotify("Unable to extract the contents of package %s. Skipping.", name); 134 } 135 if (chdir(where) == -1) 136 msgFatal("Unable to get back to where I was before, Jojo! (That was: %s)", where); 137 vsystem("rm -rf %s", pen); 138 if (isDebug()) 139 msgDebug("Nuked pen: %s\n", pen); 140 } 141 else { 142 dialog_clear(); 143 msgConfirm("Unable to find a temporary location to unpack this stuff in.\n" 144 "You must simply not have enough space or you've configured your\n" 145 "system oddly. Sorry!"); 146 ret = RET_FAIL; 147 } 148 dev->close(dev, fd); 149 if (dev->type == DEVICE_TYPE_TAPE) 150 unlink(path); 151 } 152 else { 153 msgDebug("pkg_extract: get operation returned %d\n", fd); 154 if (variable_get(VAR_NO_CONFIRM)) 155 msgNotify("Unable to fetch package %s from selected media.\n" 156 "No package add will be done.", name); 157 else { 158 dialog_clear(); 159 msgConfirm("Unable to fetch package %s from selected media.\n" 160 "No package add will be done.", name); 161 } 162 } 163 return ret; 164} 165 166static size_t 167min_free(char *tmpdir) 168{ 169 struct statfs buf; 170 171 if (statfs(tmpdir, &buf) != 0) { 172 msgDebug("Error in statfs, errno = %d\n", errno); 173 return -1; 174 } 175 return buf.f_bavail * buf.f_bsize; 176} 177 178/* Find a good place to play. */ 179static char * 180find_play_pen(char *pen, size_t sz) 181{ 182 struct stat sb; 183 184 if (pen[0] && stat(pen, &sb) != RET_FAIL && (min_free(pen) >= sz)) 185 return pen; 186 else if (stat("/var/tmp", &sb) != RET_FAIL && min_free("/var/tmp") >= sz) 187 strcpy(pen, "/var/tmp/instmp.XXXXXX"); 188 else if (stat("/tmp", &sb) != RET_FAIL && min_free("/tmp") >= sz) 189 strcpy(pen, "/tmp/instmp.XXXXXX"); 190 else if ((stat("/usr/tmp", &sb) == RET_SUCCESS || mkdir("/usr/tmp", 01777) == RET_SUCCESS) && 191 min_free("/usr/tmp") >= sz) 192 strcpy(pen, "/usr/tmp/instmp.XXXXXX"); 193 else { 194 dialog_clear(); 195 msgConfirm("Can't find enough temporary space to extract the files, please try\n" 196 "This again after your system is up (you can run /stand/sysinstall\n" 197 "directly) and you've had a chance to point /var/tmp somewhere with\n" 198 "sufficient temporary space available."); 199 return NULL; 200 } 201 return pen; 202} 203 204/* 205 * Make a temporary directory to play in and chdir() to it, returning 206 * pathname of previous working directory. 207 */ 208static char * 209make_playpen(char *pen, size_t sz) 210{ 211 static char Previous[FILENAME_MAX]; 212 213 if (!find_play_pen(pen, sz)) 214 return NULL; 215 216 if (!mktemp(pen)) { 217 dialog_clear(); 218 msgConfirm("Can't mktemp '%s'.", pen); 219 return NULL; 220 } 221 if (mkdir(pen, 0755) == RET_FAIL) { 222 dialog_clear(); 223 msgConfirm("Can't mkdir '%s'.", pen); 224 return NULL; 225 } 226 if (isDebug()) { 227 if (sz) 228 msgDebug("Requested space: %d bytes, free space: %d bytes in %s\n", (int)sz, min_free(pen), pen); 229 } 230 if (min_free(pen) < sz) { 231 rmdir(pen); 232 dialog_clear(); 233 msgConfirm("Not enough free space to create: `%s'\n" 234 "Please try this again after your system is up (you can run\n" 235 "/stand/sysinstall directly) and you've had a chance to point\n" 236 "/var/tmp somewhere with sufficient temporary space available."); 237 return NULL; 238 } 239 if (!getcwd(Previous, FILENAME_MAX)) { 240 dialog_clear(); 241 msgConfirm("getcwd"); 242 return NULL; 243 } 244 if (chdir(pen) == RET_FAIL) { 245 dialog_clear(); 246 msgConfirm("Can't chdir to '%s'.", pen); 247 } 248 return Previous; 249} 250