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