Esempio n. 1
0
int
exec_clean(int argc, char **argv)
{
	struct pkgdb	*db = NULL;
	struct pkgdb_it	*it = NULL;
	struct pkg	*pkg = NULL;
	struct pkg	*p = NULL;
	FTS		*fts = NULL;
	FTSENT		*ent = NULL;
	struct dl_head	dl = STAILQ_HEAD_INITIALIZER(dl);
	const char	*cachedir;
	char		*paths[2];
	char		*repopath;
	bool		 dry_run = false;
	bool		 yes;
	int		 retcode = EX_SOFTWARE;
	int		 ret;
	int		 ch;

	pkg_config_bool(PKG_CONFIG_ASSUME_ALWAYS_YES, &yes);

	while ((ch = getopt(argc, argv, "nqy")) != -1) {
		switch (ch) {
		case 'n':
			dry_run = true;
			break;
		case 'q':
			quiet = true;
			break;
		case 'y':
			yes = true;
			break;
		default:
			usage_clean();
			return (EX_USAGE);
		}
	}
	argc -= optind;
	argv += optind;

	if (pkg_config_string(PKG_CONFIG_CACHEDIR, &cachedir) != EPKG_OK) {
		warnx("Cannot get cachedir config entry");
		return 1;
	}

	paths[0] = __DECONST(char*, cachedir);
	paths[1] = NULL;

	if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) {
		goto cleanup;
	}

	if ((fts = fts_open(paths, FTS_PHYSICAL, NULL)) == NULL) {
		warn("fts_open(%s)", cachedir);
		goto cleanup;
	}

	/* Build the list of out-of-date or obsolete packages */

	while ((ent = fts_read(fts)) != NULL) {
		const char *origin, *pkgrepopath;

		if (ent->fts_info != FTS_F)
			continue;

		repopath = ent->fts_path + strlen(cachedir);
		if (repopath[0] == '/')
			repopath++;

		if (pkg_open(&pkg, ent->fts_path) != EPKG_OK) {
			if (!quiet)
				warnx("skipping %s", ent->fts_path);
			continue;
		}

		pkg_get(pkg, PKG_ORIGIN, &origin);
		it = pkgdb_search(db, origin, MATCH_EXACT, FIELD_ORIGIN,
		    FIELD_NONE, NULL);

		if (it == NULL) {
			if (!quiet)
				warnx("skipping %s", ent->fts_path);
			continue;
		}

		if ((ret = pkgdb_it_next(it, &p, PKG_LOAD_BASIC)) ==
		    EPKG_FATAL) {
			if (!quiet)
				warnx("skipping %s", ent->fts_path);
			continue;
		}

		pkg_get(p, PKG_REPOPATH, &pkgrepopath);
		if (ret == EPKG_END) {
			ret = add_to_dellist(&dl, REMOVED, ent->fts_path,
					     origin, NULL, NULL);
		} else if (strcmp(repopath, pkgrepopath)) {
			const char	*newname;
			const char	*newversion;

			pkg_get(p, 
				PKG_NAME,    &newname,
				PKG_VERSION, &newversion);

			ret = add_to_dellist(&dl, OUT_OF_DATE, ent->fts_path,
					     origin, newname, newversion);
		} else {
			char local_cksum[SHA256_DIGEST_LENGTH * 2 +1];
			const char *cksum;

			pkg_get(p, PKG_CKSUM, &cksum);

			if (hash_file(ent->fts_path, local_cksum) == EPKG_OK) {

				if (strcmp(cksum, local_cksum) != 0) {
					ret = add_to_dellist(&dl, CKSUM_MISMATCH, ent->fts_path,
						     origin, NULL, NULL);
				}
			}
		}

		if (ret != EPKG_OK && ret != EPKG_END) {
			retcode = EX_OSERR; /* out of memory */
			goto cleanup;
		}

		pkgdb_it_free(it);
	}

	if (STAILQ_EMPTY(&dl)) {
		if (!quiet)
			printf("Nothing to do.\n");
		retcode = EX_OK;
		goto cleanup;
	}

	if (dry_run || !yes || !quiet)
		display_dellist(&dl, cachedir);

	if (!dry_run) {
		if (!yes)
			yes = query_yesno(
				"\nProceed with cleaning cache [y/N]: ");
		if (yes)
			retcode = delete_dellist(&dl);
	} else 
		retcode = EX_OK;

