コード例 #1
0
ファイル: pkg_manifest.c プロジェクト: grtodd/pkg
static int
pkg_string(struct pkg *pkg, ucl_object_t *obj, int attr)
{
	int ret = EPKG_OK;
	const char *str;
	str = ucl_object_tostring_forced(obj);

	switch (attr)
	{
	case PKG_INFOS:
		pkg_addannotation(pkg, "_INFOS_", str);
		break;
	case PKG_LICENSE_LOGIC:
		if (!strcmp(str, "single"))
			pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t) LICENSE_SINGLE);
		else if (!strcmp(str, "or") ||
		         !strcmp(str, "dual"))
			pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_OR);
		else if (!strcmp(str, "and") ||
		         !strcmp(str, "multi"))
			pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_AND);
		else {
			pkg_emit_error("Unknown license logic: %s", str);
			ret = EPKG_FATAL;
		}
		break;
	default:
		if (attr == PKG_DESC)
			ret = urldecode(str, &pkg->fields[attr]);
		else
			ret = pkg_set(pkg, attr, str);
		break;
	}

	return (ret);
}
コード例 #2
0
ファイル: register.c プロジェクト: ppentchev/pkg
int
exec_register(int argc, char **argv)
{
	struct pkg	*pkg = NULL;
	struct pkgdb	*db  = NULL;

	struct pkg_manifest_key *keys = NULL;

	regex_t		 preg;
	regmatch_t	 pmatch[2];

	char		*arch = NULL;
	char		 myarch[BUFSIZ];
	char		*www  = NULL;
	char		 fpath[MAXPATHLEN];

	const char	*plist      = NULL;
	const char	*mdir       = NULL;
	const char	*mfile      = NULL;
	const char	*input_path = NULL;
	const char	*desc       = NULL;
	const char	*location   = NULL;

	size_t		 size;

	bool		 developer;
	bool		 legacy        = false;
	bool		 old           = false;
	bool		 __unused metadata_only = false;
	bool		 testing_mode  = false;

	int		 ch;
	int		 i;
	int		 ret     = EPKG_OK;
	int		 retcode = EX_OK;

	/* options descriptor */
	struct option longopts[] = {
		{ "automatic",	no_argument,		NULL,	'A' },
		{ "plist",	required_argument,	NULL,	'f' },
		{ "root",	required_argument,	NULL,	'i' },
		{ "legacy",	no_argument,		NULL,	'l' },
		{ "manifest",	required_argument,	NULL,	'M' },
		{ "metadata",	required_argument,	NULL,	'm' },
		{ "old",	no_argument,		NULL,	'O' },
		{ "test",	no_argument,		NULL,	't' },
		{ "relocate",	required_argument,	NULL, 	1 },
		{ NULL,		0,			NULL,	0},
	};

	developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE"));

	if (pkg_new(&pkg, PKG_INSTALLED) != EPKG_OK)
		err(EX_OSERR, "malloc");

	while ((ch = getopt_long(argc, argv, "Adf:i:lM:m:Ot", longopts, NULL)) != -1) {
		switch (ch) {
		case 'A':
		case 'd':
			pkg_set(pkg, PKG_AUTOMATIC, (bool)true);
			break;
		case 'f':
			plist = optarg;
			break;
		case 'i':
			input_path = optarg;
			break;
		case 'l':
			legacy = true;
			break;
		case 'M':
			metadata_only = true;
			mfile = optarg;
			break;
		case 'm':
			mdir = optarg;
			break;
		case 'O':
			old = true;
			break;
		case 't':
			testing_mode = true;
			break;
		case 1:
			location = optarg;
			break;
		default:
			warnx("Unrecognised option -%c\n", ch);
			usage_register();
			return (EX_USAGE);
		}
	}

	if (!old) {
		retcode = pkgdb_access(PKGDB_MODE_READ  |
				       PKGDB_MODE_WRITE |
				       PKGDB_MODE_CREATE,
				       PKGDB_DB_LOCAL);
		if (retcode == EPKG_ENOACCESS) {
			warnx("Insufficient privileges to register packages");
			return (EX_NOPERM);
		} else if (retcode != EPKG_OK)
			return (EX_IOERR);
		else
			retcode = EX_OK;
	}

	/*
	 * Ideally, the +MANIFEST should be all that is necessary,
	 * since it can contain all of the meta-data supplied by the
	 * other files mentioned below.  These are here for backwards
	 * compatibility with the way the ports tree works with
	 * pkg_tools.
	 * 
	 * The -M option specifies one manifest file to read the
	 * meta-data from, and overrides the use of legacy meta-data
	 * inputs.
	 *
	 * Dependencies, shlibs, files etc. may be derived by
	 * analysing the package files (maybe discovered as the
	 * content of the staging directory) unless -t (testing_mode)
	 * is used.
	 */

	if (mfile != NULL && mdir != NULL) {
		warnx("Cannot use both -m and -M together");
		usage_register();
		return (EX_USAGE);
	}


	if (mfile == NULL && mdir == NULL) {
		warnx("One of either -m or -M flags is required");
		usage_register();
		return (EX_USAGE);
	}

	if (mfile != NULL && plist != NULL) {
		warnx("-M incompatible with -f option");
		usage_register();
		return (EX_USAGE);
	}

	if (testing_mode && input_path != NULL) {
		warnx("-i incompatible with -t option");
		usage_register();
		return (EX_USAGE);
	}

	pkg_manifest_keys_new(&keys);

	if (mfile != NULL) {
		ret = pkg_parse_manifest_file(pkg, mfile, keys);
		pkg_manifest_keys_free(keys);
		if (ret != EPKG_OK) 
			return (EX_IOERR);

	} else {
		snprintf(fpath, sizeof(fpath), "%s/+MANIFEST", mdir);
		ret = pkg_parse_manifest_file(pkg, fpath, keys);
		pkg_manifest_keys_free(keys);
		if (ret != EPKG_OK)
			return (EX_IOERR);


		snprintf(fpath, sizeof(fpath), "%s/+DESC", mdir);
		pkg_set_from_file(pkg, PKG_DESC, fpath, false);

		snprintf(fpath, sizeof(fpath), "%s/+DISPLAY", mdir);
		if (access(fpath, F_OK) == 0)
			pkg_set_from_file(pkg, PKG_MESSAGE, fpath, false);

		snprintf(fpath, sizeof(fpath), "%s/+MTREE_DIRS", mdir);
		if (access(fpath, F_OK) == 0)
			pkg_set_from_file(pkg, PKG_MTREE, fpath, false);

		for (i = 0; scripts[i] != NULL; i++) {
			snprintf(fpath, sizeof(fpath), "%s/%s", mdir,
			    scripts[i]);
			if (access(fpath, F_OK) == 0)
				pkg_addscript_file(pkg, fpath);
		}

		if (www != NULL) {
			pkg_set(pkg, PKG_WWW, www);
			free(www);
		}

		pkg_get(pkg, PKG_WWW, &www);

		/* 
		 * if www is not given then try to determine it from
		 * description
		 */

		if (www == NULL) {
			pkg_get(pkg, PKG_DESC, &desc);
			regcomp(&preg, "^WWW:[[:space:]]*(.*)$",
			    REG_EXTENDED|REG_ICASE|REG_NEWLINE);
			if (regexec(&preg, desc, 2, pmatch, 0) == 0) {
				size = pmatch[1].rm_eo - pmatch[1].rm_so;
				www = strndup(&desc[pmatch[1].rm_so], size);
				pkg_set(pkg, PKG_WWW, www);
				free(www);
			} else {
				pkg_set(pkg, PKG_WWW, "UNKNOWN");
			}
			regfree(&preg);
		}

		if (plist != NULL)
			ret += ports_parse_plist(pkg, plist, input_path);
	}

	if (ret != EPKG_OK) {
		return (EX_IOERR);
	}


	if (!old) {
		if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
			return (EX_IOERR);

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

	/*
	 * testing_mode allows updating the local package database
	 * without any check that the files etc. listed in the meta
	 * data actually exist on the system.  Inappropriate use of
	 * testing_mode can really screw things up.
	 */

	if (!testing_mode)
		pkg_analyse_files(db, pkg, input_path);

	pkg_get(pkg, PKG_ARCH, &arch);
	if (arch == NULL) {
		/*
		 * do not take the one from configuration on purpose
		 * but the real abi of the package.
		 */
		pkg_get_myarch(myarch, BUFSIZ);
		if (developer)
			pkg_suggest_arch(pkg, myarch, true);
		pkg_set(pkg, PKG_ARCH, myarch);
	} else {
		if (developer)
			pkg_suggest_arch(pkg, arch, false);
	}

	if (!testing_mode && input_path != NULL)
		pkg_copy_tree(pkg, input_path, location ? location : "/");
	
	if (location != NULL)
		pkg_addannotation(pkg, "relocated", location);

	if (old) {
		if (pkg_register_old(pkg) != EPKG_OK)
			retcode = EX_SOFTWARE;
	} else {
		if (pkgdb_register_ports(db, pkg) != EPKG_OK)
			retcode = EX_SOFTWARE;
	}

	if (!legacy && pkg_has_message(pkg))
		pkg_printf("%M\n", pkg);

	if (!old) {
		pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
		pkgdb_close(db);
	}

	pkg_free(pkg);

	return (retcode);
}
コード例 #3
0
ファイル: pkg_manifest.c プロジェクト: grtodd/pkg
static int
pkg_object(struct pkg *pkg, ucl_object_t *obj, int attr)
{
	struct sbuf *tmp = NULL;
	ucl_object_t *cur;
	ucl_object_iter_t it = NULL;
	pkg_script script_type;
	const char *key, *buf;
	size_t len;

	pkg_debug(3, "%s", "Manifest: parsing object");
	while ((cur = ucl_iterate_object(obj, &it, true))) {
		key = ucl_object_key(cur);
		if (key == NULL)
			continue;
		switch (attr) {
		case PKG_DEPS:
			if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY)
				pkg_emit_error("Skipping malformed dependency %s",
				    key);
			else
				pkg_set_deps_from_object(pkg, cur);
			break;
		case PKG_DIRS:
			if (cur->type != UCL_OBJECT)
				pkg_emit_error("Skipping malformed dirs %s",
				    key);
			else
				pkg_set_dirs_from_object(pkg, cur);
			break;
		case PKG_USERS:
			if (cur->type == UCL_STRING)
				pkg_adduid(pkg, key, ucl_object_tostring(cur));
			else
				pkg_emit_error("Skipping malformed users %s",
				    key);
			break;
		case PKG_GROUPS:
			if (cur->type == UCL_STRING)
				pkg_addgid(pkg, key, ucl_object_tostring(cur));
			else
				pkg_emit_error("Skipping malformed groups %s",
				    key);
			break;
		case PKG_DIRECTORIES:
			if (cur->type == UCL_BOOLEAN) {
				urldecode(key, &tmp);
				pkg_adddir(pkg, sbuf_data(tmp), ucl_object_toboolean(cur), false);
			} else if (cur->type == UCL_OBJECT) {
				pkg_set_dirs_from_object(pkg, cur);
			} else if (cur->type == UCL_STRING) {
				urldecode(key, &tmp);
				if (ucl_object_tostring(cur)[0] == 'y')
					pkg_adddir(pkg, sbuf_data(tmp), 1, false);
				else
					pkg_adddir(pkg, sbuf_data(tmp), 0, false);
			} else {
				pkg_emit_error("Skipping malformed directories %s",
				    key);
			}
			break;
		case PKG_FILES:
			if (cur->type == UCL_STRING) {
				buf = ucl_object_tolstring(cur, &len);
				urldecode(key, &tmp);
				pkg_addfile(pkg, sbuf_get(tmp), len == 64 ? buf : NULL, false);
			} else if (cur->type == UCL_OBJECT)
				pkg_set_files_from_object(pkg, cur);
			else
				pkg_emit_error("Skipping malformed files %s",
				   key);
			break;
		case PKG_OPTIONS:
			if (cur->type != UCL_STRING && cur->type != UCL_BOOLEAN)
				pkg_emit_error("Skipping malformed option %s",
				    key);
			else
				pkg_addoption(pkg, key, ucl_object_tostring_forced(cur));
			break;
		case PKG_OPTION_DEFAULTS:
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option default %s",
				    key);
			else
				pkg_addoption_default(pkg, key,
				    ucl_object_tostring(cur));
			break;
		case PKG_OPTION_DESCRIPTIONS:
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed option description %s",
				    key);
			else
				pkg_addoption_description(pkg, key,
				    ucl_object_tostring(cur));
			break;
		case PKG_SCRIPTS:
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed scripts %s",
				    key);
			else {
				script_type = script_type_str(key);
				if (script_type == PKG_SCRIPT_UNKNOWN) {
					pkg_emit_error("Skipping unknown script "
					    "type: %s", key);
					break;
				}

				urldecode(ucl_object_tostring(cur), &tmp);
				pkg_addscript(pkg, sbuf_data(tmp), script_type);
			}
			break;
		case PKG_ANNOTATIONS:
			if (cur->type != UCL_STRING)
				pkg_emit_error("Skipping malformed annotation %s",
				    key);
			else
				pkg_addannotation(pkg, key, ucl_object_tostring(cur));
			break;
		}
	}

	sbuf_free(tmp);

	return (EPKG_OK);
}
コード例 #4
0
ファイル: pkg_add.c プロジェクト: ppentchev/pkg
int
pkg_add(struct pkgdb *db, const char *path, unsigned flags,
    struct pkg_manifest_key *keys, const char *location)
{
	const char	*arch;
	const char	*origin;
	const char	*name;
	struct archive	*a;
	struct archive_entry *ae;
	struct pkg	*pkg = NULL;
	struct pkg_dep	*dep = NULL;
	struct pkg      *pkg_inst = NULL;
	bool		 extract = true;
	bool		 handle_rc = false;
	bool		 disable_mtree;
	char		 dpath[MAXPATHLEN];
	const char	*basedir;
	const char	*ext;
	char		*mtree;
	char		*prefix;
	int		 retcode = EPKG_OK;
	int		 ret;

