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 void removePackagesMetaRecurse(pkg_t *pkg); 46 static int pinfocmp(const void *s1, const void *s2); 47 static void scanit(const char *path, const char *subpath, 48 int *countp, pinfo_t ***list_tailp); 49 pinfo_t *pinfofind(pinfo_t **ary, int count, char *spath); 50 static void childRebuildRepo(bulk_t *bulk); 51 static void scandeletenew(const char *path); 52 53 static void rebuildTerminateSignal(int signo); 54 55 static char *RebuildRemovePath; 56 57 void 58 DoRebuildRepo(int ask) 59 { 60 bulk_t *bulk; 61 FILE *fp; 62 int fd; 63 char tpath[256]; 64 const char *sufx; 65 66 if (ask) { 67 if (askyn("Rebuild the repository? ") == 0) 68 return; 69 } 70 71 /* 72 * Scan the repository for temporary .new files and delete them. 73 */ 74 scandeletenew(RepositoryPath); 75 76 /* 77 * Generate temporary file 78 */ 79 snprintf(tpath, sizeof(tpath), "/tmp/meta.XXXXXXXX.conf"); 80 81 signal(SIGTERM, rebuildTerminateSignal); 82 signal(SIGINT, rebuildTerminateSignal); 83 signal(SIGHUP, rebuildTerminateSignal); 84 85 RebuildRemovePath = tpath; 86 87 sufx = USE_PKG_SUFX; 88 fd = mkostemps(tpath, 5, 0); 89 if (fd < 0) 90 dfatal_errno("Cannot create %s", tpath); 91 fp = fdopen(fd, "w"); 92 fprintf(fp, "version = 1;\n"); 93 fprintf(fp, "packing_format = \"%s\";\n", sufx + 1); 94 fclose(fp); 95 96 /* 97 * Run the operation under our bulk infrastructure to 98 * get the correct environment. 99 */ 100 initbulk(childRebuildRepo, 1); 101 queuebulk(tpath, NULL, NULL, NULL); 102 bulk = getbulk(); 103 104 if (bulk->r1) 105 printf("Rebuild succeeded\n"); 106 else 107 printf("Rebuild failed\n"); 108 donebulk(); 109 110 remove(tpath); 111 } 112 113 static void 114 childRebuildRepo(bulk_t *bulk) 115 { 116 FILE *fp; 117 char *ptr; 118 size_t len; 119 pid_t pid; 120 const char *cav[MAXCAC]; 121 int cac; 122 123 cac = 0; 124 cav[cac++] = PKG_BINARY; 125 cav[cac++] = "repo"; 126 cav[cac++] = "-m"; 127 cav[cac++] = bulk->s1; 128 cav[cac++] = "-o"; 129 cav[cac++] = PackagesPath; 130 cav[cac++] = RepositoryPath; 131 132 printf("pkg repo -m %s -o %s %s\n", 133 bulk->s1, PackagesPath, RepositoryPath); 134 135 fp = dexec_open(cav, cac, &pid, NULL, 1, 0); 136 while ((ptr = fgetln(fp, &len)) != NULL) 137 fwrite(ptr, 1, len, stdout); 138 if (dexec_close(fp, pid) == 0) { 139 bulk->r1 = strdup(""); 140 } 141 } 142 143 void 144 DoUpgradePkgs(pkg_t *pkgs __unused, int ask __unused) 145 { 146 dfatal("Not Implemented"); 147 } 148 149 void 150 PurgeDistfiles(pkg_t *pkgs) 151 { 152 pinfo_t *list; 153 pinfo_t *item; 154 pinfo_t **list_tail; 155 pinfo_t **ary; 156 char *dstr; 157 char *buf; 158 int count; 159 int delcount; 160 int i; 161 162 printf("Scanning distfiles... "); 163 fflush(stdout); 164 count = 0; 165 list = NULL; 166 list_tail = &list; 167 scanit(DistFilesPath, NULL, &count, &list_tail); 168 printf("Checking %d distfiles\n", count); 169 fflush(stdout); 170 171 ary = calloc(count, sizeof(pinfo_t *)); 172 for (i = 0; i < count; ++i) { 173 ary[i] = list; 174 list = list->next; 175 } 176 ddassert(list == NULL); 177 qsort(ary, count, sizeof(pinfo_t *), pinfocmp); 178 179 for (; pkgs; pkgs = pkgs->bnext) { 180 if (pkgs->distfiles == NULL || pkgs->distfiles[0] == 0) 181 continue; 182 ddprintf(0, "distfiles %s\n", pkgs->distfiles); 183 dstr = strtok(pkgs->distfiles, " \t"); 184 while (dstr) { 185 for (;;) { 186 if (pkgs->distsubdir) { 187 asprintf(&buf, "%s/%s", 188 pkgs->distsubdir, dstr); 189 item = pinfofind(ary, count, buf); 190 ddprintf(0, "TEST %s %p\n", buf, item); 191 free(buf); 192 buf = NULL; 193 } else { 194 item = pinfofind(ary, count, dstr); 195 ddprintf(0, "TEST %s %p\n", dstr, item); 196 } 197 if (item) { 198 item->foundit = 1; 199 break; 200 } 201 if (strrchr(dstr, ':') == NULL) 202 break; 203 *strrchr(dstr, ':') = 0; 204 } 205 dstr = strtok(NULL, " \t"); 206 } 207 } 208 209 delcount = 0; 210 for (i = 0; i < count; ++i) { 211 item = ary[i]; 212 if (item->foundit == 0) { 213 ++delcount; 214 } 215 } 216 if (askyn("Delete %d of %d items? ", delcount, count)) { 217 printf("Deleting %d/%d obsolete source distfiles\n", 218 delcount, count); 219 for (i = 0; i < count; ++i) { 220 item = ary[i]; 221 if (item->foundit == 0) { 222 asprintf(&buf, "%s/%s", 223 DistFilesPath, item->spath); 224 if (remove(buf) < 0) 225 printf("Cannot delete %s\n", buf); 226 free(buf); 227 } 228 } 229 } 230 231 232 free(ary); 233 } 234 235 void 236 RemovePackages(pkg_t *list) 237 { 238 pkg_t *scan; 239 char *path; 240 241 for (scan = list; scan; scan = scan->bnext) { 242 if ((scan->flags & PKGF_MANUALSEL) == 0) 243 continue; 244 if (scan->pkgfile) { 245 scan->flags &= ~PKGF_PACKAGED; 246 scan->pkgfile_size = 0; 247 asprintf(&path, "%s/%s", RepositoryPath, scan->pkgfile); 248 if (remove(path) == 0) 249 printf("Removed: %s\n", path); 250 free(path); 251 } 252 if (scan->pkgfile == NULL || 253 (scan->flags & (PKGF_DUMMY | PKGF_META))) { 254 removePackagesMetaRecurse(scan); 255 } 256 } 257 } 258 259 static void 260 removePackagesMetaRecurse(pkg_t *pkg) 261 { 262 pkglink_t *link; 263 pkg_t *scan; 264 char *path; 265 266 PKGLIST_FOREACH(link, &pkg->idepon_list) { 267 scan = link->pkg; 268 if (scan == NULL) 269 continue; 270 if (scan->pkgfile == NULL || 271 (scan->flags & (PKGF_DUMMY | PKGF_META))) { 272 removePackagesMetaRecurse(scan); 273 continue; 274 } 275 scan->flags &= ~PKGF_PACKAGED; 276 scan->pkgfile_size = 0; 277 278 asprintf(&path, "%s/%s", RepositoryPath, scan->pkgfile); 279 if (remove(path) == 0) 280 printf("Removed: %s\n", path); 281 free(path); 282 } 283 } 284 285 static int 286 pinfocmp(const void *s1, const void *s2) 287 { 288 const pinfo_t *item1 = *(const pinfo_t *const*)s1; 289 const pinfo_t *item2 = *(const pinfo_t *const*)s2; 290 291 return (strcmp(item1->spath, item2->spath)); 292 } 293 294 pinfo_t * 295 pinfofind(pinfo_t **ary, int count, char *spath) 296 { 297 pinfo_t *item; 298 int res; 299 int b; 300 int e; 301 int m; 302 303 b = 0; 304 e = count; 305 while (b != e) { 306 m = b + (e - b) / 2; 307 item = ary[m]; 308 res = strcmp(spath, item->spath); 309 if (res == 0) 310 return item; 311 if (res < 0) { 312 e = m; 313 } else { 314 b = m + 1; 315 } 316 } 317 return NULL; 318 } 319 320 void 321 scanit(const char *path, const char *subpath, 322 int *countp, pinfo_t ***list_tailp) 323 { 324 struct dirent *den; 325 pinfo_t *item; 326 char *npath; 327 char *spath; 328 DIR *dir; 329 struct stat st; 330 331 if ((dir = opendir(path)) != NULL) { 332 while ((den = readdir(dir)) != NULL) { 333 if (den->d_namlen == 1 && den->d_name[0] == '.') 334 continue; 335 if (den->d_namlen == 2 && den->d_name[0] == '.' && 336 den->d_name[1] == '.') 337 continue; 338 asprintf(&npath, "%s/%s", path, den->d_name); 339 if (lstat(npath, &st) < 0) { 340 free(npath); 341 continue; 342 } 343 if (S_ISDIR(st.st_mode)) { 344 if (subpath) { 345 asprintf(&spath, "%s/%s", 346 subpath, den->d_name); 347 scanit(npath, spath, 348 countp, list_tailp); 349 free(spath); 350 } else { 351 scanit(npath, den->d_name, 352 countp, list_tailp); 353 } 354 } else if (S_ISREG(st.st_mode)) { 355 item = calloc(1, sizeof(*item)); 356 if (subpath) { 357 asprintf(&item->spath, "%s/%s", 358 subpath, den->d_name); 359 } else { 360 item->spath = strdup(den->d_name); 361 } 362 **list_tailp = item; 363 *list_tailp = &item->next; 364 ++*countp; 365 ddprintf(0, "scan %s\n", item->spath); 366 } 367 free(npath); 368 } 369 closedir(dir); 370 } 371 } 372 373 /* 374 * This removes any .new files left over in the repo. These can wind 375 * being left around when dsynth is killed. 376 */ 377 static void 378 scandeletenew(const char *path) 379 { 380 struct dirent *den; 381 const char *ptr; 382 DIR *dir; 383 char *buf; 384 385 if ((dir = opendir(path)) == NULL) 386 dfatal_errno("Cannot scan directory %s", path); 387 while ((den = readdir(dir)) != NULL) { 388 if ((ptr = strrchr(den->d_name, '.')) != NULL && 389 strcmp(ptr, ".new") == 0) { 390 asprintf(&buf, "%s/%s", path, den->d_name); 391 if (remove(buf) < 0) 392 dfatal_errno("remove: Garbage %s\n", buf); 393 printf("Deleted Garbage %s\n", buf); 394 free(buf); 395 } 396 } 397 closedir(dir); 398 } 399 400 static void 401 rebuildTerminateSignal(int signo __unused) 402 { 403 if (RebuildRemovePath) 404 remove(RebuildRemovePath); 405 exit(1); 406 407 } 408