perform.c revision 81046
1222090Simp#ifndef lint 2255974Semastestatic const char rcsid[] = 3235342Sgjb "$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 81046 2001-08-02 12:38:29Z sobomax $"; 4222090Simp#endif 5222090Simp 6222090Simp/* 7222090Simp * FreeBSD install - a package for the installation and maintainance 8 * of non-core utilities. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * Jordan K. Hubbard 20 * 23 Aug 1993 21 * 22 * This is the main body of the info module. 23 * 24 */ 25 26#include "lib.h" 27#include "info.h" 28#include <err.h> 29#include <signal.h> 30 31static int pkg_do(char *); 32static int find_pkg(char *, struct which_head *); 33static int cmp_path(const char *, const char *, const char *); 34 35int 36pkg_perform(char **pkgs) 37{ 38 char **matched; 39 char *tmp; 40 int err_cnt = 0; 41 int i, errcode; 42 43 signal(SIGINT, cleanup); 44 45 tmp = getenv(PKG_DBDIR); 46 if (!tmp) 47 tmp = DEF_LOG_DIR; 48 49 /* Overriding action? */ 50 if (CheckPkg) { 51 char buf[FILENAME_MAX]; 52 53 snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); 54 return abs(access(buf, R_OK)); 55 /* Not reached */ 56 } else if (!TAILQ_EMPTY(whead)) { 57 return find_pkg(tmp, whead); 58 } 59 60 if (MatchType != MATCH_EXACT) { 61 matched = matchinstalled(MatchType, pkgs, &errcode); 62 if (errcode != 0) 63 return 1; 64 /* Not reached */ 65 66 if (matched != NULL) 67 pkgs = matched; 68 else switch (MatchType) { 69 case MATCH_GLOB: 70 break; 71 case MATCH_ALL: 72 warnx("no packages installed"); 73 return 0; 74 /* Not reached */ 75 case MATCH_REGEX: 76 warnx("no packages match pattern(s)"); 77 return 1; 78 /* Not reached */ 79 default: 80 break; 81 } 82 } 83 84 for (i = 0; pkgs[i]; i++) 85 err_cnt += pkg_do(pkgs[i]); 86 87 return err_cnt; 88} 89 90static char *Home; 91 92static int 93pkg_do(char *pkg) 94{ 95 Boolean installed = FALSE, isTMP = FALSE; 96 char log_dir[FILENAME_MAX]; 97 char fname[FILENAME_MAX]; 98 Package plist; 99 FILE *fp; 100 struct stat sb; 101 char *cp = NULL; 102 int code = 0; 103 104 if (isURL(pkg)) { 105 if ((cp = fileGetURL(NULL, pkg)) != NULL) { 106 strcpy(fname, cp); 107 isTMP = TRUE; 108 } 109 } 110 else if (fexists(pkg) && isfile(pkg)) { 111 int len; 112 113 if (*pkg != '/') { 114 if (!getcwd(fname, FILENAME_MAX)) 115 upchuck("getcwd"); 116 len = strlen(fname); 117 snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg); 118 } 119 else 120 strcpy(fname, pkg); 121 cp = fname; 122 } 123 else { 124 if ((cp = fileFindByPath(NULL, pkg)) != NULL) 125 strncpy(fname, cp, FILENAME_MAX); 126 } 127 if (cp) { 128 /* 129 * Apply a crude heuristic to see how much space the package will 130 * take up once it's unpacked. I've noticed that most packages 131 * compress an average of 75%, but we're only unpacking the + files so 132 * be very optimistic. 133 */ 134 if (stat(fname, &sb) == FAIL) { 135 warnx("can't stat package file '%s'", fname); 136 code = 1; 137 goto bail; 138 } 139 Home = make_playpen(PlayPen, sb.st_size / 2); 140 if (unpack(fname, "+*")) { 141 warnx("error during unpacking, no info for '%s' available", pkg); 142 code = 1; 143 goto bail; 144 } 145 } 146 /* It's not an ininstalled package, try and find it among the installed */ 147 else { 148 char *tmp; 149 150 sprintf(log_dir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, 151 pkg); 152 if (!fexists(log_dir)) { 153 warnx("can't find package '%s' installed or in a file!", pkg); 154 return 1; 155 } 156 if (chdir(log_dir) == FAIL) { 157 warnx("can't change directory to '%s'!", log_dir); 158 return 1; 159 } 160 installed = TRUE; 161 } 162 163 /* Suck in the contents list */ 164 plist.head = plist.tail = NULL; 165 fp = fopen(CONTENTS_FNAME, "r"); 166 if (!fp) { 167 warnx("unable to open %s file", CONTENTS_FNAME); 168 code = 1; 169 goto bail; 170 } 171 /* If we have a prefix, add it now */ 172 read_plist(&plist, fp); 173 fclose(fp); 174 175 /* 176 * Index is special info type that has to override all others to make 177 * any sense. 178 */ 179 if (Flags & SHOW_INDEX) { 180 char tmp[FILENAME_MAX]; 181 182 snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); 183 show_index(tmp, COMMENT_FNAME); 184 } 185 else { 186 /* Start showing the package contents */ 187 if (!Quiet) 188 printf("%sInformation for %s:\n\n", InfoPrefix, pkg); 189 if (Flags & SHOW_COMMENT) 190 show_file("Comment:\n", COMMENT_FNAME); 191 if (Flags & SHOW_REQUIRE) 192 show_plist("Depends on:\n", &plist, PLIST_PKGDEP); 193 if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) 194 show_file("Required by:\n", REQUIRED_BY_FNAME); 195 if (Flags & SHOW_DESC) 196 show_file("Description:\n", DESC_FNAME); 197 if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) 198 show_file("Install notice:\n", DISPLAY_FNAME); 199 if (Flags & SHOW_PLIST) 200 show_plist("Packing list:\n", &plist, (plist_t)-1); 201 if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) 202 show_file("Install script:\n", INSTALL_FNAME); 203 if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME)) 204 show_file("Post-Install script:\n", POST_INSTALL_FNAME); 205 if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) 206 show_file("De-Install script:\n", DEINSTALL_FNAME); 207 if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME)) 208 show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME); 209 if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) 210 show_file("mtree file:\n", MTREE_FNAME); 211 if (Flags & SHOW_PREFIX) 212 show_plist("Prefix(s):\n", &plist, PLIST_CWD); 213 if (Flags & SHOW_FILES) 214 show_files("Files:\n", &plist); 215 if ((Flags & SHOW_SIZE) && installed) 216 show_size("Package Size:\n", &plist); 217 if ((Flags & SHOW_CKSUM) && installed) 218 show_cksum("Mismatched Checksums:\n", &plist); 219 if (Flags & SHOW_ORIGIN) 220 show_origin("Origin:\n", &plist); 221 if (!Quiet) 222 puts(InfoPrefix); 223 } 224 free_plist(&plist); 225 bail: 226 leave_playpen(); 227 if (isTMP) 228 unlink(fname); 229 return code; 230} 231 232void 233cleanup(int sig) 234{ 235 static int in_cleanup = 0; 236 237 if (!in_cleanup) { 238 in_cleanup = 1; 239 leave_playpen(); 240 } 241 if (sig) 242 exit(1); 243} 244 245/* 246 * Return an absolute path, additionally removing all .'s, ..'s, and extraneous 247 * /'s, as realpath() would, but without resolving symlinks, because that can 248 * potentially screw up our comparisons later. 249 */ 250char * 251abspath(const char *pathname) 252{ 253 char *tmp, *tmp1, *resolved_path; 254 char *cwd = NULL; 255 int len; 256 257 if (pathname[0] != '/') { 258 cwd = getcwd(NULL, MAXPATHLEN); 259 asprintf(&resolved_path, "%s/%s/", cwd, pathname); 260 } else 261 asprintf(&resolved_path, "%s/", pathname); 262 263 if (resolved_path == NULL) 264 errx(2, NULL); 265 266 if (cwd != NULL) 267 free(cwd); 268 269 while ((tmp = strstr(resolved_path, "//")) != NULL) 270 strcpy(tmp, tmp + 1); 271 272 while ((tmp = strstr(resolved_path, "/./")) != NULL) 273 strcpy(tmp, tmp + 2); 274 275 while ((tmp = strstr(resolved_path, "/../")) != NULL) { 276 *tmp = '\0'; 277 if ((tmp1 = strrchr(resolved_path, '/')) == NULL) 278 tmp1 = resolved_path; 279 strcpy(tmp1, tmp + 3); 280 } 281 282 len = strlen(resolved_path); 283 if (len > 1 && resolved_path[len - 1] == '/') 284 resolved_path[len - 1] = '\0'; 285 286 return resolved_path; 287} 288 289/* 290 * Comparison to see if the path we're on matches the 291 * one we are looking for. 292 */ 293static int 294cmp_path(const char *target, const char *current, const char *cwd) 295{ 296 char *resolved, *temp; 297 int rval; 298 299 asprintf(&temp, "%s/%s", cwd, current); 300 if (temp == NULL) 301 errx(2, NULL); 302 303 /* 304 * Make sure there's no multiple /'s or other weird things in the PLIST, 305 * since some plists seem to have them and it could screw up our strncmp. 306 */ 307 resolved = abspath(temp); 308 309 if (strcmp(target, resolved) == 0) 310 rval = 1; 311 else 312 rval = 0; 313 314 free(temp); 315 free(resolved); 316 return rval; 317} 318 319/* 320 * Look through package dbs in db_dir and find which 321 * packages installed the files in which_list. 322 */ 323static int 324find_pkg(char *db_dir, struct which_head *which_list) 325{ 326 char **installed; 327 int errcode, i; 328 struct which_entry *wp; 329 330 TAILQ_FOREACH(wp, which_list, next) { 331 char *msg = "file cannot be found"; 332 char *tmp; 333 334 wp->skip = TRUE; 335 /* If it's not a file, we'll see if it's an executable. */ 336 if (isfile(wp->file) == FALSE) { 337 if (strchr(wp->file, '/') == NULL) { 338 tmp = vpipe("/usr/bin/which %s", wp->file); 339 if (tmp != NULL) { 340 strlcpy(wp->file, tmp, PATH_MAX); 341 wp->skip = FALSE; 342 free(tmp); 343 } else 344 msg = "file is not in PATH"; 345 } 346 } else { 347 tmp = abspath(wp->file); 348 if (isfile(tmp)) { 349 strlcpy(wp->file, tmp, PATH_MAX); 350 wp->skip = FALSE; 351 } 352 free(tmp); 353 } 354 if (wp->skip == TRUE) 355 warnx("%s: %s", wp->file, msg); 356 } 357 358 installed = matchinstalled(MATCH_ALL, NULL, &errcode); 359 if (installed == NULL) 360 return errcode; 361 362 for (i = 0; installed[i] != NULL; i++) { 363 FILE *fp; 364 Package pkg; 365 PackingList itr; 366 char *cwd = NULL; 367 char tmp[PATH_MAX]; 368 369 snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], 370 CONTENTS_FNAME); 371 fp = fopen(tmp, "r"); 372 if (fp == NULL) { 373 warn("%s", tmp); 374 return 1; 375 } 376 377 pkg.head = pkg.tail = NULL; 378 read_plist(&pkg, fp); 379 fclose(fp); 380 for (itr = pkg.head; itr != pkg.tail; itr = itr->next) { 381 if (itr->type == PLIST_CWD) { 382 cwd = itr->name; 383 } else if (itr->type == PLIST_FILE) { 384 TAILQ_FOREACH(wp, which_list, next) { 385 if (wp->skip == TRUE) 386 continue; 387 if (!cmp_path(wp->file, itr->name, cwd)) 388 continue; 389 if (wp->package[0] != '\0') { 390 warnx("both %s and %s claim to have installed %s\n", 391 wp->package, installed[i], wp->file); 392 } else { 393 strlcpy(wp->package, installed[i], PATH_MAX); 394 } 395 } 396 } 397 } 398 free_plist(&pkg); 399 } 400 401 TAILQ_FOREACH(wp, which_list, next) { 402 if (wp->package[0] != '\0') { 403 if (Quiet) 404 puts(wp->package); 405 else 406 printf("%s was installed by package %s\n", \ 407 wp->file, wp->package); 408 } 409 } 410 while (!TAILQ_EMPTY(which_list)) { 411 wp = TAILQ_FIRST(which_list); 412 TAILQ_REMOVE(which_list, wp, next); 413 free(wp); 414 } 415 416 free(which_list); 417 return 0; 418} 419