	assert(path != NULL);

	/*
	 * Open the package archive file, read all the meta files and set the
	 * current archive_entry to the first non-meta file.
	 * If there is no non-meta files, EPKG_END is returned.
	 */
	ret = pkg_open2(&pkg, &a, &ae, path, keys, 0, -1);
	if (ret == EPKG_END)
		extract = false;
	else if (ret != EPKG_OK) {
		retcode = ret;
		goto cleanup;
	}
	if ((flags & PKG_ADD_UPGRADE) == 0)
		pkg_emit_install_begin(pkg);

	if (pkg_is_valid(pkg) != EPKG_OK) {
		pkg_emit_error("the package is not valid");
		return (EPKG_FATAL);
	}

	if (flags & PKG_ADD_AUTOMATIC)
		pkg_set(pkg, PKG_AUTOMATIC, (bool)true);

	/*
	 * Check the architecture
	 */

	pkg_get(pkg, PKG_ARCH, &arch, PKG_ORIGIN, &origin, PKG_NAME, &name);

	if (!is_valid_abi(arch, true)) {
		if ((flags & PKG_ADD_FORCE) == 0) {
			retcode = EPKG_FATAL;
			goto cleanup;
		}
	}

	/*
	 * Check if the package is already installed
	 */

	ret = pkg_try_installed(db, origin, &pkg_inst, PKG_LOAD_BASIC);
	if (ret == EPKG_OK) {
		if ((flags & PKG_ADD_FORCE) == 0) {
			pkg_emit_already_installed(pkg_inst);
			retcode = EPKG_INSTALLED;
			pkg_free(pkg_inst);
			pkg_inst = NULL;
			goto cleanup;
		}
		else {
			pkg_emit_notice("package %s is already installed, forced install", name);
			pkg_free(pkg_inst);
			pkg_inst = NULL;
		}
	} else if (ret != EPKG_END) {
		retcode = ret;
		goto cleanup;
	}

