4#endif 5 6/* 7 * 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 * Maxim Sobolev 20 * 14 March 2001 21 * 22 * Routines used to do various operations with dependencies 23 * among installed packages. 24 * 25 */ 26 27#include "lib.h" 28#include <err.h> 29#include <stdio.h> 30 31/* 32 * Sort given NULL-terminated list of installed packages (pkgs) in 33 * such a way that if package A depends on package B then after 34 * sorting A will be listed before B no matter how they were 35 * originally positioned in the list. 36 */ 37int 38sortdeps(char **pkgs) 39{ 40 char *tmp; 41 int i, j, loop_cnt; 42 int err_cnt = 0; 43 44 for (i = 0; pkgs[i]; i++) { 45 /* 46 * Check to see if any other package in pkgs[i+1:] depends 47 * on pkgs[i] and swap those two packages if so. 48 */ 49 loop_cnt = 0; 50 for (j = i + 1; pkgs[j]; j++) { 51 if (chkifdepends(pkgs[j], pkgs[i]) == 1) { 52 /* 53 * Try to avoid deadlock if package A depends on B which in 54 * turn depends on C and C due to an error depends on A. 55 * Use ugly but simple method, becase it Should Never 56 * Happen[tm] in the real life anyway. 57 */ 58 if (loop_cnt > 4096) { 59 warnx("dependency loop detected for package %s", pkgs[j]); 60 err_cnt++; 61 break; 62 } 63 loop_cnt++; 64 tmp = pkgs[i]; 65 pkgs[i] = pkgs[j]; 66 pkgs[j] = tmp; 67 /* 68 * Another iteration requred to check if new pkgs[i] 69 * itself has any packages that depend on it 70 */ 71 j = i + 1; 72 } 73 } 74 } 75 return err_cnt; 76} 77 78/* 79 * Check to see if pkgname1 depends on pkgname2. 80 * Returns 1 if depends, 0 if not, and -1 if error occured. 81 */ 82int
|
84{ 85 char pkgdir[FILENAME_MAX]; 86 int errcode; 87 struct reqr_by_entry *rb_entry; 88 struct reqr_by_head *rb_list; 89 90 /* Check that pkgname2 is actually installed */ 91 snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, pkgname2); 92 if (!isdir(pkgdir)) 93 return 0; 94 95 errcode = requiredby(pkgname2, &rb_list, FALSE, TRUE); 96 if (errcode < 0) 97 return errcode; 98 99 STAILQ_FOREACH(rb_entry, rb_list, link) 100 if (strcmp(rb_entry->pkgname, pkgname1) == 0) /* match */ 101 return 1; 102 103 return 0; 104} 105 106/* 107 * Load +REQUIRED_BY file and return a list with names of 108 * packages that require package reffered to by `pkgname'. 109 * 110 * Optionally check that packages listed there are actually 111 * installed and filter out those that don't (filter == TRUE). 112 * 113 * strict argument controls whether the caller want warnings 114 * to be emitted when there are some non-fatal conditions, 115 * i.e. package doesn't have +REQUIRED_BY file or some packages 116 * listed in +REQUIRED_BY don't exist. 117 * 118 * Result returned in the **list, while return value is equal 119 * to the number of entries in the resulting list. Print error 120 * message and return -1 on error. 121 */ 122int 123requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter) 124{ 125 FILE *fp; 126 char fbuf[FILENAME_MAX], fname[FILENAME_MAX], pkgdir[FILENAME_MAX]; 127 int retval; 128 struct reqr_by_entry *rb_entry; 129 static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list); 130 131 *list = &rb_list; 132 /* Deallocate any previously allocated space */ 133 while (!STAILQ_EMPTY(&rb_list)) { 134 rb_entry = STAILQ_FIRST(&rb_list); 135 STAILQ_REMOVE_HEAD(&rb_list, link); 136 free(rb_entry); 137 } 138 139 snprintf(fname, sizeof(fname), "%s/%s", LOG_DIR, pkgname); 140 if (!isdir(fname)) { 141 if (strict == TRUE) 142 warnx("no such package '%s' installed", pkgname); 143 return -1; 144 } 145 146 snprintf(fname, sizeof(fname), "%s/%s", fname, REQUIRED_BY_FNAME); 147 fp = fopen(fname, "r"); 148 if (fp == NULL) { 149 /* Probably pkgname doesn't have any packages that depend on it */ 150 if (strict == TRUE) 151 warnx("couldn't open dependency file '%s'", fname); 152 return 0; 153 } 154 155 retval = 0; 156 while (fgets(fbuf, sizeof(fbuf), fp) != NULL) { 157 if (fbuf[strlen(fbuf) - 1] == '\n') 158 fbuf[strlen(fbuf) - 1] = '\0'; 159 snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, fbuf); 160 if (filter == TRUE && !isdir(pkgdir)) { 161 if (strict == TRUE) 162 warnx("package '%s' is recorded in the '%s' but isn't " 163 "actually installed", fbuf, fname); 164 continue; 165 } 166 retval++; 167 rb_entry = malloc(sizeof(*rb_entry)); 168 if (rb_entry == NULL) { 169 warnx("%s(): malloc() failed", __FUNCTION__); 170 retval = -1; 171 break; 172 } 173 strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname)); 174 STAILQ_INSERT_TAIL(&rb_list, rb_entry, link); 175 } 176 fclose(fp); 177 178 return retval; 179}
|