1/*
2 *
3 * FreeBSD install - a package for the installation and maintenance
4 * of non-core utilities.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * Jordan K. Hubbard
16 * 18 July 1993
17 *
18 * This is the delete module.
19 *
20 */
21
22#include <sys/cdefs.h>
23__FBSDID("$FreeBSD$");
24
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <getopt.h>
28#include <err.h>
29
30#include "lib.h"
31#include "delete.h"
32
33char	*Prefix		= NULL;
34Boolean	CleanDirs	= FALSE;
35Boolean	Interactive	= FALSE;
36Boolean	NoDeInstall	= FALSE;
37Boolean	Recursive	= FALSE;
38match_t	MatchType	= MATCH_GLOB;
39
40static void usage(void);
41
42static char opts[] = "adDfGhinp:rvxX";
43static struct option longopts[] = {
44	{ "all",	no_argument,		NULL,		'a' },
45	{ "clean-dirs",	no_argument,		NULL,		'd' },
46	{ "dry-run",	no_argument,		NULL,		'n' },
47	{ "extended",	no_argument,		NULL,		'X' },
48	{ "force",	no_argument,		NULL,		'f' },
49	{ "help",	no_argument,		NULL,		'h' },
50	{ "interactive",no_argument,		NULL,		'i' },
51	{ "prefix",	required_argument,	NULL,		'p' },
52	{ "recursive",	no_argument,		NULL,		'r' },
53	{ "regex",	no_argument,		NULL,		'x' },
54	{ "no-glob",	no_argument,		NULL,		'G' },
55	{ "no-script",	no_argument,		NULL,		'D' },
56	{ "no-scripts",	no_argument,		NULL,		'D' },
57	{ "verbose",	no_argument,		NULL,		'v' },
58	{ NULL,		0,			NULL,		0 },
59};
60
61int
62main(int argc, char **argv)
63{
64    int ch, error;
65    char **pkgs, **start;
66    char *pkgs_split;
67    const char *tmp;
68    struct stat stat_s;
69
70    warnpkgng();
71    pkgs = start = argv;
72    while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1)
73	switch(ch) {
74	case 'v':
75	    Verbose++;
76	    break;
77
78	case 'f':
79	    Force = TRUE;
80	    break;
81
82	case 'p':
83	    Prefix = optarg;
84	    break;
85
86	case 'D':
87	    NoDeInstall = TRUE;
88	    break;
89
90	case 'd':
91	    CleanDirs = TRUE;
92	    break;
93
94	case 'n':
95	    Fake = TRUE;
96	    Verbose = TRUE;
97	    break;
98
99	case 'a':
100	    MatchType = MATCH_ALL;
101	    break;
102
103	case 'G':
104	    MatchType = MATCH_EXACT;
105	    break;
106
107	case 'x':
108	    MatchType = MATCH_REGEX;
109	    break;
110
111	case 'X':
112	    MatchType = MATCH_EREGEX;
113	    break;
114
115	case 'i':
116	    Interactive = TRUE;
117	    break;
118
119	case 'r':
120	    Recursive = TRUE;
121	    break;
122
123	case 'h':
124	default:
125	    usage();
126	    break;
127	}
128
129    argc -= optind;
130    argv += optind;
131
132    /* Get all the remaining package names, if any */
133    while (*argv) {
134	/* Don't try to apply heuristics if arguments are regexs */
135	if (MatchType != MATCH_REGEX)
136	    while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
137		*pkgs_split++ = '\0';
138		/*
139		 * If character after the '/' is alphanumeric, then we've found the
140		 * package name.  Otherwise we've come across a trailing '/' and
141		 * need to continue our quest.
142		 */
143		if (isalnum(*pkgs_split) || ((MatchType == MATCH_GLOB) && \
144		    strpbrk(pkgs_split, "*?[]") != NULL)) {
145		    *argv = pkgs_split;
146		    break;
147		}
148	    }
149	*pkgs++ = *argv++;
150    }
151
152    /* If no packages, yelp */
153    if (pkgs == start && MatchType != MATCH_ALL)
154	warnx("missing package name(s)"), usage();
155    *pkgs = NULL;
156    tmp = LOG_DIR;
157    (void) stat(tmp, &stat_s);
158    if (!Fake && getuid() && geteuid() != stat_s.st_uid) {
159	if (!Force)
160	    errx(1, "you do not own %s, use -f to force", tmp);
161	else
162	    warnx("you do not own %s (proceeding anyways)", tmp);
163    }
164    if ((error = pkg_perform(start)) != 0) {
165	if (Verbose)
166	    warnx("%d package deletion(s) failed", error);
167	return error;
168    }
169    else
170	return 0;
171}
172
173static void
174usage(void)
175{
176    fprintf(stderr, "%s\n%s\n",
177	"usage: pkg_delete [-dDfGinrvxX] [-p prefix] pkg-name ...",
178	"       pkg_delete -a [flags]");
179    exit(1);
180}
181