cleanup:
	free_dellist(&dl);

	pkg_free(pkg);
	pkg_free(p);
	if (fts != NULL)
		fts_close(fts);
	if (db != NULL)
		pkgdb_close(db);

	return (retcode);
}
Esempio n. 2
0
int
exec_clean(int argc, char **argv)
{
	struct pkgdb	*db = NULL;
	struct pkgdb_it	*it = NULL;
	struct pkg	*p = NULL;
	struct sumlist	*sumlist = NULL, *s, *t;
	FTS		*fts = NULL;
	FTSENT		*ent = NULL;
	struct dl_head	dl = STAILQ_HEAD_INITIALIZER(dl);
	const char	*cachedir, *sum, *name;
	char		*paths[2], csum[PKG_FILE_CKSUM_CHARS + 1],
			link_buf[MAXPATHLEN];
	bool		 all = false;
	bool		 sumloaded = false;
	int		 retcode;
	int		 ch, cnt = 0;
	size_t		 total = 0, slen;
	ssize_t		 link_len;
	char		 size[7];
	struct pkg_manifest_key *keys = NULL;

	struct option longopts[] = {
		{ "all",	no_argument,	NULL,	'a' },
		{ "dry-run",	no_argument,	NULL,	'n' },
		{ "quiet",	no_argument,	NULL,	'q' },
		{ "yes",	no_argument,	NULL,	'y' },
		{ NULL,		0,		NULL,	0   },
	};

	while ((ch = getopt_long(argc, argv, "+anqy", longopts, NULL)) != -1) {
		switch (ch) {
		case 'a':
			all = true;
			break;
		case 'n':
			dry_run = true;
			break;
		case 'q':
			quiet = true;
			break;
		case 'y':
			yes = true;
			break;
		default:
			usage_clean();
			return (EX_USAGE);
		}
	}
	argc -= optind;
	argv += optind;

	cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));

	paths[0] = __DECONST(char*, cachedir);
	paths[1] = NULL;

	retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_REPO);

	if (retcode == EPKG_ENOACCESS) {
		warnx("Insufficient privileges to clean old packages");
		return (EX_NOPERM);
	} else if (retcode == EPKG_ENODB) {
		warnx("No package database installed.  Nothing to do!");
		return (EX_OK);
	} else if (retcode != EPKG_OK) {
		warnx("Error accessing the package database");
		return (EX_SOFTWARE);
	}

	retcode = EX_SOFTWARE;

	if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK)
		return (EX_IOERR);

	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
		pkgdb_close(db);
		warnx("Cannot get a read lock on a database, it is locked by another process");
		return (EX_TEMPFAIL);
	}

	if ((fts = fts_open(paths, FTS_PHYSICAL, NULL)) == NULL) {
		warn("fts_open(%s)", cachedir);
		goto cleanup;
	}

	/* Build the list of out-of-date or obsolete packages */

	pkg_manifest_keys_new(&keys);
	while ((ent = fts_read(fts)) != NULL) {
		if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL)
			continue;

		if (all) {
			retcode = add_to_dellist(&dl, ent->fts_path);
			if (retcode == EPKG_OK) {
				total += ent->fts_statp->st_size;
				++cnt;
			}
			continue;
		}

		if (sumlist == NULL && !sumloaded) {
			it = pkgdb_repo_search(db, "*", MATCH_GLOB, FIELD_NAME, FIELD_NONE, NULL);
			while (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) {
				pkg_get(p, PKG_CKSUM, &sum);
				slen = MIN(strlen(sum), PKG_FILE_CKSUM_CHARS);
				s = calloc(1, sizeof(struct sumlist));
				memcpy(s->sum, sum, slen);
				s->sum[slen] = '\0';
				HASH_ADD_STR(sumlist, sum, s);
			}
		}

		if (ent->fts_info == FTS_SL) {
			/* Dereference the symlink and check it for being
			 * recognized checksum file, or delete the symlink
			 * later. */
			if ((link_len = readlink(ent->fts_name, link_buf,
			    sizeof(link_buf))) == -1)
				continue;
			link_buf[link_len] = '\0';
			name = link_buf;
		} else
			name = ent->fts_name;

		s = NULL;
		if (extract_filename_sum(name, csum))
			HASH_FIND_STR(sumlist, csum, s);
		if (s == NULL) {
			retcode = add_to_dellist(&dl, ent->fts_path);
			if (retcode == EPKG_OK) {
				total += ent->fts_statp->st_size;
				++cnt;
			}
			continue;
		}
	}
	HASH_ITER(hh, sumlist, s, t) {
		HASH_DEL(sumlist, s);
		free(s);
	}
Esempio n. 3
0
File: clean.c Progetto: grembo/pkg
static int
recursive_analysis(int fd, struct pkgdb *db, const char *dir,
    const char *cachedir, dl_list *dl, kh_sum_t **sumlist, bool all,
    size_t *total)
{
	DIR *d;
	struct dirent *ent;
	int newfd, tmpfd;
	char path[MAXPATHLEN], csum[PKG_FILE_CKSUM_CHARS + 1],
		link_buf[MAXPATHLEN];
	const char *name;
	ssize_t link_len;
	size_t nbfiles = 0, added = 0;
	khint_t k;

	tmpfd = dup(fd);
	d = fdopendir(tmpfd);
	if (d == NULL) {
		close(tmpfd);
		warnx("Impossible to open the directory %s", dir);
		return (0);
	}

	while ((ent = readdir(d)) != NULL) {
		if (strcmp(ent->d_name, ".") == 0 ||
		    strcmp(ent->d_name, "..") == 0)
			continue;
		snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name);
		if (ent->d_type == DT_DIR) {
			nbfiles++;
			newfd = openat(fd, ent->d_name, O_DIRECTORY, 0);
			if (newfd == -1) {
				warnx("Impossible to open the directory %s",
				    path);
				continue;
			}
			if (recursive_analysis(newfd, db, path, cachedir, dl,
			    sumlist, all, total) == 0 || all) {
				add_to_dellist(fd, dl, cachedir, path);
				added++;
			}
			close(newfd);
			continue;
		}
		if (ent->d_type != DT_LNK && ent->d_type != DT_REG)
			continue;
		nbfiles++;
		if (all) {
			*total += add_to_dellist(fd, dl, cachedir, path);
			continue;
		}
		if (*sumlist == NULL) {
			*sumlist = populate_sums(db);
		}
		name = ent->d_name;
		if (ent->d_type == DT_LNK) {
			/* Dereference the symlink and check it for being
			 * recognized checksum file, or delete the symlink
			 * later. */
			if ((link_len = readlinkat(fd, ent->d_name, link_buf,
			    sizeof(link_buf))) == -1)
				continue;
			link_buf[link_len - 1] = '\0';
			name = link_buf;
		}

		k = kh_end(*sumlist);
		if (extract_filename_sum(name, csum))
			k = kh_get_sum(*sumlist, csum);
		if (k == kh_end(*sumlist)) {
			added++;
			*total += add_to_dellist(fd, dl, cachedir, path);
		}
	}
	closedir(d);
	return (nbfiles - added);
}