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