PageRenderTime 26ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/register.c

https://gitlab.com/tunixman/pkg
C | 346 lines | 241 code | 46 blank | 59 comment | 67 complexity | 5bbf0018482917f3f4bee44ddab8e4b5 MD5 | raw file
  1. /*-
  2. * Copyright (c) 2011-2014 Baptiste Daroussin <bapt@FreeBSD.org>
  3. * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
  4. * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
  5. * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer
  13. * in this position and unchanged.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  19. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include <sys/param.h>
  30. #include <err.h>
  31. #include <stdio.h>
  32. #include <pkg.h>
  33. #include <string.h>
  34. #include <sysexits.h>
  35. #include <unistd.h>
  36. #include <stdlib.h>
  37. #include <stdbool.h>
  38. #include <regex.h>
  39. #include <getopt.h>
  40. #include "pkgcli.h"
  41. static const char * const scripts[] = {
  42. "+INSTALL",
  43. "+PRE_INSTALL",
  44. "+POST_INSTALL",
  45. "+POST_INSTALL",
  46. "+DEINSTALL",
  47. "+PRE_DEINSTALL",
  48. "+POST_DEINSTALL",
  49. "+UPGRADE",
  50. "+PRE_UPGRADE",
  51. "+POST_UPGRADE",
  52. "pkg-install",
  53. "pkg-pre-install",
  54. "pkg-post-install",
  55. "pkg-deinstall",
  56. "pkg-pre-deinstall",
  57. "pkg-post-deinstall",
  58. "pkg-upgrade",
  59. "pkg-pre-upgrade",
  60. "pkg-post-upgrade",
  61. NULL
  62. };
  63. void
  64. usage_register(void)
  65. {
  66. fprintf(stderr, "Usage: pkg register [-ldt] [-i <input-path>]"
  67. " [-f <plist-file>] -m <metadatadir>\n");
  68. fprintf(stderr, " pkg register [-ldt] [-i <input_path>]"
  69. " -M <manifest>\n\n");
  70. fprintf(stderr, "For more information see 'pkg help register'.\n");
  71. }
  72. int
  73. exec_register(int argc, char **argv)
  74. {
  75. struct pkg *pkg = NULL;
  76. struct pkgdb *db = NULL;
  77. struct pkg_manifest_key *keys = NULL;
  78. regex_t preg;
  79. regmatch_t pmatch[2];
  80. char *arch = NULL;
  81. char myarch[BUFSIZ];
  82. char *www = NULL;
  83. char fpath[MAXPATHLEN];
  84. const char *plist = NULL;
  85. const char *mdir = NULL;
  86. const char *mfile = NULL;
  87. const char *input_path = NULL;
  88. const char *desc = NULL;
  89. const char *location = NULL;
  90. size_t size;
  91. bool developer;
  92. bool legacy = false;
  93. bool __unused metadata_only = false;
  94. bool testing_mode = false;
  95. int ch;
  96. int i;
  97. int ret = EPKG_OK;
  98. int retcode = EX_OK;
  99. /* options descriptor */
  100. struct option longopts[] = {
  101. { "automatic", no_argument, NULL, 'A' },
  102. { "debug", no_argument, NULL, 'd' },
  103. { "legacy", no_argument, NULL, 'l' },
  104. { "manifest", required_argument, NULL, 'M' },
  105. { "metadata", required_argument, NULL, 'm' },
  106. { "plist", required_argument, NULL, 'f' },
  107. { "relocate", required_argument, NULL, 1 },
  108. { "root", required_argument, NULL, 'i' },
  109. { "test", no_argument, NULL, 't' },
  110. { NULL, 0, NULL, 0},
  111. };
  112. developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE"));
  113. if (pkg_new(&pkg, PKG_INSTALLED) != EPKG_OK)
  114. err(EX_OSERR, "malloc");
  115. while ((ch = getopt_long(argc, argv, "+Adf:i:lM:m:t", longopts, NULL)) != -1) {
  116. switch (ch) {
  117. case 'A':
  118. case 'd':
  119. pkg_set(pkg, PKG_AUTOMATIC, (bool)true);
  120. break;
  121. case 'f':
  122. plist = optarg;
  123. break;
  124. case 'i':
  125. input_path = optarg;
  126. break;
  127. case 'l':
  128. legacy = true;
  129. break;
  130. case 'M':
  131. metadata_only = true;
  132. mfile = optarg;
  133. break;
  134. case 'm':
  135. mdir = optarg;
  136. break;
  137. case 't':
  138. testing_mode = true;
  139. break;
  140. case 1:
  141. location = optarg;
  142. break;
  143. default:
  144. warnx("Unrecognised option -%c\n", ch);
  145. usage_register();
  146. pkg_free(pkg);
  147. return (EX_USAGE);
  148. }
  149. }
  150. retcode = pkgdb_access(PKGDB_MODE_READ |
  151. PKGDB_MODE_WRITE |
  152. PKGDB_MODE_CREATE,
  153. PKGDB_DB_LOCAL);
  154. if (retcode == EPKG_ENOACCESS) {
  155. warnx("Insufficient privileges to register packages");
  156. pkg_free(pkg);
  157. return (EX_NOPERM);
  158. } else if (retcode != EPKG_OK) {
  159. pkg_free(pkg);
  160. return (EX_IOERR);
  161. } else
  162. retcode = EX_OK;
  163. /*
  164. * Ideally, the +MANIFEST should be all that is necessary,
  165. * since it can contain all of the meta-data supplied by the
  166. * other files mentioned below. These are here for backwards
  167. * compatibility with the way the ports tree works with
  168. * pkg_tools.
  169. *
  170. * The -M option specifies one manifest file to read the
  171. * meta-data from, and overrides the use of legacy meta-data
  172. * inputs.
  173. *
  174. * Dependencies, shlibs, files etc. may be derived by
  175. * analysing the package files (maybe discovered as the
  176. * content of the staging directory) unless -t (testing_mode)
  177. * is used.
  178. */
  179. if (mfile != NULL && mdir != NULL) {
  180. warnx("Cannot use both -m and -M together");
  181. usage_register();
  182. pkg_free(pkg);
  183. return (EX_USAGE);
  184. }
  185. if (mfile == NULL && mdir == NULL) {
  186. warnx("One of either -m or -M flags is required");
  187. usage_register();
  188. pkg_free(pkg);
  189. return (EX_USAGE);
  190. }
  191. if (mfile != NULL && plist != NULL) {
  192. warnx("-M incompatible with -f option");
  193. usage_register();
  194. pkg_free(pkg);
  195. return (EX_USAGE);
  196. }
  197. if (testing_mode && input_path != NULL) {
  198. warnx("-i incompatible with -t option");
  199. usage_register();
  200. pkg_free(pkg);
  201. return (EX_USAGE);
  202. }
  203. pkg_manifest_keys_new(&keys);
  204. if (mfile != NULL) {
  205. ret = pkg_parse_manifest_file(pkg, mfile, keys);
  206. pkg_manifest_keys_free(keys);
  207. if (ret != EPKG_OK) {
  208. pkg_free(pkg);
  209. return (EX_IOERR);
  210. }
  211. } else {
  212. snprintf(fpath, sizeof(fpath), "%s/+MANIFEST", mdir);
  213. ret = pkg_parse_manifest_file(pkg, fpath, keys);
  214. pkg_manifest_keys_free(keys);
  215. if (ret != EPKG_OK) {
  216. pkg_free(pkg);
  217. return (EX_IOERR);
  218. }
  219. snprintf(fpath, sizeof(fpath), "%s/+DESC", mdir);
  220. if (access(fpath, F_OK) == 0)
  221. pkg_set_from_file(pkg, PKG_DESC, fpath, false);
  222. snprintf(fpath, sizeof(fpath), "%s/+DISPLAY", mdir);
  223. if (access(fpath, F_OK) == 0)
  224. pkg_set_from_file(pkg, PKG_MESSAGE, fpath, false);
  225. for (i = 0; scripts[i] != NULL; i++) {
  226. snprintf(fpath, sizeof(fpath), "%s/%s", mdir,
  227. scripts[i]);
  228. if (access(fpath, F_OK) == 0)
  229. pkg_addscript_file(pkg, fpath);
  230. }
  231. if (www != NULL) {
  232. pkg_set(pkg, PKG_WWW, www);
  233. free(www);
  234. }
  235. pkg_get(pkg, PKG_WWW, &www);
  236. /*
  237. * if www is not given then try to determine it from
  238. * description
  239. */
  240. if (www == NULL) {
  241. pkg_get(pkg, PKG_DESC, &desc);
  242. regcomp(&preg, "^WWW:[[:space:]]*(.*)$",
  243. REG_EXTENDED|REG_ICASE|REG_NEWLINE);
  244. if (regexec(&preg, desc, 2, pmatch, 0) == 0) {
  245. size = pmatch[1].rm_eo - pmatch[1].rm_so;
  246. www = strndup(&desc[pmatch[1].rm_so], size);
  247. pkg_set(pkg, PKG_WWW, www);
  248. free(www);
  249. } else {
  250. pkg_set(pkg, PKG_WWW, "UNKNOWN");
  251. }
  252. regfree(&preg);
  253. }
  254. if (plist != NULL)
  255. ret += ports_parse_plist(pkg, plist, input_path);
  256. }
  257. if (ret != EPKG_OK) {
  258. pkg_free(pkg);
  259. return (EX_IOERR);
  260. }
  261. if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
  262. pkg_free(pkg);
  263. return (EX_IOERR);
  264. }
  265. if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
  266. pkgdb_close(db);
  267. pkg_free(pkg);
  268. warnx("Cannot get an exclusive lock on a database, it is locked by another process");
  269. return (EX_TEMPFAIL);
  270. }
  271. /*
  272. * testing_mode allows updating the local package database
  273. * without any check that the files etc. listed in the meta
  274. * data actually exist on the system. Inappropriate use of
  275. * testing_mode can really screw things up.
  276. */
  277. if (!testing_mode)
  278. pkg_analyse_files(db, pkg, input_path);
  279. pkg_get(pkg, PKG_ABI, &arch);
  280. if (arch == NULL) {
  281. /*
  282. * do not take the one from configuration on purpose
  283. * but the real abi of the package.
  284. */
  285. pkg_get_myarch(myarch, BUFSIZ);
  286. if (developer)
  287. pkg_suggest_arch(pkg, myarch, true);
  288. pkg_set(pkg, PKG_ABI, myarch);
  289. } else {
  290. if (developer)
  291. pkg_suggest_arch(pkg, arch, false);
  292. }
  293. retcode = pkg_add_port(db, pkg, input_path, location, testing_mode);
  294. if (!legacy && retcode == EPKG_OK && messages != NULL) {
  295. sbuf_finish(messages);
  296. printf("%s\n", sbuf_data(messages));
  297. }
  298. pkg_free(pkg);
  299. return (retcode != EPKG_OK ? EX_SOFTWARE : EX_OK);
  300. }