-
Notifications
You must be signed in to change notification settings - Fork 42
/
main.c
425 lines (387 loc) · 11.5 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/*
* Copyright (c) 2009-2015 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Emile "iMil" Heitor <imil@NetBSD.org> .
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "pkgin.h"
#include "cmd.h"
#include "external/lib.h"
static void usage(int);
static int find_cmd(const char *);
static void missing_param(int, int, const char *);
static char **mkpkgargs(char **);
static void ginto(void);
uint8_t yesflag = 0, noflag = 0;
uint8_t verbosity = 0, package_version = 0, parsable = 0, pflag = 0;
char lslimit = '\0';
char fetchflags[4] = { 0, 0, 0, 0 };
FILE *tracefp = NULL;
int
main(int argc, char *argv[])
{
int need_upgrade, need_refresh;
int do_inst = DO_INST; /* by default, do install packages */
int ch, i, rc = EXIT_SUCCESS;
int force_update = 0;
char **pkgargs = NULL;
const char *chrootpath = NULL;
int v4flag = 0, v6flag = 0, ffidx = 0;
setprogname("pkgin");
/* Default to not doing \r printouts if we don't send to a tty */
parsable = !isatty(fileno(stdout));
while ((ch = getopt(argc, argv, "46dhyfFPvVl:nc:t:p")) != -1) {
switch (ch) {
case '4':
v4flag = 1;
break;
case '6':
v6flag = 1;
break;
case 'f':
force_update = 1;
break;
case 'F':
/* Previously "force reinstall", now ignored. */
break;
case 'y':
yesflag = 1;
noflag = 0;
break;
case 'n':
yesflag = 0;
noflag = 1;
break;
case 'v':
printf("pkgin %s (using %s)\n",
PKGIN_VERSION, pdb_version());
exit(EXIT_SUCCESS);
/* NOTREACHED */
case 'h':
usage(EXIT_SUCCESS);
/* NOTREACHED */
case 'l':
lslimit = optarg[0];
break;
case 'd':
do_inst = DONT_INST; /* download only */
break;
case 'c':
chrootpath = optarg;
break;
case 'V':
verbosity = 1;
break;
case 'P':
package_version = 1;
break;
case 't':
if ((tracefp = fopen(optarg, "w")) == NULL)
err(EXIT_FAILURE, MSG_CANT_OPEN_WRITE, optarg);
break;
case 'p':
parsable = 1;
pflag = 1;
break;
default:
usage(EXIT_FAILURE);
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
/* check we were given a valid command */
if (argc < 1 || (ch = find_cmd(argv[0])) == -1) {
usage(EXIT_FAILURE);
/* NOTREACHED */
}
/* enter chroot if -c specified */
if (chrootpath != NULL) {
if (chroot(chrootpath) == -1)
errx(-1, MSG_CHROOT_FAILED);
if (chdir("/") == -1)
errx(-1, MSG_CHDIR_FAILED);
}
/*
* Apply flags for libfetch operations.
*/
if (v4flag) {
fetchflags[ffidx++] = '4';
}
if (v6flag) {
fetchflags[ffidx++] = '6';
}
if (verbosity) {
fetchflags[ffidx++] = 'v';
}
/* Configure pkg_install */
setup_pkg_install();
/* Configure pkgin database directory */
setup_pkgin_dbdir();
/*
* Opening the database returns 0 for a valid database schema, and 1
* for a newly created or recreated database, so we use that to
* determine whether an upgrade needs to be performed or not.
*/
need_upgrade = pkgindb_open();
/*
* Check for updates to the local pkgdb and refresh the local database
* (quietly to avoid unexpected stdout for e.g. "pkgin export") if
* necessary. Ignore any returned errors so that unprivileged users
* can perform query operations.
*/
(void) update_db(LOCAL_SUMMARY, 0);
/* split PKG_REPOS env variable and record them */
split_repos();
/*
* Check repository consistency between repository list and recorded
* repositories. The force_update argument here is ugly, but needs to
* be done this way until force_fetch is removed as a global variable.
*/
need_refresh = chk_repo_list(force_update);
/*
* Upgrade the remote database if the database schema has changed, if
* the database is empty, if the repository list has changed, or if we
* have explicitly requested a refresh.
*/
if (need_upgrade || need_refresh) {
(void) update_db(REMOTE_SUMMARY, 1);
/*
* If we're performing any operations that fetch remote packages, make
* sure the remote databases are up-to-date to avoid mismatches. These
* are privileged operations so exit if the update cannot be performed.
*/
} else if (ch == PKG_INST_CMD || ch == PKG_UPGRD_CMD ||
ch == PKG_FUPGRD_CMD) {
if (update_db(REMOTE_SUMMARY, 0) == EXIT_FAILURE)
errx(EXIT_FAILURE, MSG_DONT_HAVE_RIGHTS);
}
/* load preferred file */
load_preferred();
/*
* Load package lists for everything other than update. It's likely
* this can be tightened up further to speed up a few commands.
*/
if (ch != PKG_UPDT_CMD) {
/*
* update_localdb(), called earlier via update_db(), explicitly
* inits the local pkglist if any changes were required, so
* this may already be initialised.
*/
if (is_empty_local_pkglist())
init_local_pkglist();
init_remote_pkglist();
}
switch (ch) {
case PKG_UPDT_CMD: /* update packages db */
if (need_upgrade || need_refresh) /* no need to do it twice */
break;
if (update_db(REMOTE_SUMMARY, 1) == EXIT_FAILURE)
errx(EXIT_FAILURE, MSG_DONT_HAVE_RIGHTS);
break;
case PKG_SHDDP_CMD: /* show direct depends */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
rc = show_direct_depends(argv[1]);
break;
case PKG_SHFDP_CMD: /* show full dependency tree */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
rc = show_full_dep_tree(argv[1]);
break;
case PKG_SHRDP_CMD: /* show full reverse dependency tree */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
rc = show_rev_dep_tree(argv[1]);
break;
case PKG_LLIST_CMD:
/* list local packages */
list_pkgs(LOCAL_PKGS_QUERY_DESC, PKG_LLIST_CMD);
break;
case PKG_RLIST_CMD:
/* list available packages */
list_pkgs(REMOTE_PKGS_QUERY_DESC, PKG_RLIST_CMD);
break;
case PKG_INST_CMD: /* install a package and its dependencies */
missing_param(argc, 2, MSG_PKG_ARGS_INST);
pkgargs = mkpkgargs(&argv[1]);
rc = pkgin_install(pkgargs, do_inst, 0);
break;
/*
* Historically there was a distinction between "upgrade" (only upgrade
* "keep" packages) and "full-upgrade" (all packages), but there's no
* real reasons for the former, especially with refresh support.
*/
case PKG_UPGRD_CMD:
case PKG_FUPGRD_CMD:
rc = pkgin_upgrade(do_inst);
break;
case PKG_REMV_CMD: /* remove packages and reverse dependencies */
missing_param(argc, 2, MSG_PKG_ARGS_RM);
pkgargs = mkpkgargs(&argv[1]);
rc = pkgin_remove(pkgargs);
break;
case PKG_AUTORM_CMD: /* autoremove orphan packages */
pkgin_autoremove();
break;
case PKG_KEEP_CMD: /* mark a package as "keep" (not automatic) */
missing_param(argc, 2, MSG_PKG_ARGS_KEEP);
for (i = 1; i < argc; i++) {
if (pkg_keep(KEEP, argv[i]))
rc = EXIT_FAILURE;
}
break;
case PKG_UNKEEP_CMD: /* mark a package as "unkeep" (automatic) */
missing_param(argc, 2, MSG_PKG_ARGS_UNKEEP);
for (i = 1; i < argc; i++) {
if (pkg_keep(UNKEEP, argv[i]))
rc = EXIT_FAILURE;
}
break;
case PKG_SHKP_CMD: /* show keep packages */
show_pkg_keep();
break;
case PKG_SHNOKP_CMD: /* show keep packages */
show_pkg_nokeep();
break;
case PKG_SRCH_CMD: /* search for package */
missing_param(argc, 2, MSG_MISSING_SRCH);
rc = search_pkg(argv[1]);
break;
case PKG_CLEAN_CMD: /* clean pkgin's packages cache */
clean_cache();
break;
case PKG_EXPORT_CMD: /* export PKGPATH for keep packages */
export_keep();
break;
case PKG_IMPORT_CMD: /* import for keep packages and install them */
missing_param(argc, 2, MSG_MISSING_FILENAME);
for (i=1; i<argc; i++)
import_keep(do_inst, argv[i]);
break;
case PKG_SHPROV_CMD: /* show what a package provides */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
show_prov_req(REMOTE_PROVIDES, argv[1]);
break;
case PKG_SHREQ_CMD: /* show what a package requires */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
show_prov_req(REMOTE_REQUIRES, argv[1]);
break;
case PKG_SHPKGCONT_CMD: /* show remote package content */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
rc = show_pkg_info('L', argv[1]); /* pkg_info flag */
break;
case PKG_SHPKGDESC_CMD: /* show remote package DESCR */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
rc = show_pkg_info('d', argv[1]); /* pkg_info flag */
break;
case PKG_SHPKGBDEFS_CMD: /* show remote package build definitions */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
rc = show_pkg_info('B', argv[1]); /* pkg_info flag */
break;
case PKG_SHCAT_CMD: /* show packages belonging to a category */
missing_param(argc, 2, MSG_MISSING_CATEGORY);
show_category(argv[1]);
break;
case PKG_SHPCAT_CMD: /* show package's category */
missing_param(argc, 2, MSG_MISSING_PKGNAME);
rc = show_pkg_category(argv[1]);
break;
case PKG_SHALLCAT_CMD: /* show all categories */
show_all_categories();
break;
case PKG_GINTO_CMD: /* Miod's request */
ginto();
break;
case PKG_STATS_CMD: /* show package statistics */
pkgindb_stats();
break;
default:
usage(EXIT_FAILURE);
/* NOTREACHED */
}
free_local_pkglist();
free_remote_pkglist();
pkgindb_close();
if (tracefp != NULL)
fclose(tracefp);
XFREE(env_repos);
XFREE(pkg_repos);
free_preferred();
free_list(pkgargs);
return rc;
}
static void
missing_param(int argc, int nargs, const char *msg)
{
if (argc < nargs)
errx(EXIT_FAILURE, "%s", msg);
}
/* find command index */
static int
find_cmd(const char *arg)
{
int i;
for (i = 0; cmd[i].name != NULL; i++) {
if (strcmp(arg, cmd[i].name) == 0 || strcmp(arg, cmd[i].shortcut) == 0)
return cmd[i].cmdtype;
}
return -1;
}
/*
* copy const argv to a modifiable array to expand globs in
* pkg_impact, https://github.com/NetBSDfr/pkgin/issues/114
*/
static char **
mkpkgargs(char **args)
{
size_t i;
char **pkgargs;
for (i = 0; args[i] != NULL; i++); /* args number */
pkgargs = xmalloc((i+1)*sizeof(char *));
for (i = 0; args[i] != NULL; i++) {
pkgargs[i] = xstrdup(args[i]);
}
pkgargs[i] = NULL;
return pkgargs;
}
__attribute__((noreturn))
static void
usage(int status)
{
int i;
fprintf((status) ? stderr : stdout,
"Usage: pkgin [-46cdfhlnPtvVy] command [package ...]\n\n"
"Commands and shortcuts:\n");
for (i = 0; cmd[i].name != NULL; i++) {
if (cmd[i].cmdtype != PKG_GINTO_CMD)
fprintf((status) ? stderr : stdout,
"%-19s (%-4s) - %s\n",
cmd[i].name, cmd[i].shortcut, cmd[i].descr);
}
exit(status);
}
static void
ginto(void)
{
printf("* 2 oz gin\n* 5 oz tonic water\n* 1 lime wedge\n");
}