	/*
	 * Check for dependencies by searching the same directory as
	 * the package archive we're reading.  Of course, if we're
	 * reading from a file descriptor or a unix domain socket or
	 * somesuch, there's no valid directory to search.
	 */

	if (strncmp(path, "-", 2) != 0 && (flags & PKG_ADD_UPGRADE) == 0) {
		basedir = dirname(path);
		if ((ext = strrchr(path, '.')) == NULL) {
			pkg_emit_error("%s has no extension", path);
			retcode = EPKG_FATAL;
			goto cleanup;
		}
	} else {
		basedir = NULL;
		ext = NULL;
	}

	while (pkg_deps(pkg, &dep) == EPKG_OK) {
		if (pkg_is_installed(db, pkg_dep_origin(dep)) == EPKG_OK)
			continue;

		if (basedir != NULL) {
			const char *dep_name = pkg_dep_name(dep);
			const char *dep_ver = pkg_dep_version(dep);

			snprintf(dpath, sizeof(dpath), "%s/%s-%s%s", basedir,
			    dep_name, dep_ver, ext);

			if ((flags & PKG_ADD_UPGRADE) == 0 &&
			    access(dpath, F_OK) == 0) {
				ret = pkg_add(db, dpath, PKG_ADD_AUTOMATIC, keys, location);
				if (ret != EPKG_OK) {
					retcode = EPKG_FATAL;
					goto cleanup;
				}
			} else {
				pkg_emit_error("Missing dependency matching "
				    "Origin: '%s' Version: '%s'",
				    pkg_dep_get(dep, PKG_DEP_ORIGIN),
				    pkg_dep_get(dep, PKG_DEP_VERSION));
				if ((flags & PKG_ADD_FORCE_MISSING) == 0) {
					retcode = EPKG_FATAL;
					goto cleanup;
				}
			}
		} else {
			retcode = EPKG_FATAL;
			pkg_emit_missing_dep(pkg, dep);
			goto cleanup;
		}
	}

