1/*
2 *
3 * FreeBSD install - a package for the installation and maintainance
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    pkgs = start = argv;
71    while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1)
72	switch(ch) {
73	case 'v':
74	    Verbose++;
75	    break;
76
77	case 'f':
78	    Force = TRUE;
79	    break;
80
81	case 'p':
82	    Prefix = optarg;
83	    break;
84
85	case 'D':
86	    NoDeInstall = TRUE;
87	    break;
88
89	case 'd':
90	    CleanDirs = TRUE;
91	    break;
92
93	case 'n':
94	    Fake = TRUE;
95	    Verbose = TRUE;
96	    break;
97
98	case 'a':
99	    MatchType = MATCH_ALL;
100	    break;
101
102	case 'G':
103	    MatchType = MATCH_EXACT;
104	    break;
105
106	case 'x':
107	    MatchType = MATCH_REGEX;
108	    break;
109
110	case 'X':
111	    MatchType = MATCH_EREGEX;
112	    break;
113
114	case 'i':
115	    Interactive = TRUE;
116	    break;
117
118	case 'r':
119	    Recursive = TRUE;
120	    break;
121
122	case 'h':
123	default:
124	    usage();
125	    break;
126	}
127
128    argc -= optind;
129    argv += optind;
130
131    /* Get all the remaining package names, if any */
132    while (*argv) {
133	/* Don't try to apply heuristics if arguments are regexs */
134	if (MatchType != MATCH_REGEX)
135	    while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
136		*pkgs_split++ = '\0';
137		/*
138		 * If character after the '/' is alphanumeric, then we've found the
139		 * package name.  Otherwise we've come across a trailing '/' and
140		 * need to continue our quest.
141		 */
142		if (isalnum(*pkgs_split) || ((MatchType == MATCH_GLOB) && \
143		    strpbrk(pkgs_split, "*?[]") != NULL)) {
144		    *argv = pkgs_split;
145		    break;
146		}
147	    }
148	*pkgs++ = *argv++;
149    }
150
151    /* If no packages, yelp */
152    if (pkgs == start && MatchType != MATCH_ALL)
153	warnx("missing package name(s)"), usage();
154    *pkgs = NULL;
155    tmp = LOG_DIR;
156    (void) stat(tmp, &stat_s);
157    if (!Fake && getuid() && geteuid() != stat_s.st_uid) {
158	if (!Force)
159	    errx(1, "you do not own %s, use -f to force", tmp);
160	else
161	    warnx("you do not own %s (proceeding anyways)", tmp);
162    }
163    if ((error = pkg_perform(start)) != 0) {
164	if (Verbose)
165	    warnx("%d package deletion(s) failed", error);
166	return error;
167    }
168    else
169	return 0;
170}
171
172static void
173usage(void)
174{
175    fprintf(stderr, "%s\n%s\n",
176	"usage: pkg_delete [-dDfGinrvxX] [-p prefix] pkg-name ...",
177	"       pkg_delete -a [flags]");
178    exit(1);
179}
180