Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2020 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
5 : : * Copyright (c) 2015 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 : : #ifdef HAVE_CONFIG_H
31 : : #include "pkg_config.h"
32 : : #endif
33 : :
34 : : #include <sys/param.h>
35 : :
36 : : #ifdef PKG_COMPAT
37 : : #include <sys/stat.h>
38 : : #include <sys/types.h>
39 : : #include <dirent.h>
40 : : #endif
41 : :
42 : : #include <err.h>
43 : : #include <getopt.h>
44 : : #include <stdio.h>
45 : : #include <stdlib.h>
46 : : #include <pkg.h>
47 : : #include <string.h>
48 : : #include <strings.h>
49 : : #include <unistd.h>
50 : : #include <tllist.h>
51 : :
52 : : #include "pkgcli.h"
53 : :
54 : : tll(struct pkg *) pkg_head = tll_init();
55 : :
56 : : void
57 : 0 : usage_create(void)
58 : : {
59 : 0 : fprintf(stderr, "Usage: pkg create [-eOhnqv] [-f format] [-l level] "
60 : : "[-T threads] [-o outdir] [-p plist] [-r rootdir] -m metadatadir\n");
61 : 0 : fprintf(stderr, "Usage: pkg create [-eOhnqv] [-f format] [-l level] "
62 : : "[-T threads] [-o outdir] [-r rootdir] -M manifest\n");
63 : 0 : fprintf(stderr, " pkg create [-eOhgnqvx] [-f format] [-l level] "
64 : : "[-T threads] [-o outdir] [-r rootdir] pkg-name ...\n");
65 : 0 : fprintf(stderr, " pkg create [-eOhnqv] [-f format] [-l level] "
66 : : "[-T threads] [-o outdir] [-r rootdir] -a\n\n");
67 : 0 : fprintf(stderr, "For more information see 'pkg help create'.\n");
68 : 0 : }
69 : :
70 : : static int
71 : 0 : pkg_create_matches(int argc, char **argv, match_t match, struct pkg_create *pc)
72 : : {
73 : 0 : int i, ret = EPKG_OK, retcode = EXIT_SUCCESS;
74 : 0 : struct pkg *pkg = NULL;
75 : 0 : struct pkgdb *db = NULL;
76 : 0 : struct pkgdb_it *it = NULL;
77 : 0 : int query_flags = PKG_LOAD_DEPS | PKG_LOAD_FILES |
78 : : PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS |
79 : : PKG_LOAD_OPTIONS | PKG_LOAD_LICENSES |
80 : : PKG_LOAD_USERS | PKG_LOAD_GROUPS | PKG_LOAD_SHLIBS_REQUIRED |
81 : : PKG_LOAD_PROVIDES | PKG_LOAD_REQUIRES |
82 : : PKG_LOAD_SHLIBS_PROVIDED | PKG_LOAD_ANNOTATIONS | PKG_LOAD_LUA_SCRIPTS;
83 : : bool foundone;
84 : :
85 [ # # ]: 0 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
86 : 0 : pkgdb_close(db);
87 : 0 : return (EXIT_FAILURE);
88 : : }
89 : : /* XXX: get rid of hardcoded timeouts */
90 [ # # ]: 0 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
91 : 0 : pkgdb_close(db);
92 : 0 : warnx("Cannot get a read lock on a database, it is locked by another process");
93 : 0 : return (EXIT_FAILURE);
94 : : }
95 : :
96 [ # # # # : 0 : for (i = 0; i < argc || match == MATCH_ALL; i++) {
# # ]
97 [ # # ]: 0 : if (match == MATCH_ALL) {
98 : 0 : printf("Loading the package list...\n");
99 [ # # ]: 0 : if ((it = pkgdb_query(db, NULL, match)) == NULL) {
100 : 0 : retcode = EXIT_FAILURE;
101 : 0 : goto cleanup;
102 : : }
103 : 0 : match = !MATCH_ALL;
104 : 0 : } else {
105 [ # # ]: 0 : if ((it = pkgdb_query(db, argv[i], match)) == NULL) {
106 : 0 : retcode = EXIT_FAILURE;
107 : 0 : goto cleanup;
108 : : }
109 : : }
110 : :
111 : 0 : foundone = false;
112 [ # # ]: 0 : while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
113 [ # # # # : 0 : tll_push_back(pkg_head, pkg);
# # # # #
# ]
114 : 0 : pkg = NULL;
115 : 0 : foundone = true;
116 : : }
117 [ # # ]: 0 : if (!foundone) {
118 : 0 : warnx("No installed package matching \"%s\" found\n",
119 : 0 : argv[i]);
120 : 0 : retcode = EXIT_FAILURE;
121 : 0 : }
122 : :
123 : 0 : pkgdb_it_free(it);
124 [ # # ]: 0 : if (ret != EPKG_END)
125 : 0 : retcode = EXIT_FAILURE;
126 : 0 : }
127 : :
128 [ # # # # : 0 : tll_foreach(pkg_head, el) {
# # ]
129 : 0 : pkg_printf("Creating package for %n-%v\n", el->item, el->item);
130 : 0 : ret = pkg_create_i(pc, el->item, false);
131 [ # # ]: 0 : if (ret == EPKG_EXIST) {
132 : 0 : pkg_printf("%n-%v already packaged, skipping...\n",
133 : 0 : el->item, el->item);
134 : 0 : }
135 [ # # # # ]: 0 : if (ret != EPKG_OK && ret != EPKG_EXIST)
136 : 0 : retcode = EXIT_FAILURE;
137 [ # # # # : 0 : tll_remove_and_free(pkg_head, el, pkg_free);
# # ]
138 : 0 : }
139 : :
140 : : cleanup:
141 : 0 : pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
142 : 0 : pkgdb_close(db);
143 : :
144 : 0 : return (retcode);
145 : 0 : }
146 : :
147 : : /*
148 : : * options:
149 : : * -M: manifest file
150 : : * -f <format>: format could be tzst, txz, tgz, tbz or tar
151 : : * -g: globbing
152 : : * -h: pkg name with hash and symlink
153 : : * -m: path to dir where to find the metadata
154 : : * -o: output directory where to create packages by default ./ is used
155 : : * -q: quiet mode
156 : : * -r: rootdir for the package
157 : : * -x: regex
158 : : */
159 : :
160 : : int
161 : 282 : exec_create(int argc, char **argv)
162 : : {
163 : : struct pkg_create *pc;
164 : 282 : match_t match = MATCH_EXACT;
165 : 282 : const char *outdir = NULL;
166 : 282 : const char *format = NULL;
167 : 282 : const char *rootdir = NULL;
168 : 282 : const char *metadatadir = NULL;
169 : 282 : const char *manifest = NULL;
170 : 282 : char *plist = NULL;
171 : : char *endptr;
172 : : int ch;
173 : : int level;
174 : 282 : bool level_is_set = false;
175 : : int threads;
176 : 282 : bool threads_is_set = false;
177 : : int ret;
178 : 282 : bool hash = false;
179 : 282 : bool overwrite = true;
180 : 282 : bool expand_manifest = false;
181 : 282 : time_t ts = (time_t)-1;
182 : :
183 : : /* Sentinel values: INT_MIN (fast), -1 (default per pkg),
184 : : * 0 (default per libarchive), INT_MAX (best). */
185 : 282 : level = -1;
186 : :
187 : : /* POLA: pkg create is quiet by default, unless
188 : : * PKG_CREATE_VERBOSE is set in pkg.conf. This is for
189 : : * historical reasons. */
190 : :
191 : 282 : quiet = !pkg_object_bool(pkg_config_get("PKG_CREATE_VERBOSE"));
192 : :
193 : 282 : struct option longopts[] = {
194 : : { "all", no_argument, NULL, 'a' },
195 : : { "expand-manifest", no_argument, NULL, 'e' },
196 : : { "format", required_argument, NULL, 'f' },
197 : : { "glob", no_argument, NULL, 'g' },
198 : : { "hash", no_argument, NULL, 'h' },
199 : : { "level", required_argument, NULL, 'l' },
200 : : { "regex", no_argument, NULL, 'x' },
201 : : { "root-dir", required_argument, NULL, 'r' },
202 : : { "metadata", required_argument, NULL, 'm' },
203 : : { "manifest", required_argument, NULL, 'M' },
204 : : { "no-clobber", no_argument, NULL, 'n' },
205 : : { "out-dir", required_argument, NULL, 'o' },
206 : : { "plist", required_argument, NULL, 'p' },
207 : : { "quiet", no_argument, NULL, 'q' },
208 : : { "timestamp", required_argument, NULL, 't' },
209 : : { "verbose", no_argument, NULL, 'v' },
210 : : { NULL, 0, NULL, 0 },
211 : : };
212 : :
213 [ + + ]: 801 : while ((ch = getopt_long(argc, argv, "+aeghxf:l:r:m:M:no:p:qvt:T:", longopts, NULL)) != -1) {
214 [ - - + - : 520 : switch (ch) {
+ + + + +
+ + + - -
+ - - - ]
215 : : case 'a':
216 : 0 : match = MATCH_ALL;
217 : 0 : break;
218 : : case 'e':
219 : 0 : expand_manifest = true;
220 : 0 : break;
221 : : case 'f':
222 : 3 : format = optarg;
223 : 3 : break;
224 : : case 'g':
225 : 0 : match = MATCH_GLOB;
226 : 0 : break;
227 : : case 'h':
228 : 1 : hash = true;
229 : 1 : break;
230 : : case 'l':
231 : : {
232 : : const char *errstr;
233 : :
234 : 0 : level_is_set = true;
235 : 0 : level = strtonum(optarg, -200, 200, &errstr);
236 [ # # ]: 0 : if (errstr == NULL)
237 : 0 : break;
238 [ # # ]: 0 : if (STRIEQ(optarg, "best")) {
239 : 0 : level = INT_MAX;
240 : 0 : break;
241 [ # # ]: 0 : } else if (STRIEQ(optarg, "fast")) {
242 : 0 : level = INT_MIN;
243 : 0 : break;
244 : : }
245 : 0 : warnx("Invalid compression level %s", optarg);
246 : 0 : return (EXIT_FAILURE);
247 : : }
248 : : case 'm':
249 : 35 : metadatadir = optarg;
250 : 35 : break;
251 : : case 'M':
252 : 246 : manifest = optarg;
253 : 246 : break;
254 : : case 'o':
255 : 94 : outdir = optarg;
256 : 94 : break;
257 : : case 'n':
258 : 1 : overwrite = false;
259 : 1 : break;
260 : : case 'p':
261 : 73 : plist = optarg;
262 : 73 : break;
263 : : case 'q':
264 : 1 : quiet = true;
265 : 1 : break;
266 : : case 'r':
267 : 63 : rootdir = optarg;
268 : 63 : break;
269 : : case 't':
270 : 3 : endptr = NULL;
271 : 3 : ts = (time_t)strtoimax(optarg, &endptr, 10);
272 [ + + ]: 3 : if (*endptr != '\0') {
273 : 1 : warnx("Invalid timestamp %s", optarg);
274 : 1 : return (EXIT_FAILURE);
275 : : }
276 : 2 : break;
277 : : case 'T':
278 : : {
279 : : const char *errstr;
280 : :
281 : 0 : threads_is_set = true;
282 : 0 : threads = strtonum(optarg, 0, INT_MAX, &errstr);
283 [ # # ]: 0 : if (errstr == NULL)
284 : 0 : break;
285 [ # # ]: 0 : if (STRIEQ(optarg, "auto")) {
286 : 0 : threads = 0;
287 : 0 : break;
288 : : }
289 : 0 : warnx("Invalid compression threads %s", optarg);
290 : 0 : return (EXIT_FAILURE);
291 : : }
292 : : case 'v':
293 : 0 : quiet = false;
294 : 0 : break;
295 : : case 'x':
296 : 0 : match = MATCH_REGEX;
297 : 0 : break;
298 : : default:
299 : 0 : usage_create();
300 : 0 : return (EXIT_FAILURE);
301 : : }
302 : : }
303 : 281 : argc -= optind;
304 : 281 : argv += optind;
305 : :
306 [ + - + + : 281 : if (match != MATCH_ALL && metadatadir == NULL && manifest == NULL &&
+ - # # ]
307 : 0 : argc == 0) {
308 : 0 : usage_create();
309 : 0 : return (EXIT_FAILURE);
310 : : }
311 : :
312 [ + + - + : 281 : if (metadatadir == NULL && manifest == NULL && rootdir != NULL) {
# # ]
313 : 0 : warnx("Do not specify a rootdir without also specifying "
314 : : "either a metadatadir or manifest");
315 : 0 : usage_create();
316 : 0 : return (EXIT_FAILURE);
317 : : }
318 : :
319 [ + + ]: 281 : if (outdir == NULL)
320 : 187 : outdir = "./";
321 : :
322 : 281 : pc = pkg_create_new();
323 [ + + ]: 281 : if (format != NULL) {
324 [ + - ]: 3 : if (format[0] == '.')
325 : 0 : ++format;
326 [ + - ]: 3 : if (!pkg_create_set_format(pc, format))
327 : 0 : warnx("unknown format %s, using the default", format);
328 : 3 : }
329 [ + - ]: 281 : if (level_is_set)
330 : 0 : pkg_create_set_compression_level(pc, level);
331 [ + - ]: 281 : if (threads_is_set)
332 : 0 : pkg_create_set_compression_threads(pc, threads);
333 : 281 : pkg_create_set_overwrite(pc, overwrite);
334 : 281 : pkg_create_set_rootdir(pc, rootdir);
335 : 281 : pkg_create_set_output_dir(pc, outdir);
336 : 281 : pkg_create_set_expand_manifest(pc, expand_manifest);
337 [ + + ]: 281 : if (ts != (time_t)-1)
338 : 2 : pkg_create_set_timestamp(pc, ts);
339 : :
340 [ + + + - ]: 281 : if (metadatadir == NULL && manifest == NULL) {
341 : 0 : ret = pkg_create_matches(argc, argv, match, pc);
342 : 0 : pkg_create_free(pc);
343 : 0 : return (ret == EPKG_OK ? EXIT_SUCCESS : EXIT_FAILURE);
344 : : }
345 [ + + ]: 281 : ret = pkg_create(pc, metadatadir != NULL ? metadatadir : manifest, plist,
346 : 281 : hash);
347 : 281 : pkg_create_free(pc);
348 [ + + + + ]: 281 : if (ret == EPKG_EXIST || ret == EPKG_OK)
349 : 264 : return (EXIT_SUCCESS);
350 : 17 : return (EXIT_FAILURE);
351 : 282 : }
352 : :
|