	if (location != NULL)
		pkg_addannotation(pkg, "relocated", location);

	/* register the package before installing it in case there are
	 * problems that could be caught here. */
	retcode = pkgdb_register_pkg(db, pkg, flags & PKG_ADD_UPGRADE, flags & PKG_ADD_FORCE);

	if (retcode != EPKG_OK)
		goto cleanup;

	/* MTREE replicates much of the standard functionality
	 * inplicit in the way pkg works.  It has to remain available
	 * in the ports for compatibility with the old pkg_tools, but
	 * ultimately, MTREE should be made redundant.  Use this for
	 * experimantal purposes and to develop MTREE-free versions of
	 * packages. */

	disable_mtree = pkg_object_bool(pkg_config_get("DISABLE_MTREE"));
	if (!disable_mtree) {
		pkg_get(pkg, PKG_PREFIX, &prefix, PKG_MTREE, &mtree);
		if ((retcode = do_extract_mtree(mtree, prefix)) != EPKG_OK)
			goto cleanup_reg;
	}

	/*
	 * Execute pre-install scripts
	 */
	if ((flags & (PKG_ADD_NOSCRIPT | PKG_ADD_USE_UPGRADE_SCRIPTS)) == 0)
		pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL);

	/* add the user and group if necessary */
	/* pkg_add_user_group(pkg); */

	/*
	 * Extract the files on disk.
	 */
	if (extract && (retcode = do_extract(a, ae, location)) != EPKG_OK) {
		/* If the add failed, clean up (silently) */
		pkg_delete_files(pkg, 2);
		pkg_delete_dirs(db, pkg, 1);
		goto cleanup_reg;
	}

	/*
	 * Execute post install scripts
	 */
	if ((flags & PKG_ADD_NOSCRIPT) == 0) {
		if ((flags & PKG_ADD_USE_UPGRADE_SCRIPTS) == PKG_ADD_USE_UPGRADE_SCRIPTS)
			pkg_script_run(pkg, PKG_SCRIPT_POST_UPGRADE);
		else
			pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL);
	}

	/*
	 * start the different related services if the users do want that
	 * and that the service is running
	 */

	handle_rc = pkg_object_bool(pkg_config_get("HANDLE_RC_SCRIPTS"));
	if (handle_rc)
		pkg_start_stop_rc_scripts(pkg, PKG_RC_START);

	cleanup_reg:
	if ((flags & PKG_ADD_UPGRADE) == 0)
		pkgdb_register_finale(db, retcode);

	if (retcode == EPKG_OK && (flags & PKG_ADD_UPGRADE) == 0)
		pkg_emit_install_finished(pkg);

	cleanup:
	if (a != NULL) {
		archive_read_close(a);
		archive_read_free(a);
	}

	pkg_free(pkg);

	if (pkg_inst != NULL)
		pkg_free(pkg_inst);

	return (retcode);
}