1/* 2 * FreeBSD install - a package for the installation and maintainance 3 * of non-core utilities. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * Jordan K. Hubbard 15 * 23 Aug 1993 16 * 17 * Various display routines for the info module. 18 * 19 */ 20 21#include <sys/cdefs.h> 22__FBSDID("$FreeBSD$"); 23 24#include "lib.h" 25#include "info.h" 26#include <err.h> 27#include <stdlib.h> 28#include <sys/types.h> 29#include <sys/stat.h> 30#include <md5.h> 31 32void 33show_file(const char *title, const char *fname) 34{ 35 FILE *fp; 36 char line[1024]; 37 int n; 38 39 if (!Quiet) 40 printf("%s%s", InfoPrefix, title); 41 fp = fopen(fname, "r"); 42 if (fp == (FILE *) NULL) 43 printf("ERROR: show_file: Can't open '%s' for reading!\n", fname); 44 else { 45 int append_nl = 0; 46 while ((n = fread(line, 1, 1024, fp)) != 0) 47 fwrite(line, 1, n, stdout); 48 fclose(fp); 49 append_nl = (line[n - 1] != '\n'); /* Do we have a trailing \n ? */ 50 if (append_nl) 51 printf("\n"); 52 } 53 printf("\n"); /* just in case */ 54} 55 56void 57show_index(const char *title, const char *fname) 58{ 59 FILE *fp; 60 char line[MAXINDEXSIZE+2]; 61 62 strlcpy(line, "???\n", sizeof(line)); 63 64 if (!Quiet) { 65 printf("%s%s", InfoPrefix, title); 66 fflush(stdout); 67 } 68 fp = fopen(fname, "r"); 69 if (fp == (FILE *) NULL) { 70 warnx("show_file: can't open '%s' for reading", fname); 71 } else { 72 if(fgets(line, MAXINDEXSIZE + 1, fp)) { 73 size_t line_length = strlen(line); 74 75 if (line[line_length - 1] != '\n') { /* Do we have a trailing \n ? */ 76 line[line_length] = '\n'; /* Add a trailing \n */ 77 line[line_length + 1] = '\0'; /* Terminate string */ 78 } 79 } 80 fclose(fp); 81 } 82 fputs(line, stdout); 83} 84 85/* Show a packing list item type. If showall is TRUE, show all */ 86void 87show_plist(const char *title, Package *plist, plist_t type, Boolean showall) 88{ 89 PackingList p; 90 Boolean ign = FALSE; 91 char *prefix = NULL; 92 93 if (!Quiet) { 94 printf("%s%s", InfoPrefix, title); 95 fflush(stdout); 96 } 97 p = plist->head; 98 while (p) { 99 if (p->type != type && showall != TRUE) { 100 p = p->next; 101 continue; 102 } 103 switch(p->type) { 104 case PLIST_FILE: 105 if (ign) { 106 printf(Quiet ? "%s\n" : "File: %s (ignored)\n", p->name); 107 ign = FALSE; 108 } 109 else 110 printf(Quiet ? "%s\n" : "File: %s\n", p->name); 111 break; 112 113 case PLIST_CWD: 114 if (!prefix) 115 prefix = p->name; 116 printf(Quiet ? "@cwd %s\n" : "\tCWD to %s\n", (p->name == NULL) ? prefix : p->name); 117 break; 118 119 case PLIST_SRC: 120 printf(Quiet ? "@srcdir %s\n" : "\tSRCDIR to %s\n", p->name); 121 break; 122 123 case PLIST_CMD: 124 printf(Quiet ? "@exec %s\n" : "\tEXEC '%s'\n", p->name); 125 break; 126 127 case PLIST_UNEXEC: 128 printf(Quiet ? "@unexec %s\n" : "\tUNEXEC '%s'\n", p->name); 129 break; 130 131 case PLIST_CHMOD: 132 printf(Quiet ? "@chmod %s\n" : "\tCHMOD to %s\n", 133 p->name ? p->name : "(clear default)"); 134 break; 135 136 case PLIST_CHOWN: 137 printf(Quiet ? "@chown %s\n" : "\tCHOWN to %s\n", 138 p->name ? p->name : "(clear default)"); 139 break; 140 141 case PLIST_CHGRP: 142 printf(Quiet ? "@chgrp %s\n" : "\tCHGRP to %s\n", 143 p->name ? p->name : "(clear default)"); 144 break; 145 146 case PLIST_COMMENT: 147 printf(Quiet ? "@comment %s\n" : "\tComment: %s\n", p->name); 148 break; 149 150 case PLIST_NOINST: 151 printf(Quiet ? "@noinst %s\n" : "\tNot installed: %s\n", p->name); 152 break; 153 154 case PLIST_IGNORE: 155 ign = TRUE; 156 break; 157 158 case PLIST_IGNORE_INST: 159 printf(Quiet ? "@ignore_inst ??? doesn't belong here.\n" : 160 "\tIgnore next file installation directive (doesn't belong)\n"); 161 ign = TRUE; 162 break; 163 164 case PLIST_NAME: 165 printf(Quiet ? "@name %s\n" : "\tPackage name: %s\n", p->name); 166 break; 167 168 case PLIST_DISPLAY: 169 printf(Quiet ? "@display %s\n" : "\tInstall message file: %s\n", p->name); 170 break; 171 172 case PLIST_PKGDEP: 173 printf(Quiet ? "@pkgdep %s\n" : "Dependency: %s\n", p->name); 174 break; 175 176 case PLIST_DEPORIGIN: 177 printf(Quiet ? "@comment DEPORIGIN:%s\n" : 178 "\tdependency origin: %s\n", p->name); 179 break; 180 181 case PLIST_CONFLICTS: 182 printf(Quiet ? "@conflicts %s\n" : "Conflicts: %s\n", p->name); 183 break; 184 185 case PLIST_MTREE: 186 printf(Quiet ? "@mtree %s\n" : "\tPackage mtree file: %s\n", p->name); 187 break; 188 189 case PLIST_DIR_RM: 190 printf(Quiet ? "@dirrm %s\n" : "\tDeinstall directory remove: %s\n", p->name); 191 break; 192 193 case PLIST_OPTION: 194 printf(Quiet ? "@option %s\n" : 195 "\tOption \"%s\" controlling package installation behaviour\n", 196 p->name); 197 break; 198 199 case PLIST_ORIGIN: 200 printf(Quiet ? "@comment ORIGIN:%s\n" : 201 "\tPackage origin: %s\n", p->name); 202 break; 203 204 default: 205 cleanup(0); 206 errx(2, "%s: unknown command type %d (%s)", 207 __func__, p->type, p->name); 208 break; 209 } 210 p = p->next; 211 } 212} 213 214static const char * 215elide_root(const char *dir) 216{ 217 if (strcmp(dir, "/") == 0) 218 return ""; 219 return dir; 220} 221 222/* Show all files in the packing list (except ignored ones) */ 223void 224show_files(const char *title, Package *plist) 225{ 226 PackingList p; 227 Boolean ign = FALSE; 228 char *prefix = NULL; 229 const char *dir = "."; 230 231 if (!Quiet) 232 printf("%s%s", InfoPrefix, title); 233 p = plist->head; 234 while (p) { 235 switch(p->type) { 236 case PLIST_FILE: 237 if (!ign) 238 printf("%s/%s\n", elide_root(dir), p->name); 239 ign = FALSE; 240 break; 241 242 case PLIST_CWD: 243 if (!prefix) 244 prefix = p->name; 245 if (p->name == NULL) 246 dir = prefix; 247 else 248 dir = p->name; 249 break; 250 251 case PLIST_IGNORE: 252 ign = TRUE; 253 break; 254 255 /* Silence GCC in the -Wall mode */ 256 default: 257 break; 258 } 259 p = p->next; 260 } 261} 262 263/* Calculate and show size of all installed package files (except ignored ones) */ 264void 265show_size(const char *title, Package *plist) 266{ 267 PackingList p; 268 Boolean ign = FALSE; 269 const char *dir = "."; 270 struct stat sb; 271 char tmp[FILENAME_MAX]; 272 unsigned long size = 0; 273 long blksize; 274 int headerlen; 275 char *descr; 276 char *prefix = NULL; 277 278 descr = getbsize(&headerlen, &blksize); 279 if (!Quiet) { 280 printf("%s%s", InfoPrefix, title); 281 fflush(stdout); 282 } 283 for (p = plist->head; p != NULL; p = p->next) { 284 switch (p->type) { 285 case PLIST_FILE: 286 if (!ign) { 287 snprintf(tmp, FILENAME_MAX, "%s/%s", elide_root(dir), p->name); 288 if (!lstat(tmp, &sb)) { 289 size += sb.st_size; 290 if (Verbose) 291 printf("%lu\t%s\n", (unsigned long) howmany(sb.st_size, blksize), tmp); 292 } 293 } 294 ign = FALSE; 295 break; 296 297 case PLIST_CWD: 298 if (!prefix) 299 prefix = p->name; 300 if (p->name == NULL) 301 dir = prefix; 302 else 303 dir = p->name; 304 break; 305 306 case PLIST_IGNORE: 307 ign = TRUE; 308 break; 309 310 /* Silence GCC in the -Wall mode */ 311 default: 312 break; 313 } 314 } 315 if (!Quiet) 316 printf("%lu\t(%s)\n", howmany(size, blksize), descr); 317 else 318 if (UseBlkSz) 319 printf("%lu\n", howmany(size, blksize)); 320 else 321 printf("%lu\n", size); 322} 323 324/* Show files that don't match the recorded checksum */ 325int 326show_cksum(const char *title, Package *plist) 327{ 328 PackingList p; 329 const char *dir = "."; 330 char *prefix = NULL; 331 char tmp[FILENAME_MAX]; 332 int errcode = 0; 333 334 if (!Quiet) { 335 printf("%s%s", InfoPrefix, title); 336 fflush(stdout); 337 } 338 339 for (p = plist->head; p != NULL; p = p->next) 340 if (p->type == PLIST_CWD) { 341 if (!prefix) 342 prefix = p->name; 343 if (p->name == NULL) 344 dir = prefix; 345 else 346 dir = p->name; 347 } else if (p->type == PLIST_FILE) { 348 snprintf(tmp, FILENAME_MAX, "%s/%s", elide_root(dir), p->name); 349 if (!fexists(tmp)) { 350 warnx("%s doesn't exist", tmp); 351 errcode = 1; 352 } else if (p->next && p->next->type == PLIST_COMMENT && 353 (strncmp(p->next->name, "MD5:", 4) == 0)) { 354 char *cp = NULL, buf[33]; 355 356 /* 357 * For packing lists whose version is 1.1 or greater, the md5 358 * hash for a symlink is calculated on the string returned 359 * by readlink(). 360 */ 361 if (issymlink(tmp) && verscmp(plist, 1, 0) > 0) { 362 int len; 363 char linkbuf[FILENAME_MAX]; 364 365 if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0) 366 cp = MD5Data((unsigned char *)linkbuf, len, buf); 367 } else if (isfile(tmp) || verscmp(plist, 1, 1) < 0) 368 cp = MD5File(tmp, buf); 369 370 if (cp != NULL) { 371 /* Mismatch? */ 372 if (strcmp(cp, p->next->name + 4)) 373 printf("%s fails the original MD5 checksum\n", tmp); 374 else if (Verbose) 375 printf("%s matched the original MD5 checksum\n", tmp); 376 } 377 } 378 } 379 return (errcode); 380} 381 382/* Show an "origin" path (usually category/portname) */ 383void 384show_origin(const char *title, Package *plist) 385{ 386 387 if (!Quiet) { 388 printf("%s%s", InfoPrefix, title); 389 fflush(stdout); 390 } 391 printf("%s\n", plist->origin != NULL ? plist->origin : ""); 392} 393 394/* Show revision number of the packing list */ 395void 396show_fmtrev(const char *title, Package *plist) 397{ 398 399 if (!Quiet) { 400 printf("%s%s", InfoPrefix, title); 401 fflush(stdout); 402 } 403 printf("%d.%d\n", plist->fmtver_maj, plist->fmtver_mnr); 404} 405