198766Smarkm/* 2228990Suqs * FreeBSD install - a package for the installation and maintenance 398766Smarkm * of non-core utilities. 498766Smarkm * 598766Smarkm * Redistribution and use in source and binary forms, with or without 698766Smarkm * modification, are permitted provided that the following conditions 798766Smarkm * are met: 898766Smarkm * 1. Redistributions of source code must retain the above copyright 998766Smarkm * notice, this list of conditions and the following disclaimer. 1098766Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1198766Smarkm * notice, this list of conditions and the following disclaimer in the 1298766Smarkm * documentation and/or other materials provided with the distribution. 1398766Smarkm * 1498766Smarkm * Jeremy D. Lea. 1598766Smarkm * 11 May 2002 1698766Smarkm * 1798766Smarkm * This is the version module. Based on pkg_version.pl by Bruce A. Mah. 1898766Smarkm * 1998766Smarkm */ 2098766Smarkm 2198766Smarkm#include <sys/cdefs.h> 2298766Smarkm__FBSDID("$FreeBSD: releng/10.3/usr.sbin/pkg_install/version/perform.c 241737 2012-10-19 14:49:42Z ed $"); 2398766Smarkm 24222035Sflz#include "lib.h" 2598766Smarkm#include "version.h" 2698766Smarkm#include <err.h> 2798766Smarkm#include <fetch.h> 2898766Smarkm#include <signal.h> 2998766Smarkm 30241737Sedstatic FILE *IndexFile; 31241737Sedstatic char IndexPath[PATH_MAX] = ""; 32241737Sedstatic struct index_head Index = SLIST_HEAD_INITIALIZER(Index); 3398766Smarkm 3498766Smarkmstatic int pkg_do(char *); 35148435Skrionstatic void show_version(Package, const char *, const char *); 3698766Smarkm 3798766Smarkm/* 38206043Sflz * This is the traditional pkg_perform, except that the argument is _not_ a 39206043Sflz * list of packages. It is the index file from the command line. 4098766Smarkm * 41206043Sflz * We loop over the installed packages, matching them with the -s flag if 42206043Sflz * needed and calling pkg_do(). Beforehand we set up a few things, and after 43206043Sflz * we tear them down... 44206043Sflz * 45206043Sflz * Returns 0 on success, non-zero on failure, corresponding to the number of 46206043Sflz * failed attempts to access the INDEX. 4798766Smarkm */ 4898766Smarkmint 4998766Smarkmpkg_perform(char **indexarg) 5098766Smarkm{ 51173014Ssimon char **pkgs, *pat[2], **patterns; 5298766Smarkm struct index_entry *ie; 53206043Sflz int i, err_cnt = 0, rel_major_ver; 54113079Srobert int MatchType; 5598766Smarkm 56206043Sflz struct utsname u; 57206043Sflz 58206043Sflz if (uname(&u) == -1) { 59240682Sbapt warn("%s: failed to determine uname information", __func__); 60206043Sflz return 1; 61206043Sflz } else if ((rel_major_ver = (int) strtol(u.release, NULL, 10)) <= 0) { 62240682Sbapt warnx("%s: bad release version specified: %s", __func__, u.release); 63240682Sbapt return 1; 64206043Sflz } 65206043Sflz 6698766Smarkm /* 6798766Smarkm * Try to find and open the INDEX. We only check IndexFile != NULL 6898766Smarkm * later, if we actually need the INDEX. 6998766Smarkm */ 70206043Sflz if (*indexarg == NULL) { 71206043Sflz snprintf(IndexPath, sizeof(IndexPath), "%s/INDEX-%d", PORTS_DIR, 72206043Sflz rel_major_ver); 73206043Sflz } else 74173014Ssimon strlcpy(IndexPath, *indexarg, sizeof(IndexPath)); 75173014Ssimon if (isURL(IndexPath)) 76173014Ssimon IndexFile = fetchGetURL(IndexPath, ""); 7798766Smarkm else 78173014Ssimon IndexFile = fopen(IndexPath, "r"); 7998766Smarkm 80113079Srobert /* Get either a list of matching or all packages */ 81113079Srobert if (MatchName != NULL) { 82113079Srobert pat[0] = MatchName; 83113079Srobert pat[1] = NULL; 84131275Seik MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX; 85113079Srobert patterns = pat; 86148435Skrion } else { 87113079Srobert MatchType = MATCH_ALL; 88113079Srobert patterns = NULL; 89148435Skrion } 90113079Srobert 91148435Skrion if (LookUpOrigin != NULL) 92148435Skrion pkgs = matchbyorigin(LookUpOrigin, &err_cnt); 93148435Skrion else 94148435Skrion pkgs = matchinstalled(MatchType, patterns, &err_cnt); 95148435Skrion 9698766Smarkm if (err_cnt != 0) 9798766Smarkm errx(2, "Unable to find package database directory!"); 98113079Srobert if (pkgs == NULL) { 99148435Skrion if (LookUpOrigin != NULL) { 100148435Skrion warnx("no packages recorded with this origin"); 101113079Srobert return (1); 102148435Skrion } else { 103148435Skrion switch (MatchType) { 104148435Skrion case MATCH_ALL: 105148435Skrion warnx("no packages installed"); 106148435Skrion return (0); 107148435Skrion case MATCH_EREGEX: 108148435Skrion case MATCH_REGEX: 109148435Skrion warnx("no packages match pattern"); 110148435Skrion return (1); 111148435Skrion default: 112148435Skrion break; 113148435Skrion } 114113079Srobert } 11598766Smarkm } 11698766Smarkm 117113079Srobert for (i = 0; pkgs[i] != NULL; i++) 118113079Srobert err_cnt += pkg_do(pkgs[i]); 119113079Srobert 12098766Smarkm /* If we opened the INDEX in pkg_do(), clean up. */ 12198766Smarkm while (!SLIST_EMPTY(&Index)) { 12298766Smarkm ie = SLIST_FIRST(&Index); 12398766Smarkm SLIST_REMOVE_HEAD(&Index, next); 124103119Ssobomax if (ie->name != NULL) 125103119Ssobomax free(ie->name); 126103119Ssobomax if (ie->origin != NULL) 127103119Ssobomax free(ie->origin); 12898766Smarkm free(ie); 12998766Smarkm } 13098766Smarkm if (IndexFile != NULL) 13198766Smarkm fclose(IndexFile); 13298766Smarkm 13398766Smarkm return err_cnt; 13498766Smarkm} 13598766Smarkm 13698766Smarkm/* 13798766Smarkm * Traditional pkg_do(). We take the package name we are passed and 13898766Smarkm * first slurp in the CONTENTS file, getting name and origin, then 13998766Smarkm * we look for it's corresponding Makefile. If that fails we pull in 14098766Smarkm * the INDEX, and check there. 14198766Smarkm */ 14298766Smarkmstatic int 14398766Smarkmpkg_do(char *pkg) 14498766Smarkm{ 14598766Smarkm char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL; 14698766Smarkm Package plist; 14798766Smarkm struct index_entry *ie; 14898766Smarkm FILE *fp; 14998766Smarkm size_t len; 15098766Smarkm 15198766Smarkm /* Suck in the contents list. */ 15298766Smarkm plist.head = plist.tail = NULL; 15398766Smarkm plist.name = plist.origin = NULL; 15498766Smarkm snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, pkg, CONTENTS_FNAME); 15598766Smarkm fp = fopen(tmp, "r"); 15698766Smarkm if (!fp) { 157131280Seik warnx("the package info for package '%s' is corrupt", pkg); 15898766Smarkm return 1; 15998766Smarkm } 16098766Smarkm read_plist(&plist, fp); 16198766Smarkm fclose(fp); 162102438Sreg if (plist.name == NULL) { 163102438Sreg warnx("%s does not appear to be a valid package!", pkg); 164102438Sreg return 1; 165102438Sreg } 16698766Smarkm 16798766Smarkm /* 16898766Smarkm * First we check if the installed package has an origin, and try 16998766Smarkm * looking for it's Makefile. If we find the Makefile we get the 17098766Smarkm * latest version from there. If we fail, we start looking in the 17198766Smarkm * INDEX, first matching the origin and then the package name. 17298766Smarkm */ 173146559Scperciva if (plist.origin != NULL && !UseINDEXOnly) { 17498766Smarkm snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, plist.origin); 17598766Smarkm if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) { 176131285Seik if ((latest = vpipe("/usr/bin/make -V PKGNAME", tmp)) == NULL) 17798766Smarkm warnx("Failed to get PKGNAME from %s/Makefile!", tmp); 17898766Smarkm else 179148435Skrion show_version(plist, latest, "port"); 18098766Smarkm } 18198766Smarkm } 18298766Smarkm if (latest == NULL) { 183151200Skrion /* Report package as not found in INDEX if the INDEX is not required. */ 184151200Skrion if (IndexFile == NULL && !UseINDEXOnly) 185151200Skrion show_version(plist, NULL, plist.origin); 186151200Skrion else { 18798766Smarkm /* We only pull in the INDEX once, if needed. */ 18898766Smarkm if (SLIST_EMPTY(&Index)) { 18998766Smarkm if (!IndexFile) 190173014Ssimon errx(2, "Unable to open %s in %s.", IndexPath, __func__); 19198766Smarkm while ((ch = fgetln(IndexFile, &len)) != NULL) { 19298766Smarkm /* 19398766Smarkm * Don't use strlcpy() because fgetln() doesn't 19498766Smarkm * return a valid C string. 19598766Smarkm */ 19698766Smarkm strncpy(tmp, ch, MIN(len, PATH_MAX)); 19798766Smarkm tmp[PATH_MAX-1] = '\0'; 19898766Smarkm /* The INDEX has pkgname|portdir|... */ 19998766Smarkm if ((ch = strchr(tmp, '|')) != NULL) 20098766Smarkm ch[0] = '\0'; 20198766Smarkm if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL) 20298766Smarkm ch[0] = '\0'; 20398766Smarkm /* Look backwards for the last two dirs = origin */ 20498766Smarkm while (ch != NULL && *--ch != '/') 20598766Smarkm if (ch[0] == '\0') 20698766Smarkm ch = NULL; 20798766Smarkm while (ch != NULL && *--ch != '/') 20898766Smarkm if (ch[0] == '\0') 20998766Smarkm ch = NULL; 21098766Smarkm if (ch == NULL) 21198766Smarkm errx(2, "The INDEX does not appear to be valid!"); 21298766Smarkm if ((ie = malloc(sizeof(struct index_entry))) == NULL) 21398766Smarkm errx(2, "Unable to allocate memory in %s.", __func__); 214103119Ssobomax bzero(ie, sizeof(struct index_entry)); 215103119Ssobomax ie->name = strdup(tmp); 216103119Ssobomax ie->origin = strdup(&ch[1]); 21798766Smarkm /* Who really cares if we reverse the index... */ 21898766Smarkm SLIST_INSERT_HEAD(&Index, ie, next); 21998766Smarkm } 22098766Smarkm } 22198766Smarkm /* Now that we've slurped in the INDEX... */ 22298766Smarkm SLIST_FOREACH(ie, &Index, next) { 22398766Smarkm if (plist.origin != NULL) { 22498766Smarkm if (strcmp(plist.origin, ie->origin) == 0) 22598766Smarkm latest = strdup(ie->name); 22698766Smarkm } else { 22798766Smarkm strlcpy(tmp, ie->name, PATH_MAX); 22898766Smarkm strlcpy(tmp2, plist.name, PATH_MAX); 22998766Smarkm /* Chop off the versions and compare. */ 23098766Smarkm if ((ch = strrchr(tmp, '-')) == NULL) 23198766Smarkm errx(2, "The INDEX does not appear to be valid!"); 23298766Smarkm ch[0] = '\0'; 23398766Smarkm if ((ch = strrchr(tmp2, '-')) == NULL) 23498766Smarkm warnx("%s is not a valid package!", plist.name); 23598766Smarkm else 23698766Smarkm ch[0] = '\0'; 23798766Smarkm if (strcmp(tmp2, tmp) == 0) { 23898766Smarkm if (latest != NULL) { 23998766Smarkm /* Multiple matches */ 24098766Smarkm snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name); 24198766Smarkm free(latest); 24298766Smarkm latest = strdup(tmp); 24398766Smarkm } else 24498766Smarkm latest = strdup(ie->name); 24598766Smarkm } 24698766Smarkm } 24798766Smarkm } 24898766Smarkm if (latest == NULL) 249148435Skrion show_version(plist, NULL, NULL); 25098766Smarkm else 251148435Skrion show_version(plist, latest, "index"); 252151200Skrion } 25398766Smarkm } 25498766Smarkm if (latest != NULL) 25598766Smarkm free(latest); 25698766Smarkm free_plist(&plist); 25798766Smarkm return 0; 25898766Smarkm} 25998766Smarkm 26098766Smarkm#define OUTPUT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \ 26198766Smarkm (LimitChars != NULL && strchr(LimitChars, (c))) || \ 26298766Smarkm (PreventChars == NULL && LimitChars == NULL)) 26398766Smarkm 26498766Smarkm/* 26598766Smarkm * Do the work of comparing and outputing. Ugly, but well that's what 26698766Smarkm * You get when you try to match perl output in C ;-). 26798766Smarkm */ 26898766Smarkmvoid 269148435Skrionshow_version(Package plist, const char *latest, const char *source) 27098766Smarkm{ 27198766Smarkm char *ch, tmp[PATH_MAX]; 27298766Smarkm const char *ver; 27398766Smarkm int cmp = 0; 27498766Smarkm 275148435Skrion if (!plist.name || strlen(plist.name) == 0) 27698766Smarkm return; 277161251Skrion if (ShowOrigin != FALSE && plist.origin != NULL) 278148435Skrion strlcpy(tmp, plist.origin, PATH_MAX); 279155577Skrion else { 280148435Skrion strlcpy(tmp, plist.name, PATH_MAX); 281155577Skrion if (!Verbose) { 282155577Skrion if ((ch = strrchr(tmp, '-')) != NULL) 283155577Skrion ch[0] = '\0'; 284155577Skrion } 28598766Smarkm } 28698766Smarkm if (latest == NULL) { 28798766Smarkm if (source == NULL && OUTPUT('!')) { 28898766Smarkm printf("%-34s !", tmp); 28998766Smarkm if (Verbose) 29098766Smarkm printf(" Comparison failed"); 29198766Smarkm printf("\n"); 292148435Skrion } else if (OUTPUT('?')) { 29398766Smarkm printf("%-34s ?", tmp); 29498766Smarkm if (Verbose) 295148435Skrion printf(" orphaned: %s", plist.origin); 29698766Smarkm printf("\n"); 29798766Smarkm } 29898766Smarkm } else if (strchr(latest,'|') != NULL) { 29998766Smarkm if (OUTPUT('*')) { 30098766Smarkm printf("%-34s *", tmp); 30198766Smarkm if (Verbose) { 30298766Smarkm strlcpy(tmp, latest, PATH_MAX); 30398766Smarkm ch = strchr(tmp, '|'); 30498766Smarkm ch[0] = '\0'; 30598766Smarkm 306131274Seik ver = strrchr(tmp, '-'); 307131274Seik ver = ver ? &ver[1] : tmp; 30898766Smarkm printf(" multiple versions (index has %s", ver); 30998766Smarkm do { 310131274Seik ver = strrchr(&ch[1], '-'); 311131274Seik ver = ver ? &ver[1] : &ch[1]; 31298766Smarkm if ((ch = strchr(&ch[1], '|')) != NULL) 31398766Smarkm ch[0] = '\0'; 31498766Smarkm printf(", %s", ver); 31598766Smarkm } while (ch != NULL); 31698766Smarkm printf(")"); 31798766Smarkm } 31898766Smarkm printf("\n"); 31998766Smarkm } 32098766Smarkm } else { 321148435Skrion cmp = version_cmp(plist.name, latest); 322131274Seik ver = strrchr(latest, '-'); 323131274Seik ver = ver ? &ver[1] : latest; 32498766Smarkm if (cmp < 0 && OUTPUT('<')) { 325240682Sbapt if (Quiet) 326240682Sbapt printf("%s", tmp); 327240682Sbapt else { 328240682Sbapt printf("%-34s <", tmp); 329240682Sbapt if (Verbose) 330240682Sbapt printf(" needs updating (%s has %s)", source, ver); 331240682Sbapt } 33298766Smarkm printf("\n"); 33398766Smarkm } else if (cmp == 0 && OUTPUT('=')) { 334240682Sbapt if (Quiet) 335240682Sbapt printf("%s", tmp); 336240682Sbapt else { 337240682Sbapt printf("%-34s =", tmp); 338240682Sbapt if (Verbose) 339240682Sbapt printf(" up-to-date with %s", source); 340240682Sbapt } 34198766Smarkm printf("\n"); 34298766Smarkm } else if (cmp > 0 && OUTPUT('>')) { 343240682Sbapt if (Quiet) 344240682Sbapt printf("%s", tmp); 345240682Sbapt else { 346240682Sbapt printf("%-34s >", tmp); 347240682Sbapt if (Verbose) 348240682Sbapt printf(" succeeds %s (%s has %s)", source, source, ver); 349240682Sbapt } 35098766Smarkm printf("\n"); 35198766Smarkm } 35298766Smarkm } 35398766Smarkm} 35498766Smarkm 355131275Seikint 356131275Seikversion_match(char *pattern, const char *pkgname) 357131275Seik{ 358131275Seik int ret = 0; 359131275Seik int matchstream = 0; 360131275Seik FILE *fp = NULL; 361131275Seik Boolean isTMP = FALSE; 362131275Seik 363131275Seik if (isURL(pkgname)) { 364131275Seik fp = fetchGetURL(pkgname, ""); 365131275Seik isTMP = TRUE; 366131275Seik matchstream = 1; 367151200Skrion if (fp == NULL) 368131275Seik errx(2, "Unable to open %s.", pkgname); 369131275Seik } else if (pkgname[0] == '/') { 370131275Seik fp = fopen(pkgname, "r"); 371131275Seik isTMP = TRUE; 372131275Seik matchstream = 1; 373151200Skrion if (fp == NULL) 374131275Seik errx(2, "Unable to open %s.", pkgname); 375131275Seik } else if (strcmp(pkgname, "-") == 0) { 376131275Seik fp = stdin; 377131275Seik matchstream = 1; 378131275Seik } else if (isURL(pattern)) { 379131275Seik fp = fetchGetURL(pattern, ""); 380131275Seik isTMP = TRUE; 381131275Seik matchstream = -1; 382151200Skrion if (fp == NULL) 383131275Seik errx(2, "Unable to open %s.", pattern); 384131275Seik } else if (pattern[0] == '/') { 385131275Seik fp = fopen(pattern, "r"); 386131275Seik isTMP = TRUE; 387131275Seik matchstream = -1; 388151200Skrion if (fp == NULL) 389131275Seik errx(2, "Unable to open %s.", pattern); 390131275Seik } else if (strcmp(pattern, "-") == 0) { 391131275Seik fp = stdin; 392131275Seik matchstream = -1; 393131275Seik } else { 394131275Seik ret = pattern_match(MATCH_GLOB, pattern, pkgname); 395131275Seik } 396131275Seik 397131275Seik if (fp != NULL) { 398131275Seik size_t len; 399131275Seik char *line; 400131275Seik while ((line = fgetln(fp, &len)) != NULL) { 401131275Seik int match; 402131275Seik char *ch, ln[2048]; 403131275Seik size_t lnlen; 404131275Seik if (len > 0 && line[len-1] == '\n') 405131275Seik len --; 406131275Seik lnlen = len; 407131275Seik if (lnlen > sizeof(ln)-1) 408131275Seik lnlen = sizeof(ln)-1; 409131275Seik memcpy(ln, line, lnlen); 410131275Seik ln[lnlen] = '\0'; 411131275Seik if ((ch = strchr(ln, '|')) != NULL) 412131275Seik ch[0] = '\0'; 413131275Seik if (matchstream > 0) 414131275Seik match = pattern_match(MATCH_GLOB, pattern, ln); 415131275Seik else 416131275Seik match = pattern_match(MATCH_GLOB, ln, pkgname); 417131275Seik if (match == 1) { 418131275Seik ret = 1; 419131275Seik printf("%.*s\n", (int)len, line); 420131275Seik } 421131275Seik } 422131275Seik if (isTMP) 423131275Seik fclose(fp); 424131275Seik } 425131275Seik 426131275Seik return ret; 427131275Seik} 428131275Seik 42998766Smarkmvoid 43098766Smarkmcleanup(int sig) 43198766Smarkm{ 43298766Smarkm if (sig) 43398766Smarkm exit(1); 43498766Smarkm} 435