Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Modify plist keyword handling so that it can be more easily extended
Baptiste Daroussin committed 14 years ago
commit 7473489db14d00c45ac5a0d004ec98512f3bd922
parent fd7df863c3d9677f19a330e8397960027956ec6d
1 file changed +291 -133
modified libpkg/pkg_ports.c
@@ -21,6 +21,33 @@ struct hardlinks {
	size_t cap;
};

+
struct keyword {
+
	const char *keyword;
+
	STAILQ_HEAD(actions, action) actions;
+
	STAILQ_ENTRY(keyword) next;
+
};
+

+
struct plist {
+
	char *last_file;
+
	const char *prefix;
+
	struct sbuf *exec_scripts;
+
	struct sbuf *unexec_scripts;
+
	struct sbuf *pre_unexec_scripts;
+
	struct sbuf *post_unexec_scripts;
+
	struct pkg *pkg;
+
	const char *uname;
+
	const char *gname;
+
	const char *slash;
+
	bool ignore_next;
+
	mode_t perm;
+
	STAILQ_HEAD(keywords, keyword) keywords;
+
};
+

+
struct action {
+
	int (*perform)(struct plist *, char *);
+
	STAILQ_ENTRY(action) next;
+
};
+

static void
sbuf_append(struct sbuf *buf, __unused const char *comment, const char *str, ...)
{
@@ -39,10 +66,208 @@ sbuf_append(struct sbuf *buf, __unused const char *comment, const char *str, ...
#define pre_unexec_append(buf, str, ...) sbuf_append(buf, "unexec", str, __VA_ARGS__)
#define exec_append(buf, str, ...) sbuf_append(buf, "exec", str, __VA_ARGS__)

+
static int
+
setprefix(struct plist *p, char *line)
+
{
+
	/* if no arguments then set default prefix */
+
	if (line[0] == '\0')
+
		pkg_get(p->pkg, PKG_PREFIX, &p->prefix);
+
	else
+
		p->prefix = line;
+
	p->slash = p->prefix[strlen(p->prefix) -1] == '/' ? "" : "/";
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
meta_dirrm(struct plist *p, char *line, bool try)
+
{
+
	size_t len;
+
	char path[MAXPATHLEN];
+

+
	len = strlen(line);
+

+
	while (isspace(line[len - 1]))
+
		line[len - 1] = '\0';
+

+
	if (line[0] == '/')
+
		snprintf(path, sizeof(path), "%s/", line);
+
	else
+
		snprintf(path, sizeof(path), "%s%s%s/", p->prefix, p->slash, line);
+

+
	return (pkg_adddir_attr(p->pkg, path, p->uname, p->gname, p->perm, try));
+
}
+

+
static int
+
dirrm(struct plist *p, char *line)
+
{
+
	return (meta_dirrm(p, line, false));
+
}
+

+
static int
+
dirrmtry(struct plist *p, char *line)
+
{
+
	return (meta_dirrm(p, line, true));
+
}
+

+
static int
+
setmod(struct plist *p, char *line)
+
{
+
	void *set;
+

+
	p->perm = 0;
+

+
	if (line[0] == '\0')
+
		return (EPKG_OK);
+

+
	if ((set = setmode(line)) == NULL)
+
		pkg_emit_error("%s wrong mode value", line);
+
	else
+
		p->perm = getmode(set, 0);
+
	return (EPKG_OK);
+
}
+

+
static int
+
setowner(struct plist *p, char *line)
+
{
+
	if (line[0] == '\0')
+
		p->uname = NULL;
+
	else
+
		p->uname = line;
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
setgroup(struct plist *p, char *line)
+
{
+
	if (line[0] == '\0')
+
		p->gname = NULL;
+
	else
+
		p->gname = line;
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ignore(__unused struct plist *p, __unused char *line)
+
{
+
	return (EPKG_OK);
+
}
+

+
static int
+
ignore_next(struct plist *p, __unused char *line)
+
{
+
	p->ignore_next = true;
+

+
	return (EPKG_OK);
+
}
+

+
static void
+
populate_keywords(struct plist *p)
+
{
+
	struct keyword *k;
+
	struct action *a;
+

+
	/* @cwd */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "cwd";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = setprefix;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+
	/* @ignore */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "ignore";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = ignore_next;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+
	/* @comment */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "comment";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = ignore;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+
	/* @dirrm */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "dirrm";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = dirrm;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+
	/* @dirrmtry */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "comment";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = dirrmtry;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+
	/* @mode */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "mode";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = setmod;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+
	/* @owner */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "owner";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = setowner;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+
	/* @group */
+
	k = malloc(sizeof(struct keyword));
+
	a = malloc(sizeof(struct action));
+
	k->keyword = "group";
+
	STAILQ_INIT(&k->actions);
+
	a->perform = setgroup;
+
	STAILQ_INSERT_TAIL(&k->actions, a, next);
+
	STAILQ_INSERT_TAIL(&p->keywords, k, next);
+

+

+
}
+

+
static int
+
parse_keywords(struct plist *plist, char *keyword, char *line)
+
{
+
	struct keyword *k;
+
	struct action *a;
+
	int ret = EPKG_FATAL;
+

+
	STAILQ_FOREACH(k, &plist->keywords, next) {
+
		if (!strcmp(k->keyword, keyword)) {
+
			STAILQ_FOREACH(a, &k->actions, next) {
+
				ret = a->perform(plist, line);
+
				if (ret != EPKG_OK)
+
					return (ret);
+
			}
+
			return (ret);
+
		}
+
	}
+

+
	return (ret);
+
}
+

int
ports_parse_plist(struct pkg *pkg, char *plist)
{
-
	bool ignore_next = false;
	char *plist_p, *buf, *p, *plist_buf;
	char comment[2];
	int nbel, i;
@@ -51,26 +276,35 @@ ports_parse_plist(struct pkg *pkg, char *plist)
	size_t j;
	char sha256[SHA256_DIGEST_LENGTH * 2 + 1];
	char path[MAXPATHLEN + 1];
-
	char *last_plist_file = NULL;
	char *cmd = NULL;
-
	const char *prefix = NULL;
	struct stat st;
	int ret = EPKG_OK;
	off_t sz = 0;
-
	const char *slash;
	int64_t flatsize = 0;
	struct hardlinks hardlinks = {NULL, 0, 0};
	bool regular;
-
	struct sbuf *exec_scripts = sbuf_new_auto();
-
	struct sbuf *unexec_scripts = sbuf_new_auto();
-
	struct sbuf *pre_unexec_scripts = sbuf_new_auto();
-
	struct sbuf *post_unexec_scripts = sbuf_new_auto();
-
	void *set = NULL;
-
	const char *uname = NULL;
-
	const char *gname = NULL;
-
	mode_t perm=0;
	regex_t preg1, preg2;
	regmatch_t pmatch[2];
+
	struct plist pplist;
+

+
	assert(pkg != NULL);
+
	assert(plist != NULL);
+

+
	pplist.last_file = NULL;
+
	pplist.prefix = NULL;
+
	pplist.exec_scripts = sbuf_new_auto();
+
	pplist.unexec_scripts = sbuf_new_auto();
+
	pplist.pre_unexec_scripts = sbuf_new_auto();
+
	pplist.post_unexec_scripts = sbuf_new_auto();
+
	pplist.uname = NULL;
+
	pplist.gname = NULL;
+
	pplist.perm = 0;
+
	pplist.pkg = pkg;
+
	pplist.slash = "";
+
	pplist.ignore_next = false;
+
	STAILQ_INIT(&pplist.keywords);
+

+
	populate_keywords(&pplist);

	regcomp(&preg1, "[[:space:]]\"(/[^\"]+)", REG_EXTENDED);
	regcomp(&preg2, "[[:space:]](/[[:graph:]/]+)", REG_EXTENDED);
@@ -78,14 +312,11 @@ ports_parse_plist(struct pkg *pkg, char *plist)
	buf = NULL;
	p = NULL;

-
	assert(pkg != NULL);
-
	assert(plist != NULL);
-

	if ((ret = file_to_buffer(plist, &plist_buf, &sz)) != EPKG_OK)
		return (ret);

-
	pkg_get(pkg, PKG_PREFIX, &prefix);
-
	slash = prefix[strlen(prefix) - 1] == '/' ? "" : "/";
+
	pkg_get(pkg, PKG_PREFIX, &pplist.prefix);
+
	pplist.slash = pplist.prefix[strlen(pplist.prefix) - 1] == '/' ? "" : "/";

	nbel = split_chr(plist_buf, '\n');

@@ -93,29 +324,14 @@ ports_parse_plist(struct pkg *pkg, char *plist)
	plist_p = plist_buf;

	for (i = 0; i <= nbel; i++) {
-
		if (ignore_next)
+
		if (pplist.ignore_next) {
+
			pplist.ignore_next = false;
			continue;
+
		}

		if (plist_p[0] == '@') {
-
			if (STARTS_WITH(plist_p, "@cwd")) {
-
				buf = plist_p;
-
				buf += 4;
-
				while (isspace(buf[0]))
-
					buf++;
-
				/* with no arguments default to the original
-
				 * prefix */
-
				if (buf[0] == '\0')
-
					pkg_get(pkg, PKG_PREFIX, &prefix);
-
				else
-
					prefix = buf;
-
				slash = prefix[strlen(prefix) - 1] == '/' ? "" : "/";
-
			} else if (STARTS_WITH(plist_p, "@ignore")) {
-
				/* ignore the next line */
-
				ignore_next = true;
-
			} else if (STARTS_WITH(plist_p, "@comment ")) {
-
				/* DO NOTHING: ignore the comments */
-
			} else if (STARTS_WITH(plist_p, "@unexec ") ||
-
					   STARTS_WITH(plist_p, "@exec ")) {
+
			if (STARTS_WITH(plist_p, "@unexec ") ||
+
			    STARTS_WITH(plist_p, "@exec ")) {
				buf = plist_p;

				while (!isspace(buf[0]))
@@ -124,7 +340,7 @@ ports_parse_plist(struct pkg *pkg, char *plist)
				while (isspace(buf[0]))
					buf++;

-
				if (format_exec_cmd(&cmd, buf, prefix, last_plist_file) != EPKG_OK)
+
				if (format_exec_cmd(&cmd, buf, pplist.prefix, pplist.last_file) != EPKG_OK)
					continue;

				if (plist_p[1] == 'u') {
@@ -164,9 +380,9 @@ ports_parse_plist(struct pkg *pkg, char *plist)
					    strstr(cmd, "fonts.scale") || strstr(cmd, "gtk-update-icon-cache") ||
					    strstr(cmd, "update-desktop-database") || strstr(cmd, "update-mime-database")) {
						if (comment[0] != '#')
-
							post_unexec_append(post_unexec_scripts, "%s%s\n", comment, cmd);
+
							post_unexec_append(pplist.post_unexec_scripts, "%s%s\n", comment, cmd);
					} else
-
						sbuf_printf(unexec_scripts, "%s%s\n",comment, cmd);
+
						sbuf_printf(pplist.unexec_scripts, "%s%s\n",comment, cmd);

					/* workaround to detect the @dirrmtry */
					if (comment[0] == '#') {
@@ -185,7 +401,7 @@ ports_parse_plist(struct pkg *pkg, char *plist)
								buf+=pmatch[1].rm_eo;
								if (!strcmp(path, "/dev/null"))
									continue;
-
								ret += pkg_adddir_attr(pkg, path, uname, gname, perm, 1);
+
								ret += pkg_adddir_attr(pkg, path, pplist.uname, pplist.gname, pplist.perm, 1);
							}
						} else {
							while (regexec(&preg2, buf, 2, pmatch, 0) == 0) {
@@ -193,98 +409,40 @@ ports_parse_plist(struct pkg *pkg, char *plist)
								buf+=pmatch[1].rm_eo;
								if (!strcmp(path, "/dev/null"))
									continue;
-
								ret += pkg_adddir_attr(pkg, path, uname, gname, perm, 1);
+
								ret += pkg_adddir_attr(pkg, path, pplist.uname, pplist.gname, pplist.perm, 1);
							}
						}

					}
				} else {
-
					exec_append(exec_scripts, "%s\n", cmd);
+
					exec_append(pplist.exec_scripts, "%s\n", cmd);
				}

				free(cmd);
-

-
			} else if (STARTS_WITH(plist_p, "@dirrm")) {
-
				/* dirrm or dirrmtry */
-

-
				buf = plist_p;
-

-
				/* remove the @dirrm or @dirrmtry */
-
				while (!isspace(buf[0]))
-
					buf++;
-

-
				while (isspace(buf[0]))
+
			} else {
+
				char *keyword = plist_p;
+
				keyword++; /* skip the @ */
+
				buf = keyword;
+
				while (!(isspace(buf[0]) || buf[0] == '\0'))
					buf++;
-

-
				len = strlen(buf);
-

-
				while (isspace(buf[len - 1])) {
-
					buf[len - 1] = '\0';
-
					len--;
-
				}
-

-
				if (buf[0] == '/')
-
					snprintf(path, sizeof(path), "%s/", buf);
-
				else
-
					snprintf(path, sizeof(path), "%s%s%s/", prefix, slash, buf);
-

-

-
				if (plist_p[6] == 't') {
-
					//post_unexec_append(post_unexec_scripts, "#@unexec /bin/rmdir \"%s\" || true\n", path);
-
					ret += pkg_adddir_attr(pkg, path, uname, gname, perm, 1);
-
				} else {
-
					//post_unexec_append(post_unexec_scripts, "#@dirrm \"%s\" || true\n", path);
-
					ret += pkg_adddir_attr(pkg, path, uname, gname, perm, 0);
-
				}
-

-

-
			} else if (STARTS_WITH(plist_p, "@mode")) {
-
				buf = plist_p;
-
				buf += 5;
-
				while (isspace(buf[0]))
+
				if (buf[0] != '\0') {
+
					buf[0] = '\0';
					buf++;
-

-
				if (buf[0] == '\0') {
-
					perm = 0;
-
				} else {
-
					if ((set = setmode(buf)) == NULL) {
-
						pkg_emit_error("%s wrong @mode value", buf);
-
						perm = 0;
-
					} else {
-
						getmode(set, 0);
-
					}
				}
-
			} else if (STARTS_WITH(plist_p, "@owner")) {
-
				buf = plist_p;
-
				buf += 6;
+
				/* trim write spaces */
				while (isspace(buf[0]))
					buf++;
-

-
				if (buf[0])
-
					uname = NULL;
-
				else
-
					uname = buf;
-
			} else if (STARTS_WITH(plist_p, "@group")) {
-
				buf = plist_p;
-
				buf += 6;
-
				while (isspace(buf[0]))
-
					buf++;
-

-
				if (buf[0])
-
					gname = NULL;
-
				else
-
					gname = buf;
-
			} else {
-
				pkg_emit_error("%s is deprecated, ignoring", plist_p);
+
				if (parse_keywords(&pplist, keyword, buf) != EPKG_OK)
+
					pkg_emit_error("unknown keyword %s, ignoring %s", keyword, plist_p);
			}
		} else if ((len = strlen(plist_p)) > 0){
-
			if (sbuf_len(unexec_scripts) > 0) {
-
				sbuf_finish(unexec_scripts);
-
				pre_unexec_append(pre_unexec_scripts, sbuf_data(unexec_scripts), "");
-
				sbuf_reset(unexec_scripts);
+
			if (sbuf_len(pplist.unexec_scripts) > 0) {
+
				sbuf_finish(pplist.unexec_scripts);
+
				pre_unexec_append(pplist.pre_unexec_scripts, sbuf_data(pplist.unexec_scripts), "");
+
				sbuf_reset(pplist.unexec_scripts);
			}
			buf = plist_p;
-
			last_plist_file = buf;
+
			pplist.last_file = buf;
			sha256[0] = '\0';

			/* remove spaces at the begining and at the end */
@@ -296,7 +454,7 @@ ports_parse_plist(struct pkg *pkg, char *plist)
				len--;
			}

-
			snprintf(path, sizeof(path), "%s%s%s", prefix, slash, buf);
+
			snprintf(path, sizeof(path), "%s%s%s", pplist.prefix, pplist.slash, buf);

			if (lstat(path, &st) == 0) {
				p = NULL;
@@ -329,7 +487,7 @@ ports_parse_plist(struct pkg *pkg, char *plist)
					sha256_file(path, sha256);
					p = sha256;
				}
-
				ret += pkg_addfile_attr(pkg, path, p, uname, gname, perm);
+
				ret += pkg_addfile_attr(pkg, path, p, pplist.uname, pplist.gname, pplist.perm);
			} else {
				pkg_emit_errno("lstat", path);
			}
@@ -343,27 +501,27 @@ ports_parse_plist(struct pkg *pkg, char *plist)

	pkg_set(pkg, PKG_FLATSIZE, flatsize);

-
	if (sbuf_len(pre_unexec_scripts) > 0) {
-
		sbuf_finish(pre_unexec_scripts);
-
		pkg_appendscript(pkg, sbuf_data(pre_unexec_scripts), PKG_SCRIPT_PRE_DEINSTALL);
+
	if (sbuf_len(pplist.pre_unexec_scripts) > 0) {
+
		sbuf_finish(pplist.pre_unexec_scripts);
+
		pkg_appendscript(pkg, sbuf_data(pplist.pre_unexec_scripts), PKG_SCRIPT_PRE_DEINSTALL);
	}
-
	if (sbuf_len(exec_scripts) > 0) {
-
		sbuf_finish(exec_scripts);
-
		pkg_appendscript(pkg, sbuf_data(exec_scripts), PKG_SCRIPT_POST_INSTALL);
+
	if (sbuf_len(pplist.exec_scripts) > 0) {
+
		sbuf_finish(pplist.exec_scripts);
+
		pkg_appendscript(pkg, sbuf_data(pplist.exec_scripts), PKG_SCRIPT_POST_INSTALL);
	}
-
	if (sbuf_len(unexec_scripts) > 0) {
-
		sbuf_finish(unexec_scripts);
-
		post_unexec_append(post_unexec_scripts, sbuf_data(unexec_scripts), "");
-
		sbuf_finish(post_unexec_scripts);
+
	if (sbuf_len(pplist.unexec_scripts) > 0) {
+
		sbuf_finish(pplist.unexec_scripts);
+
		post_unexec_append(pplist.post_unexec_scripts, sbuf_data(pplist.unexec_scripts), "");
+
		sbuf_finish(pplist.post_unexec_scripts);
	}
-
	if (sbuf_len(post_unexec_scripts) > 0)
-
		pkg_appendscript(pkg, sbuf_data(post_unexec_scripts), PKG_SCRIPT_POST_DEINSTALL);
+
	if (sbuf_len(pplist.post_unexec_scripts) > 0)
+
		pkg_appendscript(pkg, sbuf_data(pplist.post_unexec_scripts), PKG_SCRIPT_POST_DEINSTALL);

	regfree(&preg1);
	regfree(&preg2);
-
	sbuf_delete(pre_unexec_scripts);
-
	sbuf_delete(exec_scripts);
-
	sbuf_delete(unexec_scripts);
+
	sbuf_delete(pplist.pre_unexec_scripts);
+
	sbuf_delete(pplist.exec_scripts);
+
	sbuf_delete(pplist.unexec_scripts);
	free(hardlinks.inodes);

	free(plist_buf);