1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #include <stdio.h> 29 #include <time.h> 30 #include <wait.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <ulimit.h> 34 #include <sys/stat.h> 35 #include <sys/statvfs.h> 36 #include <assert.h> 37 #include <fcntl.h> 38 #include <errno.h> 39 #include <ctype.h> 40 #include <dirent.h> 41 #include <string.h> 42 #include <signal.h> 43 #include <locale.h> 44 #include <libintl.h> 45 #include <pkgstrct.h> 46 #include <pkginfo.h> 47 #include <pkgdev.h> 48 #include <pkglocs.h> 49 #include <pwd.h> 50 #include <pkglib.h> 51 #include <libinst.h> 52 #include <libadm.h> 53 #include <messages.h> 54 55 /* 56 * ***************************************************************************** 57 * global external (public) functions 58 * ***************************************************************************** 59 */ 60 61 /* 62 * open package datastream 63 * Arguments: a_argc - (int) - [RO, *RO] 64 * - number of arguments available in a_argv 65 * a_argv - (char **) - [RO, *RO] 66 * - arguments representing package names to add 67 * a_spoolDir - (char *) - [RO, *RO] 68 * - directory to write the package (spool) into 69 * - if == (char *)NULL then install the packages 70 * - if != (char *)NULL then write packages into directory 71 * a_device - (char *) - [RO, *RO] 72 * - device to read packages from when spooling 73 * - ignored if a_spoolDir == (char *)NULL 74 * r_repeat - (int *) - [RO, *RW] 75 * - set == 0 if no further package names in argc/argv 76 * - set != 0 IF there are package names in argc/argv 77 * - if == (int *)NULL - not set 78 * r_idsName - (char **) - [RW, *RW] 79 * - set to the name of package input data stream device 80 * - if == (char *)NULL - no input data stream; that is, 81 * -- the packages are in a directory and not in a stream 82 * - if != (char *)NULL - this is the device/file that 83 * -- is the datastream that contains the packages to add 84 * a_pkgdev - (struct pkgdev *) - [RO, *RW] 85 * - pkgdev structure containing package device to open 86 * Returns: B_TRUE - datastream opened successfully 87 * B_FALSE - datastream failed to open 88 */ 89 90 boolean_t 91 open_package_datastream(int a_argc, char **a_argv, char *a_spoolDir, 92 char *a_device, int *r_repeat, char **r_idsName, char *a_tmpdir, 93 struct pkgdev *a_pkgdev, int a_optind) 94 { 95 int n; 96 97 /* entry assertions */ 98 99 assert(a_argv != (char **)NULL); 100 assert(r_idsName != (char **)NULL); 101 assert(a_tmpdir != (char *)NULL); 102 assert(a_pkgdev != (struct pkgdev *)NULL); 103 104 /* entry debug information */ 105 106 echoDebug(DBG_ODS_ENTRY); 107 echoDebug(DBG_ODS_ARGS, 108 a_pkgdev->bdevice ? a_pkgdev->bdevice : "?", 109 a_pkgdev->cdevice ? a_pkgdev->cdevice : "?", 110 a_pkgdev->pathname ? a_pkgdev->pathname : "?", 111 a_argc, a_device ? a_device : "?"); 112 113 /* reset possible return values to defaults */ 114 115 *r_idsName = (char *)NULL; 116 if (r_repeat != (int *)NULL) { 117 *r_repeat = 0; 118 } 119 120 /* 121 * Determine how to access the package source "device": 122 * - if a block device is associated with the source: 123 * -- make sure the next "volume" is mounted and ready. 124 * -- input data stream is associated character device 125 * - if char device but no block device associated with device: 126 * -- input data stream is associated character device 127 * - else if a path is associated with device: 128 * -- input data stream is associated path 129 */ 130 131 if (a_pkgdev->bdevice != (char *)NULL) { 132 /* package source is block device */ 133 134 /* 135 * _getvol verifies that the specified device is accessible and 136 * that a volume of the appropriate medium has been inserted. 137 * _getvol is in libadm.h - delivered by ON as part of SUNWcsl 138 * is somewhat analagous to getvol(1M) - args are: 139 * - char *device 140 * - char *label 141 * - int options 142 * - char *prompt 143 * - char *norewind - no rewind device (NULL to use device) 144 * Returns: 145 * 0 - okay, label matches 146 * 1 - device not accessable 147 * 2 - unknown device (devattr failed) 148 * 3 - user selected quit 149 * 4 - label does not match 150 */ 151 152 echoDebug(DBG_ODS_DATASTREAM_BDEV, a_pkgdev->bdevice); 153 154 n = _getvol(a_pkgdev->bdevice, NULL, 0L, 155 MSG_INSERT_VOL, a_pkgdev->norewind); 156 157 switch (n) { 158 case 0: /* volume open, label matches */ 159 if (ds_readbuf(a_pkgdev->cdevice)) { 160 (*r_idsName) = a_pkgdev->cdevice; 161 } 162 break; 163 case 3: /* user selected quit */ 164 quit(3); 165 /* NOTREACHED */ 166 case 2: /* unknown device (devattr failed) */ 167 progerr(ERR_UNKNOWN_DEV, a_pkgdev->name); 168 quit(99); 169 /* NOTREACHED */ 170 default: /* device not accessable */ 171 progerr(ERR_PKGVOL); 172 logerr(LOG_GETVOL_RET, n); 173 quit(99); 174 /* NOTREACHED */ 175 } 176 } else if (a_pkgdev->cdevice != (char *)NULL) { 177 /* package source is character device */ 178 179 echoDebug(DBG_ODS_DATASTREAM_CDEV, a_pkgdev->cdevice); 180 181 (*r_idsName) = a_pkgdev->cdevice; 182 } else if (a_pkgdev->pathname != (char *)NULL) { 183 /* package source is path name to file */ 184 185 echoDebug(DBG_ODS_DATASTREAM_ISFILE, a_pkgdev->pathname); 186 187 (*r_idsName) = a_pkgdev->pathname; 188 } else { 189 echoDebug(DBG_ODS_DATASTREAM_UNK); 190 } 191 192 /* 193 * If writing the packages into a spool directory instead of 194 * installing the packages, invoke pkgtrans to perform the 195 * conversion and exit. 196 */ 197 198 if (a_spoolDir) { 199 return (B_TRUE); 200 } 201 202 /* create temp dir for op if input data stream specified */ 203 204 if (*r_idsName) { 205 /* 206 * initialize datastream, 207 * dirname is set to directory where package is unstreamed 208 */ 209 if (setup_temporary_directory(&a_pkgdev->dirname, a_tmpdir, 210 "dstream") == B_FALSE) { 211 progerr(ERR_STREAMDIR, strerror(errno)); 212 quit(99); 213 /* NOTREACHED */ 214 } 215 } 216 217 if (r_repeat != (int *)NULL) { 218 *r_repeat = (a_optind >= a_argc); 219 } 220 221 /* 222 * mount source device (e.g. floppy) if no input data stream 223 * specified, and the package source device is mountable. If 224 * the pkgmount fails, go back and try to mount the package 225 * source again. When a package is split up into multiple 226 * volumes (such as floppies), it might be possible to go back 227 * and insert a different copy of the required volume/floppy 228 * if the current one cannot be mounted. Otherwise this could 229 * have just called quit() if the mount failed... 230 */ 231 232 if (((*r_idsName) == (char *)NULL) && a_pkgdev->mount) { 233 echoDebug(DBG_ODS_DATASTREAM_MOUNTING, *r_idsName, 234 a_pkgdev->mount); 235 a_pkgdev->rdonly++; 236 n = pkgmount(a_pkgdev, NULL, 0, 0, 0); 237 if (n != 0) { 238 /* pkgmount failed */ 239 return (B_FALSE); 240 } 241 } 242 243 /* 244 * open and initialize input data stream if specified 245 */ 246 247 if ((*r_idsName) != (char *)NULL) { 248 echoDebug(DBG_ODS_DATASTREAM_INIT, *r_idsName); 249 250 /* use character device to force rewind of datastream */ 251 if ((a_pkgdev->cdevice != (char *)NULL) && 252 (a_pkgdev->bdevice == (char *)NULL)) { 253 n = _getvol(a_pkgdev->name, NULL, 0L, NULL, 254 a_pkgdev->norewind); 255 256 switch (n) { 257 case 0: /* volume open, label matches */ 258 break; 259 case 3: /* user selected quit */ 260 quit(3); 261 /* NOTREACHED */ 262 case 2: /* unknown device (devattr failed) */ 263 progerr(ERR_UNKNOWN_DEV, a_pkgdev->name); 264 quit(99); 265 /* NOTREACHED */ 266 default: 267 progerr(ERR_PKGVOL); 268 logerr(LOG_GETVOL_RET, n); 269 quit(99); 270 /* NOTREACHED */ 271 } 272 } 273 274 if (chdir(a_pkgdev->dirname)) { 275 progerr(ERR_CHDIR, a_pkgdev->dirname); 276 quit(99); 277 /* NOTREACHED */ 278 } 279 280 /* 281 * initialize datastream for subsequent installation; 282 * read the source device; 283 * aquire the header data and check it for validity; 284 * creates subdirectories in package stream directory 285 * (a_pkgdev->dirname) for each package and retrieves each 286 * packages pkginfo and pkgmap files 287 */ 288 289 if (ds_init(*r_idsName, &a_argv[a_optind], 290 a_pkgdev->norewind)) { 291 progerr(ERR_DSINIT, *r_idsName); 292 quit(99); 293 /* NOTREACHED */ 294 } 295 } 296 297 return (B_TRUE); 298 } 299