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