Line data Source code
1 : /*-
2 : * Copyright (c) 2011-2015 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 : #include <sys/queue.h>
36 :
37 : #ifdef PKG_COMPAT
38 : #include <sys/stat.h>
39 : #include <sys/types.h>
40 : #include <dirent.h>
41 : #endif
42 :
43 : #include <err.h>
44 : #include <getopt.h>
45 : #include <stdio.h>
46 : #include <pkg.h>
47 : #include <string.h>
48 : #include <unistd.h>
49 : #include <sysexits.h>
50 :
51 : #include "pkgcli.h"
52 :
53 : struct pkg_entry {
54 : struct pkg *pkg;
55 : STAILQ_ENTRY(pkg_entry) next;
56 : };
57 :
58 : STAILQ_HEAD(pkg_head, pkg_entry);
59 :
60 : void
61 0 : usage_create(void)
62 : {
63 0 : fprintf(stderr, "Usage: pkg create [-Onqv] [-f format] [-o outdir] "
64 : "[-p plist] [-r rootdir] -m metadatadir\n");
65 0 : fprintf(stderr, "Usage: pkg create [-Onqv] [-f format] [-o outdir] "
66 : "[-r rootdir] -M manifest\n");
67 0 : fprintf(stderr, " pkg create [-Ognqvx] [-f format] [-o outdir] "
68 : "[-r rootdir] pkg-name ...\n");
69 0 : fprintf(stderr, " pkg create [-Onqv] [-f format] [-o outdir] "
70 : "[-r rootdir] -a\n\n");
71 0 : fprintf(stderr, "For more information see 'pkg help create'.\n");
72 0 : }
73 :
74 : static int
75 0 : pkg_create_matches(int argc, char **argv, match_t match, pkg_formats fmt,
76 : const char * const outdir, bool overwrite)
77 : {
78 0 : int i, ret = EPKG_OK, retcode = EPKG_OK;
79 0 : struct pkg *pkg = NULL;
80 0 : struct pkgdb *db = NULL;
81 0 : struct pkgdb_it *it = NULL;
82 0 : int query_flags = PKG_LOAD_DEPS | PKG_LOAD_FILES |
83 : PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS |
84 : PKG_LOAD_OPTIONS | PKG_LOAD_LICENSES |
85 : PKG_LOAD_USERS | PKG_LOAD_GROUPS | PKG_LOAD_SHLIBS_REQUIRED |
86 : PKG_LOAD_PROVIDES | PKG_LOAD_REQUIRES |
87 : PKG_LOAD_SHLIBS_PROVIDED | PKG_LOAD_ANNOTATIONS;
88 0 : struct pkg_head head = STAILQ_HEAD_INITIALIZER(head);
89 0 : struct pkg_entry *e = NULL;
90 : char pkgpath[MAXPATHLEN];
91 0 : const char *format = NULL;
92 : bool foundone;
93 :
94 0 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
95 0 : pkgdb_close(db);
96 0 : return (EX_IOERR);
97 : }
98 : /* XXX: get rid of hardcoded timeouts */
99 0 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
100 0 : pkgdb_close(db);
101 0 : warnx("Cannot get a read lock on a database, it is locked by another process");
102 0 : return (EX_TEMPFAIL);
103 : }
104 :
105 0 : switch (fmt) {
106 : case TXZ:
107 0 : format = "txz";
108 0 : break;
109 : case TBZ:
110 0 : format = "tbz";
111 0 : break;
112 : case TGZ:
113 0 : format = "tgz";
114 0 : break;
115 : case TAR:
116 0 : format = "tar";
117 0 : break;
118 : }
119 :
120 0 : for (i = 0; i < argc || match == MATCH_ALL; i++) {
121 0 : if (match == MATCH_ALL) {
122 0 : printf("Loading the package list...\n");
123 0 : if ((it = pkgdb_query(db, NULL, match)) == NULL)
124 0 : goto cleanup;
125 0 : match = !MATCH_ALL;
126 : } else
127 0 : if ((it = pkgdb_query(db, argv[i], match)) == NULL)
128 0 : goto cleanup;
129 :
130 0 : foundone = false;
131 0 : while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
132 0 : if ((e = malloc(sizeof(struct pkg_entry))) == NULL)
133 0 : err(1, "malloc(pkg_entry)");
134 0 : e->pkg = pkg;
135 0 : pkg = NULL;
136 0 : STAILQ_INSERT_TAIL(&head, e, next);
137 0 : foundone = true;
138 : }
139 0 : if (!foundone) {
140 0 : warnx("No installed package matching \"%s\" found\n",
141 0 : argv[i]);
142 0 : retcode++;
143 : }
144 :
145 0 : pkgdb_it_free(it);
146 0 : if (ret != EPKG_END)
147 0 : retcode++;
148 : }
149 :
150 0 : while (!STAILQ_EMPTY(&head)) {
151 0 : e = STAILQ_FIRST(&head);
152 0 : STAILQ_REMOVE_HEAD(&head, next);
153 :
154 0 : if (!overwrite) {
155 0 : pkg_snprintf(pkgpath, sizeof(pkgpath), "%S/%n-%v.%S",
156 : outdir, e->pkg, e->pkg, format);
157 0 : if (access(pkgpath, F_OK) == 0) {
158 0 : pkg_printf("%n-%v already packaged, skipping...\n",
159 : e->pkg, e->pkg);
160 0 : pkg_free(e->pkg);
161 0 : free(e);
162 0 : continue;
163 : }
164 : }
165 0 : pkg_printf("Creating package for %n-%v\n", e->pkg, e->pkg);
166 0 : if (pkg_create_installed(outdir, fmt, e->pkg) !=
167 : EPKG_OK)
168 0 : retcode++;
169 0 : pkg_free(e->pkg);
170 0 : free(e);
171 : }
172 :
173 : cleanup:
174 0 : pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
175 0 : pkgdb_close(db);
176 :
177 0 : return (retcode);
178 : }
179 :
180 : /*
181 : * options:
182 : * -x: regex
183 : * -g: globbing
184 : * -r: rootdir for the package
185 : * -m: path to dir where to find the metadata
186 : * -q: quiet mode
187 : * -M: manifest file
188 : * -f <format>: format could be txz, tgz, tbz or tar
189 : * -o: output directory where to create packages by default ./ is used
190 : */
191 :
192 : int
193 66 : exec_create(int argc, char **argv)
194 : {
195 66 : match_t match = MATCH_EXACT;
196 66 : const char *outdir = NULL;
197 66 : const char *format = NULL;
198 66 : const char *rootdir = NULL;
199 66 : const char *metadatadir = NULL;
200 66 : const char *manifest = NULL;
201 66 : char *plist = NULL;
202 : pkg_formats fmt;
203 : int ch;
204 66 : bool overwrite = true;
205 :
206 :
207 : /* POLA: pkg create is quiet by default, unless
208 : * PKG_CREATE_VERBOSE is set in pkg.conf. This is for
209 : * historical reasons. */
210 :
211 66 : quiet = !pkg_object_bool(pkg_config_get("PKG_CREATE_VERBOSE"));
212 :
213 66 : struct option longopts[] = {
214 : { "all", no_argument, NULL, 'a' },
215 : { "glob", no_argument, NULL, 'g' },
216 : { "regex", no_argument, NULL, 'x' },
217 : { "format", required_argument, NULL, 'f' },
218 : { "root-dir", required_argument, NULL, 'r' },
219 : { "metadata", required_argument, NULL, 'm' },
220 : { "manifest", required_argument, NULL, 'M' },
221 : { "out-dir", required_argument, NULL, 'o' },
222 : { "no-clobber", no_argument, NULL, 'n' },
223 : { "plist", required_argument, NULL, 'p' },
224 : { "quiet", no_argument, NULL, 'q' },
225 : { "verbose", no_argument, NULL, 'v' },
226 : { NULL, 0, NULL, 0 },
227 : };
228 :
229 279 : while ((ch = getopt_long(argc, argv, "+agxf:r:m:M:o:np:qv", longopts, NULL)) != -1) {
230 147 : switch (ch) {
231 : case 'a':
232 0 : match = MATCH_ALL;
233 0 : break;
234 : case 'g':
235 0 : match = MATCH_GLOB;
236 0 : break;
237 : case 'x':
238 0 : match = MATCH_REGEX;
239 0 : break;
240 : case 'f':
241 0 : format = optarg;
242 0 : break;
243 : case 'o':
244 29 : outdir = optarg;
245 29 : break;
246 : case 'r':
247 26 : rootdir = optarg;
248 26 : break;
249 : case 'm':
250 25 : metadatadir = optarg;
251 25 : break;
252 : case 'M':
253 41 : manifest = optarg;
254 41 : break;
255 : case 'n':
256 0 : overwrite = false;
257 0 : break;
258 : case 'p':
259 25 : plist = optarg;
260 25 : break;
261 : case 'q':
262 1 : quiet = true;
263 1 : break;
264 : case 'v':
265 0 : quiet = false;
266 0 : break;
267 : default:
268 0 : usage_create();
269 0 : return (EX_USAGE);
270 : }
271 : }
272 66 : argc -= optind;
273 66 : argv += optind;
274 :
275 66 : if (match != MATCH_ALL && metadatadir == NULL && manifest == NULL &&
276 : argc == 0) {
277 0 : usage_create();
278 0 : return (EX_USAGE);
279 : }
280 :
281 66 : if (metadatadir == NULL && manifest == NULL && rootdir != NULL) {
282 0 : warnx("Do not specify a rootdir without also specifying "
283 : "either a metadatadir or manifest");
284 0 : usage_create();
285 0 : return (EX_USAGE);
286 : }
287 :
288 66 : if (outdir == NULL)
289 37 : outdir = "./";
290 :
291 66 : if (format == NULL) {
292 66 : fmt = TXZ;
293 : } else {
294 0 : if (format[0] == '.')
295 0 : ++format;
296 0 : if (strcmp(format, "txz") == 0)
297 0 : fmt = TXZ;
298 0 : else if (strcmp(format, "tbz") == 0)
299 0 : fmt = TBZ;
300 0 : else if (strcmp(format, "tgz") == 0)
301 0 : fmt = TGZ;
302 0 : else if (strcmp(format, "tar") == 0)
303 0 : fmt = TAR;
304 : else {
305 0 : warnx("unknown format %s, using txz", format);
306 0 : fmt = TXZ;
307 : }
308 : }
309 :
310 66 : if (metadatadir == NULL && manifest == NULL) {
311 0 : return (pkg_create_matches(argc, argv, match, fmt, outdir,
312 0 : overwrite) == EPKG_OK ? EX_OK : EX_SOFTWARE);
313 66 : } else if (metadatadir != NULL) {
314 50 : return (pkg_create_staged(outdir, fmt, rootdir, metadatadir,
315 25 : plist) == EPKG_OK ? EX_OK : EX_SOFTWARE);
316 : } else { /* (manifest != NULL) */
317 82 : return (pkg_create_from_manifest(outdir, fmt, rootdir,
318 41 : manifest, plist) == EPKG_OK ? EX_OK : EX_SOFTWARE);
319 : }
320 : }
321 :
|