1 /* 2 * Copyright (c) 2019 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * This code uses concepts and configuration based on 'synth', by 8 * John R. Marino <draco@marino.st>, which was written in ada. 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 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 3. Neither the name of The DragonFly Project nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific, prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 #include "dsynth.h" 38 39 typedef struct pinfo { 40 struct pinfo *next; 41 char *spath; 42 int foundit; 43 } pinfo_t; 44 45 static int pinfocmp(const void *s1, const void *s2); 46 static void scanit(const char *path, const char *subpath, 47 int *countp, pinfo_t ***list_tailp); 48 pinfo_t *pinfofind(pinfo_t **ary, int count, char *spath); 49 static void scandeletenew(const char *path); 50 51 void 52 DoRebuildRepo(int ask) 53 { 54 char *buf; 55 56 if (ask) { 57 if (askyn("Rebuild the repository? ") == 0) 58 return; 59 } 60 61 /* 62 * Scan the repository for temporary .new files and delete them. 63 */ 64 scandeletenew(RepositoryPath); 65 66 /* 67 * Issue the repo command to rebuild the repo 68 */ 69 asprintf(&buf, "pkg repo -o %s %s", PackagesPath, RepositoryPath); 70 printf("Rebuilding repository\n"); 71 if (system(buf)) { 72 printf("Rebuild failed\n"); 73 } else { 74 printf("Rebuild succeeded\n"); 75 } 76 } 77 78 void 79 DoUpgradePkgs(pkg_t *pkgs __unused, int ask __unused) 80 { 81 dfatal("Not Implemented"); 82 } 83 84 void 85 PurgeDistfiles(pkg_t *pkgs) 86 { 87 pinfo_t *list; 88 pinfo_t *item; 89 pinfo_t **list_tail; 90 pinfo_t **ary; 91 char *dstr; 92 char *buf; 93 int count; 94 int delcount; 95 int i; 96 97 printf("Scanning distfiles... "); 98 fflush(stdout); 99 count = 0; 100 list = NULL; 101 list_tail = &list; 102 scanit(DistFilesPath, NULL, &count, &list_tail); 103 printf("Checking %d distfiles\n", count); 104 fflush(stdout); 105 106 ary = calloc(count, sizeof(pinfo_t *)); 107 for (i = 0; i < count; ++i) { 108 ary[i] = list; 109 list = list->next; 110 } 111 ddassert(list == NULL); 112 qsort(ary, count, sizeof(pinfo_t *), pinfocmp); 113 114 for (; pkgs; pkgs = pkgs->bnext) { 115 if (pkgs->distfiles == NULL || pkgs->distfiles[0] == 0) 116 continue; 117 ddprintf(0, "distfiles %s\n", pkgs->distfiles); 118 dstr = strtok(pkgs->distfiles, " \t"); 119 while (dstr) { 120 for (;;) { 121 if (pkgs->distsubdir) { 122 asprintf(&buf, "%s/%s", 123 pkgs->distsubdir, dstr); 124 item = pinfofind(ary, count, buf); 125 ddprintf(0, "TEST %s %p\n", buf, item); 126 free(buf); 127 buf = NULL; 128 } else { 129 item = pinfofind(ary, count, dstr); 130 ddprintf(0, "TEST %s %p\n", dstr, item); 131 } 132 if (item) { 133 item->foundit = 1; 134 break; 135 } 136 if (strrchr(dstr, ':') == NULL) 137 break; 138 *strrchr(dstr, ':') = 0; 139 } 140 dstr = strtok(NULL, " \t"); 141 } 142 } 143 144 delcount = 0; 145 for (i = 0; i < count; ++i) { 146 item = ary[i]; 147 if (item->foundit == 0) { 148 ++delcount; 149 } 150 } 151 if (askyn("Delete %d of %d items? ", delcount, count)) { 152 printf("Deleting %d/%d obsolete source distfiles\n", 153 delcount, count); 154 for (i = 0; i < count; ++i) { 155 item = ary[i]; 156 if (item->foundit == 0) { 157 asprintf(&buf, "%s/%s", 158 DistFilesPath, item->spath); 159 if (remove(buf) < 0) 160 printf("Cannot delete %s\n", buf); 161 free(buf); 162 } 163 } 164 } 165 166 167 free(ary); 168 } 169 170 void 171 RemovePackages(pkg_t *pkgs __unused) 172 { 173 dfatal("Not Implemented"); 174 } 175 176 static int 177 pinfocmp(const void *s1, const void *s2) 178 { 179 const pinfo_t *item1 = *(const pinfo_t *const*)s1; 180 const pinfo_t *item2 = *(const pinfo_t *const*)s2; 181 182 return (strcmp(item1->spath, item2->spath)); 183 } 184 185 pinfo_t * 186 pinfofind(pinfo_t **ary, int count, char *spath) 187 { 188 pinfo_t *item; 189 int res; 190 int b; 191 int e; 192 int m; 193 194 b = 0; 195 e = count; 196 while (b != e) { 197 m = b + (e - b) / 2; 198 item = ary[m]; 199 res = strcmp(spath, item->spath); 200 if (res == 0) 201 return item; 202 if (res < 0) { 203 e = m; 204 } else { 205 b = m + 1; 206 } 207 } 208 return NULL; 209 } 210 211 void 212 scanit(const char *path, const char *subpath, 213 int *countp, pinfo_t ***list_tailp) 214 { 215 struct dirent *den; 216 pinfo_t *item; 217 char *npath; 218 char *spath; 219 DIR *dir; 220 struct stat st; 221 222 if ((dir = opendir(path)) != NULL) { 223 while ((den = readdir(dir)) != NULL) { 224 if (den->d_namlen == 1 && den->d_name[0] == '.') 225 continue; 226 if (den->d_namlen == 2 && den->d_name[0] == '.' && 227 den->d_name[1] == '.') 228 continue; 229 asprintf(&npath, "%s/%s", path, den->d_name); 230 if (lstat(npath, &st) < 0) { 231 free(npath); 232 continue; 233 } 234 if (S_ISDIR(st.st_mode)) { 235 if (subpath) { 236 asprintf(&spath, "%s/%s", 237 subpath, den->d_name); 238 scanit(npath, spath, 239 countp, list_tailp); 240 free(spath); 241 } else { 242 scanit(npath, den->d_name, 243 countp, list_tailp); 244 } 245 } else if (S_ISREG(st.st_mode)) { 246 item = calloc(1, sizeof(*item)); 247 if (subpath) { 248 asprintf(&item->spath, "%s/%s", 249 subpath, den->d_name); 250 } else { 251 item->spath = strdup(den->d_name); 252 } 253 **list_tailp = item; 254 *list_tailp = &item->next; 255 ++*countp; 256 ddprintf(0, "scan %s\n", item->spath); 257 } 258 free(npath); 259 } 260 closedir(dir); 261 } 262 } 263 264 /* 265 * This removes any .new files left over in the repo. These can wind 266 * being left around when dsynth is killed. 267 */ 268 static void 269 scandeletenew(const char *path) 270 { 271 struct dirent *den; 272 const char *ptr; 273 DIR *dir; 274 char *buf; 275 276 if ((dir = opendir(path)) == NULL) 277 dfatal_errno("Cannot scan directory %s", path); 278 while ((den = readdir(dir)) != NULL) { 279 if ((ptr = strrchr(den->d_name, '.')) != NULL && 280 strcmp(ptr, ".new") == 0) { 281 asprintf(&buf, "%s/%s", path, den->d_name); 282 if (remove(buf) < 0) 283 dfatal_errno("remove: Garbage %s\n", buf); 284 printf("Deleted Garbage %s\n", buf); 285 free(buf); 286 } 287 } 288 closedir(dir); 289 } 290