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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 #include <stdio.h> 30 #include <errno.h> 31 #include <limits.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <string.h> 35 #include <ctype.h> 36 #include <dirent.h> 37 #include <sys/types.h> 38 #include <pkgstrct.h> 39 #include <pkginfo.h> 40 #include <locale.h> 41 #include <libintl.h> 42 #include <pkglib.h> 43 #include "libinst.h" 44 #include "libadm.h" 45 #include "messages.h" 46 47 #define LSIZE 256 48 #define NVERS 50 49 50 /* 51 * internal global variables 52 */ 53 54 static struct pkginfo info; 55 56 static char type; 57 static char *alist[NVERS]; 58 static char *rmpkginst; 59 static char *vlist[NVERS]; 60 static char file[128]; 61 static char name[128]; 62 static char rmpkg[PKGSIZ+1]; 63 static char wabbrev[128]; 64 65 static int errflg = 0; 66 static int nlist; 67 static int pkgexist; 68 static int pkgokay; 69 static int is_update; 70 static int is_patch_update; 71 72 /* 73 * IMPORTANT NOTE: THE SIZE OF 'abbrev' IS HARD CODED INTO THE CHARACTER 74 * ARRAY SSCANF_FORMAT -- YOU MUST UPDATE BOTH VALUES AT THE SAME TIME!! 75 */ 76 77 static char abbrev[128+1]; 78 static char *SSCANF_FORMAT = "%c %128s %[^\n]"; 79 80 /* 81 * forward declarations 82 */ 83 84 static void ckrdeps(boolean_t a_preinstallCheck); 85 static void ckpreq(FILE *fp, char *dname, boolean_t a_preinstallCheck); 86 static void deponme(char *pkginst, char *pkgname, 87 boolean_t a_preinstallCheck); 88 static void prereq(char *pkginst, char *pkgname, 89 boolean_t a_preinstallCheck); 90 static void incompat(char *pkginst, char *pkgname, 91 boolean_t a_preinstallCheck); 92 static int getaline(FILE *fp); 93 94 /* 95 * ***************************************************************************** 96 * global external (public) functions 97 * ***************************************************************************** 98 */ 99 100 int 101 dockdeps(char *a_depfile, int a_removeFlag, boolean_t a_preinstallCheck) 102 { 103 FILE *fp; 104 int i; 105 char *inst; 106 107 if (a_removeFlag) { 108 /* check removal dependencies */ 109 rmpkginst = a_depfile; 110 (void) strncpy(rmpkg, rmpkginst, PKGSIZ); 111 (void) strtok(rmpkg, "."); 112 (void) snprintf(file, sizeof (file), 113 "%s/%s/%s", pkgdir, rmpkginst, DEPEND_FILE); 114 if ((fp = fopen(file, "r")) == NULL) 115 goto done; 116 } else { 117 if ((fp = fopen(a_depfile, "r")) == NULL) { 118 progerr(ERR_CANNOT_OPEN_DEPEND_FILE, a_depfile, 119 strerror(errno)); 120 quit(99); 121 } 122 } 123 124 while (getaline(fp)) { 125 switch (type) { 126 case 'I': 127 case 'P': 128 if (a_removeFlag) { 129 continue; 130 } 131 break; 132 133 case 'R': 134 if (!a_removeFlag) { 135 continue; 136 } 137 break; 138 139 default: 140 errflg++; 141 progerr(ERR_UNKNOWN_DEPENDENCY, type); 142 break; 143 } 144 145 /* check to see if any versions listed are installed */ 146 pkgexist = pkgokay = 0; 147 i = 0; 148 if (strchr(abbrev, '.')) { 149 progerr(ERR_PKGABRV, abbrev); 150 } 151 (void) snprintf(wabbrev, sizeof (wabbrev), "%s.*", abbrev); 152 153 do { 154 inst = fpkginst(wabbrev, alist[i], vlist[i]); 155 if (inst && (pkginfo(&info, inst, NULL, NULL) == 0)) { 156 pkgexist++; 157 if (info.status == PI_INSTALLED) 158 pkgokay++; 159 } 160 } while (++i < nlist); 161 (void) fpkginst(NULL); /* force closing/rewind of files */ 162 163 if (!info.name) { 164 info.name = name; 165 } 166 167 switch (type) { 168 case 'I': 169 incompat(abbrev, info.name, a_preinstallCheck); 170 break; 171 172 case 'P': 173 prereq(abbrev, name, a_preinstallCheck); 174 break; 175 176 case 'R': 177 deponme(abbrev, info.name, a_preinstallCheck); 178 } 179 } 180 (void) fclose(fp); 181 182 done: 183 if (a_removeFlag) { 184 ckrdeps(a_preinstallCheck); 185 } 186 187 return (errflg); 188 } 189 190 void 191 setPatchUpdate(void) 192 { 193 is_patch_update = 1; 194 } 195 196 int 197 isPatchUpdate(void) 198 { 199 return ((is_patch_update) ? 1 : 0); 200 } 201 202 void 203 setUpdate(void) 204 { 205 is_update = 1; 206 } 207 208 int 209 isUpdate(void) 210 { 211 return ((is_update) ? 1 : 0); 212 } 213 214 /* 215 * ***************************************************************************** 216 * static internal (private) functions 217 * ***************************************************************************** 218 */ 219 220 static void 221 incompat(char *pkginst, char *pkgname, boolean_t a_preinstallCheck) 222 { 223 char buf[512]; 224 225 if (!pkgexist) 226 return; 227 228 errflg++; 229 if (a_preinstallCheck == B_TRUE) { 230 (void) fprintf(stdout, "incompat=%s\n", pkginst); 231 return; 232 } 233 234 logerr(ERR_WARNING); 235 (void) snprintf(buf, sizeof (buf), ERR_INCOMP_VERS, pkginst, pkgname); 236 puttext(stderr, buf, 4, 0); 237 (void) putc('\n', stderr); 238 } 239 240 static void 241 prereq(char *pkginst, char *pkgname, boolean_t a_preinstallCheck) 242 { 243 register int i; 244 char buf[512]; 245 246 if (pkgokay) { 247 return; 248 } 249 250 errflg++; 251 252 if (a_preinstallCheck == B_TRUE) { 253 if (pkgexist) { 254 (void) fprintf(stdout, 255 "prerequisite-incomplete=%s\n", pkginst); 256 } else { 257 (void) fprintf(stdout, 258 "prerequisite-installed=%s\n", pkginst); 259 } 260 return; 261 } 262 263 logerr(ERR_WARNING); 264 if (pkgexist) { 265 (void) snprintf(buf, sizeof (buf), ERR_PRENCI, pkginst, 266 pkgname); 267 puttext(stderr, buf, 4, 0); 268 (void) putc('\n', stderr); 269 } else { 270 (void) snprintf(buf, sizeof (buf), ERR_PREREQ, pkginst, 271 pkgname); 272 if (nlist) { 273 (void) strcat(buf, ERR_VALINST); 274 } 275 puttext(stderr, buf, 4, 0); 276 (void) putc('\n', stderr); 277 for (i = 0; i < nlist; i++) { 278 (void) printf(" "); 279 if (alist[i]) 280 (void) printf("(%s) ", alist[i]); 281 if (vlist[i]) 282 (void) printf("%s", vlist[i]); 283 (void) printf("\n"); 284 } 285 } 286 } 287 288 static void 289 deponme(char *pkginst, char *pkgname, boolean_t a_preinstallCheck) 290 { 291 char buf[512]; 292 293 if (!pkgexist) 294 return; 295 296 errflg++; 297 298 if (a_preinstallCheck == B_TRUE) { 299 if (!pkgname || !pkgname[0]) { 300 (void) snprintf(buf, sizeof (buf), 301 "dependonme=%s", pkginst); 302 } else { 303 (void) snprintf(buf, sizeof (buf), 304 "dependsonme=%s:%s", pkginst, pkgname); 305 } 306 (void) fprintf(stdout, "%s\n", buf); 307 return; 308 } 309 310 logerr(ERR_WARNING); 311 if (!pkgname || !pkgname[0]) { 312 (void) snprintf(buf, sizeof (buf), ERR_DEPONME, pkginst); 313 } else { 314 (void) snprintf(buf, sizeof (buf), ERR_DEPNAM, pkginst, 315 pkgname); 316 } 317 puttext(stderr, buf, 4, 0); 318 (void) putc('\n', stderr); 319 } 320 321 static int 322 getaline(FILE *fp) 323 { 324 register int i, c, found; 325 char *pt, *new, line[LSIZE]; 326 327 abbrev[0] = name[0] = type = '\0'; 328 329 for (i = 0; i < nlist; i++) { 330 if (alist[i]) { 331 free(alist[i]); 332 alist[i] = NULL; 333 } 334 if (vlist[i]) { 335 free(vlist[i]); 336 vlist[i] = NULL; 337 } 338 } 339 alist[0] = vlist[0] = NULL; 340 341 found = (-1); 342 nlist = 0; 343 while ((c = getc(fp)) != EOF) { 344 (void) ungetc(c, fp); 345 if ((found >= 0) && !isspace(c)) 346 return (1); 347 348 if (!fgets(line, LSIZE, fp)) 349 break; 350 351 for (pt = line; isspace(*pt); /* void */) 352 pt++; 353 if (!*pt || (*pt == '#')) 354 continue; 355 356 if (pt == line) { 357 /* begin new definition */ 358 /* LINTED variable format specifier to sscanf(): */ 359 (void) sscanf(line, SSCANF_FORMAT, &type, abbrev, name); 360 found++; 361 continue; 362 } 363 if (found < 0) 364 return (0); 365 366 if (*pt == '(') { 367 /* architecture is specified */ 368 if (new = strchr(pt, ')')) 369 *new++ = '\0'; 370 else 371 return (-1); /* bad specification */ 372 alist[found] = qstrdup(pt+1); 373 pt = new; 374 } 375 while (isspace(*pt)) 376 pt++; 377 if (*pt) { 378 vlist[found] = qstrdup(pt); 379 if (pt = strchr(vlist[found], '\n')) 380 *pt = '\0'; 381 } 382 found++; 383 nlist++; 384 } 385 return ((found >= 0) ? 1 : 0); 386 } 387 388 static void 389 ckrdeps(boolean_t a_preinstallCheck) 390 { 391 struct dirent *drp; 392 DIR *dirfp; 393 FILE *fp; 394 char depfile[PATH_MAX+1]; 395 396 if ((dirfp = opendir(pkgdir)) == NULL) 397 return; 398 399 while ((drp = readdir(dirfp)) != NULL) { 400 if (drp->d_name[0] == '.') 401 continue; 402 403 if (strcmp(drp->d_name, rmpkginst) == 0) 404 continue; /* others don't include me */ 405 (void) snprintf(depfile, sizeof (depfile), 406 "%s/%s/%s", pkgdir, drp->d_name, DEPEND_FILE); 407 if ((fp = fopen(depfile, "r")) == NULL) 408 continue; 409 410 ckpreq(fp, drp->d_name, a_preinstallCheck); 411 } 412 (void) closedir(dirfp); 413 } 414 415 static void 416 ckpreq(FILE *fp, char *dname, boolean_t a_preinstallCheck) 417 { 418 register int i; 419 char *inst; 420 421 while (getaline(fp)) { 422 if (type != 'P') 423 continue; 424 425 if (strcmp(abbrev, rmpkg)) 426 continue; 427 428 /* see if package is installed */ 429 i = 0; 430 if (strchr(abbrev, '.') == 0) { 431 (void) strcat(abbrev, ".*"); 432 } 433 pkgexist = 1; 434 435 do { 436 if (inst = fpkginst(abbrev, alist[i], vlist[i])) { 437 if (strcmp(inst, rmpkginst) == 0) { 438 deponme(dname, "", a_preinstallCheck); 439 (void) fclose(fp); 440 (void) fpkginst(NULL); 441 return; 442 } 443 } 444 } while (++i < nlist); 445 (void) fpkginst(NULL); 446 } 447 (void) fclose(fp); 448 } 449