xref: /dragonfly/usr.bin/dsynth/repo.c (revision c819d181)
18e25f19bSMatthew Dillon /*
26ec1f604SMatthew Dillon  * Copyright (c) 2019-2020 The DragonFly Project.  All rights reserved.
38e25f19bSMatthew Dillon  *
48e25f19bSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
58e25f19bSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
68e25f19bSMatthew Dillon  *
78e25f19bSMatthew Dillon  * This code uses concepts and configuration based on 'synth', by
88e25f19bSMatthew Dillon  * John R. Marino <draco@marino.st>, which was written in ada.
98e25f19bSMatthew Dillon  *
108e25f19bSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
118e25f19bSMatthew Dillon  * modification, are permitted provided that the following conditions
128e25f19bSMatthew Dillon  * are met:
138e25f19bSMatthew Dillon  *
148e25f19bSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
158e25f19bSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
168e25f19bSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
178e25f19bSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
188e25f19bSMatthew Dillon  *    the documentation and/or other materials provided with the
198e25f19bSMatthew Dillon  *    distribution.
208e25f19bSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
218e25f19bSMatthew Dillon  *    contributors may be used to endorse or promote products derived
228e25f19bSMatthew Dillon  *    from this software without specific, prior written permission.
238e25f19bSMatthew Dillon  *
248e25f19bSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
258e25f19bSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
268e25f19bSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
278e25f19bSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
288e25f19bSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
298e25f19bSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
308e25f19bSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
318e25f19bSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
328e25f19bSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
338e25f19bSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
348e25f19bSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
358e25f19bSMatthew Dillon  * SUCH DAMAGE.
368e25f19bSMatthew Dillon  */
378e25f19bSMatthew Dillon #include "dsynth.h"
386ec1f604SMatthew Dillon #include <openssl/md5.h>
398e25f19bSMatthew Dillon 
401645cafeSMatthew Dillon typedef struct pinfo {
411645cafeSMatthew Dillon 	struct pinfo *next;
421645cafeSMatthew Dillon 	char *spath;
431645cafeSMatthew Dillon 	int foundit;
446ec1f604SMatthew Dillon 	int inlocks;
451645cafeSMatthew Dillon } pinfo_t;
461645cafeSMatthew Dillon 
47f4094b20SMatthew Dillon static void removePackagesMetaRecurse(pkg_t *pkg);
481645cafeSMatthew Dillon static int pinfocmp(const void *s1, const void *s2);
491645cafeSMatthew Dillon static void scanit(const char *path, const char *subpath,
506ec1f604SMatthew Dillon 			int *countp, pinfo_t ***list_tailp,
516ec1f604SMatthew Dillon 			int inlocks);
521645cafeSMatthew Dillon pinfo_t *pinfofind(pinfo_t **ary, int count, char *spath);
53066daf2aSMatthew Dillon static void childRebuildRepo(bulk_t *bulk);
54f7f25838SMatthew Dillon static void scandeletenew(const char *path);
551645cafeSMatthew Dillon 
56066daf2aSMatthew Dillon static void rebuildTerminateSignal(int signo);
576ec1f604SMatthew Dillon static char *md5lkfile(char *rpath, int which);
586ec1f604SMatthew Dillon static int lkdircount(char *buf);
59066daf2aSMatthew Dillon 
60066daf2aSMatthew Dillon static char *RebuildRemovePath;
61066daf2aSMatthew Dillon 
628e25f19bSMatthew Dillon void
DoRebuildRepo(int ask)631645cafeSMatthew Dillon DoRebuildRepo(int ask)
648e25f19bSMatthew Dillon {
65066daf2aSMatthew Dillon 	bulk_t *bulk;
66066daf2aSMatthew Dillon 	FILE *fp;
67066daf2aSMatthew Dillon 	int fd;
68066daf2aSMatthew Dillon 	char tpath[256];
6968dc2eeaSMatthew Dillon 	const char *sufx;
701645cafeSMatthew Dillon 
711645cafeSMatthew Dillon 	if (ask) {
721645cafeSMatthew Dillon 		if (askyn("Rebuild the repository? ") == 0)
731645cafeSMatthew Dillon 			return;
741645cafeSMatthew Dillon 	}
75f7f25838SMatthew Dillon 
76f7f25838SMatthew Dillon 	/*
77f7f25838SMatthew Dillon 	 * Scan the repository for temporary .new files and delete them.
78f7f25838SMatthew Dillon 	 */
79f7f25838SMatthew Dillon 	scandeletenew(RepositoryPath);
80f7f25838SMatthew Dillon 
81f7f25838SMatthew Dillon 	/*
82066daf2aSMatthew Dillon 	 * Generate temporary file
83f7f25838SMatthew Dillon 	 */
84066daf2aSMatthew Dillon 	snprintf(tpath, sizeof(tpath), "/tmp/meta.XXXXXXXX.conf");
85066daf2aSMatthew Dillon 
86066daf2aSMatthew Dillon 	signal(SIGTERM, rebuildTerminateSignal);
87066daf2aSMatthew Dillon 	signal(SIGINT, rebuildTerminateSignal);
88066daf2aSMatthew Dillon 	signal(SIGHUP, rebuildTerminateSignal);
89066daf2aSMatthew Dillon 
90066daf2aSMatthew Dillon 	RebuildRemovePath = tpath;
91066daf2aSMatthew Dillon 
92483dbac9SMatthew Dillon 	sufx = UsePkgSufx;
93066daf2aSMatthew Dillon 	fd = mkostemps(tpath, 5, 0);
94066daf2aSMatthew Dillon 	if (fd < 0)
95066daf2aSMatthew Dillon 		dfatal_errno("Cannot create %s", tpath);
96066daf2aSMatthew Dillon 	fp = fdopen(fd, "w");
97*6a7ba689SMatthew Dillon 	fprintf(fp, "version = %d;\n", MetaVersion);
9868dc2eeaSMatthew Dillon 	fprintf(fp, "packing_format = \"%s\";\n", sufx + 1);
99066daf2aSMatthew Dillon 	fclose(fp);
100066daf2aSMatthew Dillon 
101066daf2aSMatthew Dillon 	/*
102066daf2aSMatthew Dillon 	 * Run the operation under our bulk infrastructure to
103066daf2aSMatthew Dillon 	 * get the correct environment.
104066daf2aSMatthew Dillon 	 */
105066daf2aSMatthew Dillon 	initbulk(childRebuildRepo, 1);
106066daf2aSMatthew Dillon 	queuebulk(tpath, NULL, NULL, NULL);
107066daf2aSMatthew Dillon 	bulk = getbulk();
108066daf2aSMatthew Dillon 
109066daf2aSMatthew Dillon 	if (bulk->r1)
1101645cafeSMatthew Dillon 		printf("Rebuild succeeded\n");
111066daf2aSMatthew Dillon 	else
112066daf2aSMatthew Dillon 		printf("Rebuild failed\n");
113066daf2aSMatthew Dillon 	donebulk();
114066daf2aSMatthew Dillon 
115066daf2aSMatthew Dillon 	remove(tpath);
116066daf2aSMatthew Dillon }
117066daf2aSMatthew Dillon 
118066daf2aSMatthew Dillon static void
1197f2422cfSMatthew Dillon repackage(const char *basepath, const char *basefile,
1207f2422cfSMatthew Dillon 	  const char *decomp_suffix, const char *comp_suffix,
1217f2422cfSMatthew Dillon 	  const char *decomp, const char *comp);
122cda252a4SMatthew Dillon 
123cda252a4SMatthew Dillon static void
childRebuildRepo(bulk_t * bulk)124066daf2aSMatthew Dillon childRebuildRepo(bulk_t *bulk)
125066daf2aSMatthew Dillon {
126066daf2aSMatthew Dillon 	FILE *fp;
127066daf2aSMatthew Dillon 	char *ptr;
128066daf2aSMatthew Dillon 	size_t len;
129066daf2aSMatthew Dillon 	pid_t pid;
130066daf2aSMatthew Dillon 	const char *cav[MAXCAC];
131753e4c44SMatthew Dillon 	char *pkg_path;
132066daf2aSMatthew Dillon 	int cac;
1337f2422cfSMatthew Dillon 	int repackage_mode = 0;
134066daf2aSMatthew Dillon 
135753e4c44SMatthew Dillon 	/*
136753e4c44SMatthew Dillon 	 * We have to use the pkg-static that we built as part of the
137753e4c44SMatthew Dillon 	 * build process to rebuild the repo because the system pkg might
138753e4c44SMatthew Dillon 	 * not be compatible with the repo format changes made in 1.17.
139753e4c44SMatthew Dillon 	 */
140753e4c44SMatthew Dillon 	asprintf(&pkg_path, "%s/Template/usr/local/sbin/pkg-static", BuildBase);
141753e4c44SMatthew Dillon 
142066daf2aSMatthew Dillon 	cac = 0;
143753e4c44SMatthew Dillon 	cav[cac++] = pkg_path;
144066daf2aSMatthew Dillon 	cav[cac++] = "repo";
145066daf2aSMatthew Dillon 	cav[cac++] = "-m";
146066daf2aSMatthew Dillon 	cav[cac++] = bulk->s1;
147066daf2aSMatthew Dillon 	cav[cac++] = "-o";
148066daf2aSMatthew Dillon 	cav[cac++] = PackagesPath;
149cda252a4SMatthew Dillon 
150cda252a4SMatthew Dillon 	/*
151cda252a4SMatthew Dillon 	 * The yaml needs to generate paths relative to PackagePath
152cda252a4SMatthew Dillon 	 */
153cda252a4SMatthew Dillon 	if (strncmp(PackagesPath, RepositoryPath, strlen(PackagesPath)) == 0)
154cda252a4SMatthew Dillon 		cav[cac++] = PackagesPath;
155cda252a4SMatthew Dillon 	else
156066daf2aSMatthew Dillon 		cav[cac++] = RepositoryPath;
157066daf2aSMatthew Dillon 
158cda252a4SMatthew Dillon 	printf("pkg repo -m %s -o %s %s\n", bulk->s1, cav[cac-2], cav[cac-1]);
159066daf2aSMatthew Dillon 
160f9d29536SMatthew Dillon 	fp = dexec_open(NULL, cav, cac, &pid, NULL, 1, 0);
161066daf2aSMatthew Dillon 	while ((ptr = fgetln(fp, &len)) != NULL)
162066daf2aSMatthew Dillon 		fwrite(ptr, 1, len, stdout);
16396cc8f92SMatthew Dillon 	if (dexec_close(fp, pid) == 0)
164066daf2aSMatthew Dillon 		bulk->r1 = strdup("");
16596cc8f92SMatthew Dillon 
16696cc8f92SMatthew Dillon 	/*
16796cc8f92SMatthew Dillon 	 * Check package version.  Pkg version 1.12 and later generates
16896cc8f92SMatthew Dillon 	 * the proper repo compression format.  Prior to that version
16996cc8f92SMatthew Dillon 	 * the repo directive always generated .txz files.
17096cc8f92SMatthew Dillon 	 */
17196cc8f92SMatthew Dillon 	cac = 0;
172753e4c44SMatthew Dillon 	cav[cac++] = pkg_path;
17396cc8f92SMatthew Dillon 	cav[cac++] = "-v";
174f9d29536SMatthew Dillon 	fp = dexec_open(NULL, cav, cac, &pid, NULL, 1, 0);
17596cc8f92SMatthew Dillon 	if ((ptr = fgetln(fp, &len)) != NULL && len > 0) {
17696cc8f92SMatthew Dillon 		int v1;
17796cc8f92SMatthew Dillon 		int v2;
17896cc8f92SMatthew Dillon 
17996cc8f92SMatthew Dillon 		ptr[len-1] = 0;
18096cc8f92SMatthew Dillon 		if (sscanf(ptr, "%d.%d", &v1, &v2) == 2) {
181753e4c44SMatthew Dillon 			printf("pkg repo - pkg version: %d.%d\n", v1, v2);
18296cc8f92SMatthew Dillon 			if (v1 > 1 || (v1 == 1 && v2 >= 12))
1837f2422cfSMatthew Dillon 				repackage_mode = 1;
1841645cafeSMatthew Dillon 		}
18596cc8f92SMatthew Dillon 	}
18696cc8f92SMatthew Dillon 	dexec_close(fp, pid);
187cda252a4SMatthew Dillon 
188cda252a4SMatthew Dillon 	/*
189cda252a4SMatthew Dillon 	 * Repackage the .txz files created by pkg repo if necessary
190cda252a4SMatthew Dillon 	 */
1917f2422cfSMatthew Dillon 	if (repackage_mode == 0 && strcmp(UsePkgSufx, ".txz") != 0) {
192cda252a4SMatthew Dillon 		const char *comp;
193cda252a4SMatthew Dillon 		const char *decomp;
194cda252a4SMatthew Dillon 
1957f2422cfSMatthew Dillon 		printf("pkg repo - recompressing digests and packagesite\n");
19696cc8f92SMatthew Dillon 
197483dbac9SMatthew Dillon 		if (strcmp(UsePkgSufx, ".tar") == 0) {
198cda252a4SMatthew Dillon 			decomp = "unxz";
199cda252a4SMatthew Dillon 			comp = "cat";
200483dbac9SMatthew Dillon 		} else if (strcmp(UsePkgSufx, ".tgz") == 0) {
201cda252a4SMatthew Dillon 			decomp = "unxz";
202cda252a4SMatthew Dillon 			comp = "gzip";
203483dbac9SMatthew Dillon 		} else if (strcmp(UsePkgSufx, ".tbz") == 0) {
204cda252a4SMatthew Dillon 			decomp = "unxz";
205cda252a4SMatthew Dillon 			comp = "bzip";
206ef0c0bf5SKrzysztof Piecuch 		} else if (strcmp(UsePkgSufx, ".tzst") == 0) {
207ef0c0bf5SKrzysztof Piecuch 			decomp = "unxz";
208ef0c0bf5SKrzysztof Piecuch 			comp = "zstd";
209cda252a4SMatthew Dillon 		} else {
2107f2422cfSMatthew Dillon 			dfatal("recompressing as %s not supported",
2117f2422cfSMatthew Dillon 			       UsePkgSufx);
212cda252a4SMatthew Dillon 			decomp = "unxz";
213cda252a4SMatthew Dillon 			comp = "cat";
214cda252a4SMatthew Dillon 		}
2157f2422cfSMatthew Dillon 		repackage(PackagesPath, "digests",
2167f2422cfSMatthew Dillon 			  ".txz", UsePkgSufx,
2177f2422cfSMatthew Dillon 			  decomp, comp);
2187f2422cfSMatthew Dillon 		repackage(PackagesPath, "packagesite",
2197f2422cfSMatthew Dillon 			  ".txz", UsePkgSufx,
2207f2422cfSMatthew Dillon 			  decomp, comp);
2217f2422cfSMatthew Dillon 	} else if (repackage_mode == 1 && strcmp(UsePkgSufx, ".txz") != 0) {
2227f2422cfSMatthew Dillon 		const char *comp;
2237f2422cfSMatthew Dillon 		const char *decomp;
2247f2422cfSMatthew Dillon 
2257f2422cfSMatthew Dillon 		printf("pkg repo - recompressing meta\n");
2267f2422cfSMatthew Dillon 
2277f2422cfSMatthew Dillon 		if (strcmp(UsePkgSufx, ".tar") == 0) {
2287f2422cfSMatthew Dillon 			decomp = "cat";
2297f2422cfSMatthew Dillon 			comp = "xz";
2307f2422cfSMatthew Dillon 		} else if (strcmp(UsePkgSufx, ".tgz") == 0) {
2317f2422cfSMatthew Dillon 			decomp = "gunzip";
2327f2422cfSMatthew Dillon 			comp = "xz";
2337f2422cfSMatthew Dillon 		} else if (strcmp(UsePkgSufx, ".tbz") == 0) {
2347f2422cfSMatthew Dillon 			decomp = "bunzip2";
2357f2422cfSMatthew Dillon 			comp = "xz";
236ef0c0bf5SKrzysztof Piecuch 		} else if (strcmp(UsePkgSufx, ".tzst") == 0) {
237ef0c0bf5SKrzysztof Piecuch 			decomp = "unzstd";
238ef0c0bf5SKrzysztof Piecuch 			comp = "xz";
2397f2422cfSMatthew Dillon 		} else {
2407f2422cfSMatthew Dillon 			dfatal("recompressing from %s not supported",
2417f2422cfSMatthew Dillon 			       UsePkgSufx);
2427f2422cfSMatthew Dillon 			decomp = "cat";
2437f2422cfSMatthew Dillon 			comp = "cat";
2447f2422cfSMatthew Dillon 		}
2457f2422cfSMatthew Dillon 		repackage(PackagesPath, "meta",
2467f2422cfSMatthew Dillon 			  UsePkgSufx, ".txz",
2477f2422cfSMatthew Dillon 			  decomp, comp);
248cda252a4SMatthew Dillon 	}
249753e4c44SMatthew Dillon 	free (pkg_path);
250cda252a4SMatthew Dillon }
251cda252a4SMatthew Dillon 
252cda252a4SMatthew Dillon static
253cda252a4SMatthew Dillon void
repackage(const char * basepath,const char * basefile,const char * decomp_suffix,const char * comp_suffix,const char * decomp,const char * comp)2547f2422cfSMatthew Dillon repackage(const char *basepath, const char *basefile,
2557f2422cfSMatthew Dillon 	  const char *decomp_suffix, const char *comp_suffix,
2567f2422cfSMatthew Dillon 	  const char *decomp, const char *comp)
257cda252a4SMatthew Dillon {
258cda252a4SMatthew Dillon 	char *buf;
259cda252a4SMatthew Dillon 
2607f2422cfSMatthew Dillon 	asprintf(&buf, "%s < %s/%s%s | %s > %s/%s%s",
2617f2422cfSMatthew Dillon 		decomp, basepath, basefile, decomp_suffix,
2627f2422cfSMatthew Dillon 		comp, basepath, basefile, comp_suffix);
263cda252a4SMatthew Dillon 	if (system(buf) != 0) {
264cda252a4SMatthew Dillon 		dfatal("command failed: %s", buf);
265cda252a4SMatthew Dillon 	}
266cda252a4SMatthew Dillon 	free(buf);
2678e25f19bSMatthew Dillon }
2688e25f19bSMatthew Dillon 
2698e25f19bSMatthew Dillon void
DoUpgradePkgs(pkg_t * pkgs __unused,int ask __unused)2708e25f19bSMatthew Dillon DoUpgradePkgs(pkg_t *pkgs __unused, int ask __unused)
2718e25f19bSMatthew Dillon {
2728e25f19bSMatthew Dillon }
2738e25f19bSMatthew Dillon 
2748e25f19bSMatthew Dillon void
PurgeDistfiles(pkg_t * pkgs)2751645cafeSMatthew Dillon PurgeDistfiles(pkg_t *pkgs)
2768e25f19bSMatthew Dillon {
2771645cafeSMatthew Dillon 	pinfo_t *list;
2781645cafeSMatthew Dillon 	pinfo_t *item;
2791645cafeSMatthew Dillon 	pinfo_t **list_tail;
2801645cafeSMatthew Dillon 	pinfo_t **ary;
2811645cafeSMatthew Dillon 	char *dstr;
2821645cafeSMatthew Dillon 	char *buf;
2831645cafeSMatthew Dillon 	int count;
2841645cafeSMatthew Dillon 	int delcount;
2851645cafeSMatthew Dillon 	int i;
2861645cafeSMatthew Dillon 
2871645cafeSMatthew Dillon 	printf("Scanning distfiles... ");
2881645cafeSMatthew Dillon 	fflush(stdout);
2891645cafeSMatthew Dillon 	count = 0;
2901645cafeSMatthew Dillon 	list = NULL;
2911645cafeSMatthew Dillon 	list_tail = &list;
2926ec1f604SMatthew Dillon 	scanit(DistFilesPath, NULL, &count, &list_tail, 0);
2931645cafeSMatthew Dillon 	printf("Checking %d distfiles\n", count);
2941645cafeSMatthew Dillon 	fflush(stdout);
2951645cafeSMatthew Dillon 
2961645cafeSMatthew Dillon 	ary = calloc(count, sizeof(pinfo_t *));
2971645cafeSMatthew Dillon 	for (i = 0; i < count; ++i) {
2981645cafeSMatthew Dillon 		ary[i] = list;
2991645cafeSMatthew Dillon 		list = list->next;
3001645cafeSMatthew Dillon 	}
3011645cafeSMatthew Dillon 	ddassert(list == NULL);
3021645cafeSMatthew Dillon 	qsort(ary, count, sizeof(pinfo_t *), pinfocmp);
3031645cafeSMatthew Dillon 
3041645cafeSMatthew Dillon 	for (; pkgs; pkgs = pkgs->bnext) {
3051645cafeSMatthew Dillon 		if (pkgs->distfiles == NULL || pkgs->distfiles[0] == 0)
3061645cafeSMatthew Dillon 			continue;
3071645cafeSMatthew Dillon 		ddprintf(0, "distfiles %s\n", pkgs->distfiles);
3081645cafeSMatthew Dillon 		dstr = strtok(pkgs->distfiles, " \t");
3091645cafeSMatthew Dillon 		while (dstr) {
3101645cafeSMatthew Dillon 			for (;;) {
3116ec1f604SMatthew Dillon 				/*
3126ec1f604SMatthew Dillon 				 * Look for distfile
3136ec1f604SMatthew Dillon 				 */
3144ea2ee4dSMatthew Dillon 				if (pkgs->distsubdir) {
3151645cafeSMatthew Dillon 					asprintf(&buf, "%s/%s",
3161645cafeSMatthew Dillon 						 pkgs->distsubdir, dstr);
3176ec1f604SMatthew Dillon 				} else {
3186ec1f604SMatthew Dillon 					buf = dstr;
3196ec1f604SMatthew Dillon 				}
3201645cafeSMatthew Dillon 				item = pinfofind(ary, count, buf);
3216ec1f604SMatthew Dillon 				if (item)
3226ec1f604SMatthew Dillon 					item->foundit = 1;
3236ec1f604SMatthew Dillon 				if (item && item->inlocks == 0) {
3246ec1f604SMatthew Dillon 					/*
3256ec1f604SMatthew Dillon 					 * Look for the lock file
3266ec1f604SMatthew Dillon 					 */
3276ec1f604SMatthew Dillon 					int scount;
3286ec1f604SMatthew Dillon 
3296ec1f604SMatthew Dillon 					scount = lkdircount(buf);
3306ec1f604SMatthew Dillon 
3316ec1f604SMatthew Dillon 					for (i = 0; i <= scount; ++i) {
3326ec1f604SMatthew Dillon 						item = pinfofind(ary, count,
3336ec1f604SMatthew Dillon 							     md5lkfile(buf, i));
3346ec1f604SMatthew Dillon 						if (item)
3356ec1f604SMatthew Dillon 							item->foundit = 1;
3366ec1f604SMatthew Dillon 					}
3376ec1f604SMatthew Dillon 				}
3386ec1f604SMatthew Dillon 
3396ec1f604SMatthew Dillon 				/*
3406ec1f604SMatthew Dillon 				 * Cleanup and iterate
3416ec1f604SMatthew Dillon 				 */
3426ec1f604SMatthew Dillon 				if (buf != dstr) {
3431645cafeSMatthew Dillon 					free(buf);
3441645cafeSMatthew Dillon 					buf = NULL;
3451645cafeSMatthew Dillon 				}
3461645cafeSMatthew Dillon 				if (strrchr(dstr, ':') == NULL)
3471645cafeSMatthew Dillon 					break;
3481645cafeSMatthew Dillon 				*strrchr(dstr, ':') = 0;
3491645cafeSMatthew Dillon 			}
3501645cafeSMatthew Dillon 			dstr = strtok(NULL, " \t");
3511645cafeSMatthew Dillon 		}
3521645cafeSMatthew Dillon 	}
3531645cafeSMatthew Dillon 
3541645cafeSMatthew Dillon 	delcount = 0;
3551645cafeSMatthew Dillon 	for (i = 0; i < count; ++i) {
3561645cafeSMatthew Dillon 		item = ary[i];
3571645cafeSMatthew Dillon 		if (item->foundit == 0) {
3581645cafeSMatthew Dillon 			++delcount;
3591645cafeSMatthew Dillon 		}
3601645cafeSMatthew Dillon 	}
36161e823a7SMatthew Dillon 	if (delcount == 0) {
36261e823a7SMatthew Dillon 		printf("No obsolete source files out of %d found\n", count);
36361e823a7SMatthew Dillon 	} else if (askyn("Delete %d of %d items? ", delcount, count)) {
3641645cafeSMatthew Dillon 		printf("Deleting %d/%d obsolete source distfiles\n",
3651645cafeSMatthew Dillon 		       delcount, count);
3661645cafeSMatthew Dillon 		for (i = 0; i < count; ++i) {
3671645cafeSMatthew Dillon 			item = ary[i];
3681645cafeSMatthew Dillon 			if (item->foundit == 0) {
3691645cafeSMatthew Dillon 				asprintf(&buf, "%s/%s",
3701645cafeSMatthew Dillon 					 DistFilesPath, item->spath);
3711645cafeSMatthew Dillon 				if (remove(buf) < 0)
3721645cafeSMatthew Dillon 					printf("Cannot delete %s\n", buf);
3736ec1f604SMatthew Dillon 				else
3746ec1f604SMatthew Dillon 					printf("Deleted %s\n", item->spath);
3751645cafeSMatthew Dillon 				free(buf);
3761645cafeSMatthew Dillon 			}
3771645cafeSMatthew Dillon 		}
3781645cafeSMatthew Dillon 	}
3791645cafeSMatthew Dillon 
3801645cafeSMatthew Dillon 
3811645cafeSMatthew Dillon 	free(ary);
3828e25f19bSMatthew Dillon }
3838e25f19bSMatthew Dillon 
3848e25f19bSMatthew Dillon void
RemovePackages(pkg_t * list)385f4094b20SMatthew Dillon RemovePackages(pkg_t *list)
3868e25f19bSMatthew Dillon {
387f4094b20SMatthew Dillon 	pkg_t *scan;
388f4094b20SMatthew Dillon 	char *path;
389f4094b20SMatthew Dillon 
390f4094b20SMatthew Dillon 	for (scan = list; scan; scan = scan->bnext) {
391f4094b20SMatthew Dillon 		if ((scan->flags & PKGF_MANUALSEL) == 0)
392f4094b20SMatthew Dillon 			continue;
393f4094b20SMatthew Dillon 		if (scan->pkgfile) {
394f4094b20SMatthew Dillon 			scan->flags &= ~PKGF_PACKAGED;
395f4094b20SMatthew Dillon 			scan->pkgfile_size = 0;
396f4094b20SMatthew Dillon 			asprintf(&path, "%s/%s", RepositoryPath, scan->pkgfile);
397f4094b20SMatthew Dillon 			if (remove(path) == 0)
398f4094b20SMatthew Dillon 				printf("Removed: %s\n", path);
399f4094b20SMatthew Dillon 			free(path);
400f4094b20SMatthew Dillon 		}
401f4094b20SMatthew Dillon 		if (scan->pkgfile == NULL ||
402f4094b20SMatthew Dillon 		    (scan->flags & (PKGF_DUMMY | PKGF_META))) {
403f4094b20SMatthew Dillon 			removePackagesMetaRecurse(scan);
404f4094b20SMatthew Dillon 		}
405f4094b20SMatthew Dillon 	}
406f4094b20SMatthew Dillon }
407f4094b20SMatthew Dillon 
408f4094b20SMatthew Dillon static void
removePackagesMetaRecurse(pkg_t * pkg)409f4094b20SMatthew Dillon removePackagesMetaRecurse(pkg_t *pkg)
410f4094b20SMatthew Dillon {
411f4094b20SMatthew Dillon 	pkglink_t *link;
412f4094b20SMatthew Dillon 	pkg_t *scan;
413f4094b20SMatthew Dillon 	char *path;
414f4094b20SMatthew Dillon 
415f4094b20SMatthew Dillon 	PKGLIST_FOREACH(link, &pkg->idepon_list) {
416f4094b20SMatthew Dillon 		scan = link->pkg;
417f4094b20SMatthew Dillon 		if (scan == NULL)
418f4094b20SMatthew Dillon 			continue;
419f4094b20SMatthew Dillon 		if (scan->pkgfile == NULL ||
420f4094b20SMatthew Dillon 		    (scan->flags & (PKGF_DUMMY | PKGF_META))) {
421f4094b20SMatthew Dillon 			removePackagesMetaRecurse(scan);
422f4094b20SMatthew Dillon 			continue;
423f4094b20SMatthew Dillon 		}
424f4094b20SMatthew Dillon 		scan->flags &= ~PKGF_PACKAGED;
425f4094b20SMatthew Dillon 		scan->pkgfile_size = 0;
426f4094b20SMatthew Dillon 
427f4094b20SMatthew Dillon 		asprintf(&path, "%s/%s", RepositoryPath, scan->pkgfile);
428f4094b20SMatthew Dillon 		if (remove(path) == 0)
429f4094b20SMatthew Dillon 			printf("Removed: %s\n", path);
430f4094b20SMatthew Dillon 		free(path);
431f4094b20SMatthew Dillon 	}
4328e25f19bSMatthew Dillon }
4331645cafeSMatthew Dillon 
4341645cafeSMatthew Dillon static int
pinfocmp(const void * s1,const void * s2)4351645cafeSMatthew Dillon pinfocmp(const void *s1, const void *s2)
4361645cafeSMatthew Dillon {
4371645cafeSMatthew Dillon 	const pinfo_t *item1 = *(const pinfo_t *const*)s1;
4381645cafeSMatthew Dillon 	const pinfo_t *item2 = *(const pinfo_t *const*)s2;
4391645cafeSMatthew Dillon 
4401645cafeSMatthew Dillon 	return (strcmp(item1->spath, item2->spath));
4411645cafeSMatthew Dillon }
4421645cafeSMatthew Dillon 
4431645cafeSMatthew Dillon pinfo_t *
pinfofind(pinfo_t ** ary,int count,char * spath)4441645cafeSMatthew Dillon pinfofind(pinfo_t **ary, int count, char *spath)
4451645cafeSMatthew Dillon {
4461645cafeSMatthew Dillon 	pinfo_t *item;
4471645cafeSMatthew Dillon 	int res;
4481645cafeSMatthew Dillon 	int b;
4491645cafeSMatthew Dillon 	int e;
4501645cafeSMatthew Dillon 	int m;
4511645cafeSMatthew Dillon 
4521645cafeSMatthew Dillon 	b = 0;
4531645cafeSMatthew Dillon 	e = count;
4541645cafeSMatthew Dillon 	while (b != e) {
4551645cafeSMatthew Dillon 		m = b + (e - b) / 2;
4561645cafeSMatthew Dillon 		item = ary[m];
4571645cafeSMatthew Dillon 		res = strcmp(spath, item->spath);
4581645cafeSMatthew Dillon 		if (res == 0)
4591645cafeSMatthew Dillon 			return item;
4601645cafeSMatthew Dillon 		if (res < 0) {
4611645cafeSMatthew Dillon 			e = m;
4621645cafeSMatthew Dillon 		} else {
4631645cafeSMatthew Dillon 			b = m + 1;
4641645cafeSMatthew Dillon 		}
4651645cafeSMatthew Dillon 	}
4661645cafeSMatthew Dillon 	return NULL;
4671645cafeSMatthew Dillon }
4681645cafeSMatthew Dillon 
4691645cafeSMatthew Dillon void
scanit(const char * path,const char * subpath,int * countp,pinfo_t *** list_tailp,int inlocks)4701645cafeSMatthew Dillon scanit(const char *path, const char *subpath,
4716ec1f604SMatthew Dillon        int *countp, pinfo_t ***list_tailp,
4726ec1f604SMatthew Dillon        int inlocks)
4731645cafeSMatthew Dillon {
4741645cafeSMatthew Dillon 	struct dirent *den;
4751645cafeSMatthew Dillon 	pinfo_t *item;
4761645cafeSMatthew Dillon 	char *npath;
4771645cafeSMatthew Dillon 	char *spath;
4781645cafeSMatthew Dillon 	DIR *dir;
4791645cafeSMatthew Dillon 	struct stat st;
4801645cafeSMatthew Dillon 
4811645cafeSMatthew Dillon 	if ((dir = opendir(path)) != NULL) {
4821645cafeSMatthew Dillon 		while ((den = readdir(dir)) != NULL) {
4831645cafeSMatthew Dillon 			if (den->d_namlen == 1 && den->d_name[0] == '.')
4841645cafeSMatthew Dillon 				continue;
4851645cafeSMatthew Dillon 			if (den->d_namlen == 2 && den->d_name[0] == '.' &&
4861645cafeSMatthew Dillon 			    den->d_name[1] == '.')
4871645cafeSMatthew Dillon 				continue;
4881645cafeSMatthew Dillon 			asprintf(&npath, "%s/%s", path, den->d_name);
4891645cafeSMatthew Dillon 			if (lstat(npath, &st) < 0) {
4901645cafeSMatthew Dillon 				free(npath);
4911645cafeSMatthew Dillon 				continue;
4921645cafeSMatthew Dillon 			}
4931645cafeSMatthew Dillon 			if (S_ISDIR(st.st_mode)) {
4946ec1f604SMatthew Dillon 				int sublocks;
4956ec1f604SMatthew Dillon 
4966ec1f604SMatthew Dillon 				sublocks =
4976ec1f604SMatthew Dillon 				    (strcmp(den->d_name, ".locks") == 0);
4986ec1f604SMatthew Dillon 
4991645cafeSMatthew Dillon 				if (subpath) {
5001645cafeSMatthew Dillon 					asprintf(&spath, "%s/%s",
5011645cafeSMatthew Dillon 						 subpath, den->d_name);
5026ec1f604SMatthew Dillon 					scanit(npath, spath, countp,
5036ec1f604SMatthew Dillon 					       list_tailp, sublocks);
5041645cafeSMatthew Dillon 					free(spath);
5051645cafeSMatthew Dillon 				} else {
5066ec1f604SMatthew Dillon 					scanit(npath, den->d_name, countp,
5076ec1f604SMatthew Dillon 					       list_tailp, sublocks);
5081645cafeSMatthew Dillon 				}
5091645cafeSMatthew Dillon 			} else if (S_ISREG(st.st_mode)) {
5101645cafeSMatthew Dillon 				item = calloc(1, sizeof(*item));
5111645cafeSMatthew Dillon 				if (subpath) {
5121645cafeSMatthew Dillon 					asprintf(&item->spath, "%s/%s",
5131645cafeSMatthew Dillon 						 subpath, den->d_name);
5141645cafeSMatthew Dillon 				} else {
5151645cafeSMatthew Dillon 					item->spath = strdup(den->d_name);
5161645cafeSMatthew Dillon 				}
5176ec1f604SMatthew Dillon 				item->inlocks = inlocks;
5186ec1f604SMatthew Dillon 
5191645cafeSMatthew Dillon 				**list_tailp = item;
5201645cafeSMatthew Dillon 				*list_tailp = &item->next;
5211645cafeSMatthew Dillon 				++*countp;
5221645cafeSMatthew Dillon 				ddprintf(0, "scan   %s\n", item->spath);
5231645cafeSMatthew Dillon 			}
5246a3a20b1SMatthew Dillon 			free(npath);
5251645cafeSMatthew Dillon 		}
5261645cafeSMatthew Dillon 		closedir(dir);
5271645cafeSMatthew Dillon 	}
5281645cafeSMatthew Dillon }
529f7f25838SMatthew Dillon 
530f7f25838SMatthew Dillon /*
531f7f25838SMatthew Dillon  * This removes any .new files left over in the repo.  These can wind
532f7f25838SMatthew Dillon  * being left around when dsynth is killed.
533f7f25838SMatthew Dillon  */
534f7f25838SMatthew Dillon static void
scandeletenew(const char * path)535f7f25838SMatthew Dillon scandeletenew(const char *path)
536f7f25838SMatthew Dillon {
537f7f25838SMatthew Dillon 	struct dirent *den;
538f7f25838SMatthew Dillon 	const char *ptr;
539f7f25838SMatthew Dillon 	DIR *dir;
540f7f25838SMatthew Dillon 	char *buf;
541f7f25838SMatthew Dillon 
542f7f25838SMatthew Dillon 	if ((dir = opendir(path)) == NULL)
543f7f25838SMatthew Dillon 		dfatal_errno("Cannot scan directory %s", path);
544f7f25838SMatthew Dillon 	while ((den = readdir(dir)) != NULL) {
545f7f25838SMatthew Dillon 		if ((ptr = strrchr(den->d_name, '.')) != NULL &&
546f7f25838SMatthew Dillon 		    strcmp(ptr, ".new") == 0) {
547f7f25838SMatthew Dillon 			asprintf(&buf, "%s/%s", path, den->d_name);
548f7f25838SMatthew Dillon 			if (remove(buf) < 0)
549f7f25838SMatthew Dillon 				dfatal_errno("remove: Garbage %s\n", buf);
550f7f25838SMatthew Dillon 			printf("Deleted Garbage %s\n", buf);
551f7f25838SMatthew Dillon 			free(buf);
552f7f25838SMatthew Dillon 		}
553f7f25838SMatthew Dillon 	}
554f7f25838SMatthew Dillon 	closedir(dir);
555f7f25838SMatthew Dillon }
556066daf2aSMatthew Dillon 
557066daf2aSMatthew Dillon static void
rebuildTerminateSignal(int signo __unused)558066daf2aSMatthew Dillon rebuildTerminateSignal(int signo __unused)
559066daf2aSMatthew Dillon {
560066daf2aSMatthew Dillon 	if (RebuildRemovePath)
561066daf2aSMatthew Dillon 		remove(RebuildRemovePath);
562066daf2aSMatthew Dillon 	exit(1);
563066daf2aSMatthew Dillon 
564066daf2aSMatthew Dillon }
5656ec1f604SMatthew Dillon 
5666ec1f604SMatthew Dillon /*
5676ec1f604SMatthew Dillon  * There will be a .locks sub-directory in /usr/distfiles and also
5686ec1f604SMatthew Dillon  * in each sub-directory underneath it containing the MD5 sums for
5696ec1f604SMatthew Dillon  * the files in that subdirectory.
5706ec1f604SMatthew Dillon  *
5716ec1f604SMatthew Dillon  * This is a bit of a mess.  Sometimes the .locks/ for a subdirectory
5726ec1f604SMatthew Dillon  * are in parentdir/.locks and not parentdir/subdir/.locks.  The invocation
5736ec1f604SMatthew Dillon  * of do-fetch can be a bit messy so we look for a .locks subdir everywhere.
5746ec1f604SMatthew Dillon  *
5756ec1f604SMatthew Dillon  * The /usr/dports/Mk/Scripts/do-fetch.sh script uses 'echo blah | md5',
5766ec1f604SMatthew Dillon  * so we have to add a newline to the buffer being md5'd.
5776ec1f604SMatthew Dillon  *
5786ec1f604SMatthew Dillon  * The pass-in rpath is relative to the distfiles base.
5796ec1f604SMatthew Dillon  */
5806ec1f604SMatthew Dillon static char *
md5lkfile(char * rpath,int which_slash)5816ec1f604SMatthew Dillon md5lkfile(char *rpath, int which_slash)
5826ec1f604SMatthew Dillon {
5836ec1f604SMatthew Dillon 	static char mstr[128];
5846ec1f604SMatthew Dillon 	static char lkfile[128];
5856ec1f604SMatthew Dillon 	uint8_t digest[MD5_DIGEST_LENGTH];
5866ec1f604SMatthew Dillon 	int bplen;
5876ec1f604SMatthew Dillon 	int i;
5886ec1f604SMatthew Dillon 
5896ec1f604SMatthew Dillon 	bplen = 0;
5906ec1f604SMatthew Dillon 	for (i = 0; i < which_slash; ++i) {
5916ec1f604SMatthew Dillon 		while (rpath[bplen] && rpath[bplen] != '/')
5926ec1f604SMatthew Dillon 			++bplen;
5936ec1f604SMatthew Dillon 		if (rpath[bplen])
5946ec1f604SMatthew Dillon 			++bplen;
5956ec1f604SMatthew Dillon 	}
5966ec1f604SMatthew Dillon 	snprintf(mstr, sizeof(mstr), "%s\n", rpath + bplen);
5976ec1f604SMatthew Dillon 	MD5(mstr, strlen(mstr), digest);
5986ec1f604SMatthew Dillon 
5996ec1f604SMatthew Dillon 	snprintf(lkfile, sizeof(lkfile),
6006ec1f604SMatthew Dillon 		"%*.*s.locks/"
6016ec1f604SMatthew Dillon 		 "%02x%02x%02x%02x%02x%02x%02x%02x"
6026ec1f604SMatthew Dillon 		 "%02x%02x%02x%02x%02x%02x%02x%02x"
6036ec1f604SMatthew Dillon 		 ".lk",
6046ec1f604SMatthew Dillon 		 bplen, bplen, rpath,
6056ec1f604SMatthew Dillon 		 digest[0], digest[1], digest[2], digest[3],
6066ec1f604SMatthew Dillon 		 digest[4], digest[5], digest[6], digest[7],
6076ec1f604SMatthew Dillon 		 digest[8], digest[9], digest[10], digest[11],
6086ec1f604SMatthew Dillon 		 digest[12], digest[13], digest[14], digest[15]);
6096ec1f604SMatthew Dillon 
6106ec1f604SMatthew Dillon 	return lkfile;
6116ec1f604SMatthew Dillon }
6126ec1f604SMatthew Dillon 
6136ec1f604SMatthew Dillon static int
lkdircount(char * buf)6146ec1f604SMatthew Dillon lkdircount(char *buf)
6156ec1f604SMatthew Dillon {
6166ec1f604SMatthew Dillon 	int i;
6176ec1f604SMatthew Dillon 	int n;
6186ec1f604SMatthew Dillon 
6196ec1f604SMatthew Dillon 	n = 0;
6206ec1f604SMatthew Dillon 	for (i = 0; buf[i]; ++i) {
6216ec1f604SMatthew Dillon 		if (buf[i] == '/')
6226ec1f604SMatthew Dillon 			++n;
6236ec1f604SMatthew Dillon 	}
6246ec1f604SMatthew Dillon 	return n;
6256ec1f604SMatthew Dillon }
626