Line data Source code
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 :
30 : #include <sys/param.h>
31 :
32 : #include <err.h>
33 : #include <stdio.h>
34 : #include <pkg.h>
35 : #include <string.h>
36 : #include <sysexits.h>
37 : #include <unistd.h>
38 : #include <stdlib.h>
39 : #include <stdbool.h>
40 : #include <regex.h>
41 : #include <getopt.h>
42 :
43 : #include "pkgcli.h"
44 :
45 : static const char * const scripts[] = {
46 : "+INSTALL",
47 : "+PRE_INSTALL",
48 : "+POST_INSTALL",
49 : "+POST_INSTALL",
50 : "+DEINSTALL",
51 : "+PRE_DEINSTALL",
52 : "+POST_DEINSTALL",
53 : "+UPGRADE",
54 : "+PRE_UPGRADE",
55 : "+POST_UPGRADE",
56 : "pkg-install",
57 : "pkg-pre-install",
58 : "pkg-post-install",
59 : "pkg-deinstall",
60 : "pkg-pre-deinstall",
61 : "pkg-post-deinstall",
62 : "pkg-upgrade",
63 : "pkg-pre-upgrade",
64 : "pkg-post-upgrade",
65 : NULL
66 : };
67 :
68 : void
69 0 : usage_register(void)
70 : {
71 0 : fprintf(stderr, "Usage: pkg register [-ldt] [-i <input-path>]"
72 : " [-f <plist-file>] -m <metadatadir>\n");
73 0 : fprintf(stderr, " pkg register [-ldt] [-i <input_path>]"
74 : " -M <manifest>\n\n");
75 0 : fprintf(stderr, "For more information see 'pkg help register'.\n");
76 0 : }
77 :
78 : int
79 19 : exec_register(int argc, char **argv)
80 : {
81 19 : struct pkg *pkg = NULL;
82 19 : struct pkgdb *db = NULL;
83 :
84 19 : struct pkg_manifest_key *keys = NULL;
85 :
86 : regex_t preg;
87 : regmatch_t pmatch[2];
88 :
89 19 : char *arch = NULL;
90 : char myarch[BUFSIZ];
91 19 : char *www = NULL;
92 : char fpath[MAXPATHLEN];
93 :
94 19 : const char *plist = NULL;
95 19 : const char *mdir = NULL;
96 19 : const char *mfile = NULL;
97 19 : const char *input_path = NULL;
98 19 : const char *desc = NULL;
99 19 : const char *location = NULL;
100 :
101 : size_t size;
102 :
103 : bool developer;
104 19 : bool legacy = false;
105 19 : bool __unused metadata_only = false;
106 19 : bool testing_mode = false;
107 :
108 : int ch;
109 : int i;
110 19 : int ret = EPKG_OK;
111 19 : int retcode = EX_OK;
112 :
113 : /* options descriptor */
114 19 : struct option longopts[] = {
115 : { "automatic", no_argument, NULL, 'A' },
116 : { "debug", no_argument, NULL, 'd' },
117 : { "legacy", no_argument, NULL, 'l' },
118 : { "manifest", required_argument, NULL, 'M' },
119 : { "metadata", required_argument, NULL, 'm' },
120 : { "plist", required_argument, NULL, 'f' },
121 : { "relocate", required_argument, NULL, 1 },
122 : { "root", required_argument, NULL, 'i' },
123 : { "test", no_argument, NULL, 't' },
124 : { NULL, 0, NULL, 0},
125 : };
126 :
127 19 : developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE"));
128 :
129 19 : if (pkg_new(&pkg, PKG_INSTALLED) != EPKG_OK)
130 0 : err(EX_OSERR, "malloc");
131 :
132 66 : while ((ch = getopt_long(argc, argv, "+Adf:i:lM:m:t", longopts, NULL)) != -1) {
133 28 : switch (ch) {
134 : case 'A':
135 : case 'd':
136 0 : pkg_set(pkg, PKG_AUTOMATIC, (bool)true);
137 0 : break;
138 : case 'f':
139 0 : plist = optarg;
140 0 : break;
141 : case 'i':
142 2 : input_path = optarg;
143 2 : break;
144 : case 'l':
145 0 : legacy = true;
146 0 : break;
147 : case 'M':
148 19 : metadata_only = true;
149 19 : mfile = optarg;
150 19 : break;
151 : case 'm':
152 0 : mdir = optarg;
153 0 : break;
154 : case 't':
155 7 : testing_mode = true;
156 7 : break;
157 : case 1:
158 0 : location = optarg;
159 0 : break;
160 : default:
161 0 : warnx("Unrecognised option -%c\n", ch);
162 0 : usage_register();
163 0 : return (EX_USAGE);
164 : }
165 : }
166 :
167 19 : retcode = pkgdb_access(PKGDB_MODE_READ |
168 : PKGDB_MODE_WRITE |
169 : PKGDB_MODE_CREATE,
170 : PKGDB_DB_LOCAL);
171 19 : if (retcode == EPKG_ENOACCESS) {
172 0 : warnx("Insufficient privileges to register packages");
173 0 : return (EX_NOPERM);
174 19 : } else if (retcode != EPKG_OK)
175 0 : return (EX_IOERR);
176 : else
177 19 : retcode = EX_OK;
178 :
179 : /*
180 : * Ideally, the +MANIFEST should be all that is necessary,
181 : * since it can contain all of the meta-data supplied by the
182 : * other files mentioned below. These are here for backwards
183 : * compatibility with the way the ports tree works with
184 : * pkg_tools.
185 : *
186 : * The -M option specifies one manifest file to read the
187 : * meta-data from, and overrides the use of legacy meta-data
188 : * inputs.
189 : *
190 : * Dependencies, shlibs, files etc. may be derived by
191 : * analysing the package files (maybe discovered as the
192 : * content of the staging directory) unless -t (testing_mode)
193 : * is used.
194 : */
195 :
196 19 : if (mfile != NULL && mdir != NULL) {
197 0 : warnx("Cannot use both -m and -M together");
198 0 : usage_register();
199 0 : pkg_free(pkg);
200 0 : return (EX_USAGE);
201 : }
202 :
203 :
204 19 : if (mfile == NULL && mdir == NULL) {
205 0 : warnx("One of either -m or -M flags is required");
206 0 : usage_register();
207 0 : pkg_free(pkg);
208 0 : return (EX_USAGE);
209 : }
210 :
211 19 : if (mfile != NULL && plist != NULL) {
212 0 : warnx("-M incompatible with -f option");
213 0 : usage_register();
214 0 : pkg_free(pkg);
215 0 : return (EX_USAGE);
216 : }
217 :
218 19 : if (testing_mode && input_path != NULL) {
219 0 : warnx("-i incompatible with -t option");
220 0 : usage_register();
221 0 : pkg_free(pkg);
222 0 : return (EX_USAGE);
223 : }
224 :
225 19 : pkg_manifest_keys_new(&keys);
226 :
227 19 : if (mfile != NULL) {
228 19 : ret = pkg_parse_manifest_file(pkg, mfile, keys);
229 19 : pkg_manifest_keys_free(keys);
230 19 : if (ret != EPKG_OK) {
231 0 : pkg_free(pkg);
232 0 : return (EX_IOERR);
233 : }
234 :
235 : } else {
236 0 : snprintf(fpath, sizeof(fpath), "%s/+MANIFEST", mdir);
237 0 : ret = pkg_parse_manifest_file(pkg, fpath, keys);
238 0 : pkg_manifest_keys_free(keys);
239 0 : if (ret != EPKG_OK) {
240 0 : pkg_free(pkg);
241 0 : return (EX_IOERR);
242 : }
243 :
244 0 : snprintf(fpath, sizeof(fpath), "%s/+DESC", mdir);
245 0 : pkg_set_from_file(pkg, PKG_DESC, fpath, false);
246 :
247 0 : snprintf(fpath, sizeof(fpath), "%s/+DISPLAY", mdir);
248 0 : if (access(fpath, F_OK) == 0)
249 0 : pkg_set_from_file(pkg, PKG_MESSAGE, fpath, false);
250 :
251 0 : for (i = 0; scripts[i] != NULL; i++) {
252 0 : snprintf(fpath, sizeof(fpath), "%s/%s", mdir,
253 : scripts[i]);
254 0 : if (access(fpath, F_OK) == 0)
255 0 : pkg_addscript_file(pkg, fpath);
256 : }
257 :
258 0 : if (www != NULL) {
259 0 : pkg_set(pkg, PKG_WWW, www);
260 0 : free(www);
261 : }
262 :
263 0 : pkg_get(pkg, PKG_WWW, &www);
264 :
265 : /*
266 : * if www is not given then try to determine it from
267 : * description
268 : */
269 :
270 0 : if (www == NULL) {
271 0 : pkg_get(pkg, PKG_DESC, &desc);
272 0 : regcomp(&preg, "^WWW:[[:space:]]*(.*)$",
273 : REG_EXTENDED|REG_ICASE|REG_NEWLINE);
274 0 : if (regexec(&preg, desc, 2, pmatch, 0) == 0) {
275 0 : size = pmatch[1].rm_eo - pmatch[1].rm_so;
276 0 : www = strndup(&desc[pmatch[1].rm_so], size);
277 0 : pkg_set(pkg, PKG_WWW, www);
278 0 : free(www);
279 : } else {
280 0 : pkg_set(pkg, PKG_WWW, "UNKNOWN");
281 : }
282 0 : regfree(&preg);
283 : }
284 :
285 0 : if (plist != NULL)
286 0 : ret += ports_parse_plist(pkg, plist, input_path);
287 : }
288 :
289 19 : if (ret != EPKG_OK) {
290 0 : pkg_free(pkg);
291 0 : return (EX_IOERR);
292 : }
293 :
294 :
295 19 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
296 0 : pkg_free(pkg);
297 0 : return (EX_IOERR);
298 : }
299 :
300 19 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
301 0 : pkgdb_close(db);
302 0 : pkg_free(pkg);
303 0 : warnx("Cannot get an exclusive lock on a database, it is locked by another process");
304 0 : return (EX_TEMPFAIL);
305 : }
306 :
307 : /*
308 : * testing_mode allows updating the local package database
309 : * without any check that the files etc. listed in the meta
310 : * data actually exist on the system. Inappropriate use of
311 : * testing_mode can really screw things up.
312 : */
313 :
314 19 : if (!testing_mode)
315 12 : pkg_analyse_files(db, pkg, input_path);
316 :
317 19 : pkg_get(pkg, PKG_ABI, &arch);
318 19 : if (arch == NULL) {
319 : /*
320 : * do not take the one from configuration on purpose
321 : * but the real abi of the package.
322 : */
323 13 : pkg_get_myarch(myarch, BUFSIZ);
324 13 : if (developer)
325 0 : pkg_suggest_arch(pkg, myarch, true);
326 13 : pkg_set(pkg, PKG_ABI, myarch);
327 : } else {
328 6 : if (developer)
329 0 : pkg_suggest_arch(pkg, arch, false);
330 : }
331 :
332 19 : retcode = pkg_add_port(db, pkg, input_path, location, testing_mode);
333 :
334 19 : if (!legacy && retcode == EPKG_OK && pkg_has_message(pkg))
335 0 : pkg_printf("%M\n", pkg);
336 :
337 19 : pkg_free(pkg);
338 :
339 19 : return (retcode != EPKG_OK ? EX_SOFTWARE : EX_OK);
340 : }
|