1/*-
2 * Copyright (c) 2000  Peter Wemm <peter@freebsd.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/types.h>
27#include <sys/sysctl.h>
28#include <err.h>
29#include <errno.h>
30#include <kenv.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36static void	usage(void);
37static int	kdumpenv(int dump_type);
38static int	kgetenv(const char *);
39static int	ksetenv(const char *, char *);
40static int	kunsetenv(const char *);
41
42static int hflag = 0;
43static int lflag = 0;
44static int Nflag = 0;
45static int qflag = 0;
46static int sflag = 0;
47static int uflag = 0;
48static int vflag = 0;
49
50static void
51usage(void)
52{
53	(void)fprintf(stderr, "%s\n%s\n%s\n",
54	    "usage: kenv [-l|-s] [-hNq]",
55	    "       kenv [-qv] variable[=value]",
56	    "       kenv [-q] -u variable");
57	exit(1);
58}
59
60int
61main(int argc, char **argv)
62{
63	char *env, *eq, *val;
64	int ch, error;
65
66	val = NULL;
67	env = NULL;
68	while ((ch = getopt(argc, argv, "hlNqsuv")) != -1) {
69		switch (ch) {
70		case 'h':
71			hflag++;
72			break;
73		case 'l':
74			lflag++;
75			break;
76		case 'N':
77			Nflag++;
78			break;
79		case 'q':
80			qflag++;
81			break;
82		case 's':
83			sflag++;
84			break;
85		case 'u':
86			uflag++;
87			break;
88		case 'v':
89			vflag++;
90			break;
91		default:
92			usage();
93		}
94	}
95	argc -= optind;
96	argv += optind;
97	if (argc > 0) {
98		env = argv[0];
99		eq = strchr(env, '=');
100		if (eq != NULL) {
101			*eq++ = '\0';
102			val = eq;
103		}
104		argv++;
105		argc--;
106	}
107	if ((hflag || Nflag) && env != NULL)
108		usage();
109	if (lflag && sflag)
110		usage();
111	if (argc > 0 || ((uflag || vflag) && env == NULL))
112		usage();
113	if (env == NULL) {
114		if (lflag)
115			error = kdumpenv(KENV_DUMP_LOADER);
116		else if (sflag)
117			error = kdumpenv(KENV_DUMP_STATIC);
118		else
119			error = kdumpenv(KENV_DUMP);
120		if (error && !qflag) {
121			if (errno == ENOENT)
122				warnx("requested environment is unavailable");
123			else
124				warn("kdumpenv");
125		}
126	} else if (val == NULL) {
127		if (uflag) {
128			error = kunsetenv(env);
129			if (error && !qflag)
130				warnx("unable to unset %s", env);
131		} else {
132			error = kgetenv(env);
133			if (error && !qflag)
134				warnx("unable to get %s", env);
135		}
136	} else {
137		error = ksetenv(env, val);
138		if (error && !qflag)
139			warnx("unable to set %s to %s", env, val);
140	}
141	return (error);
142}
143
144static int
145kdumpenv(int dump_type)
146{
147	char *buf, *bp, *cp;
148	int buflen, envlen;
149
150	envlen = kenv(dump_type, NULL, NULL, 0);
151	if (envlen < 0)
152		return (-1);
153	for (;;) {
154		buflen = envlen * 120 / 100;
155		buf = calloc(1, buflen + 1);
156		if (buf == NULL)
157			return (-1);
158		envlen = kenv(dump_type, NULL, buf, buflen);
159		if (envlen < 0) {
160			free(buf);
161			return (-1);
162		}
163		if (envlen > buflen)
164			free(buf);
165		else
166			break;
167	}
168
169	for (bp = buf; *bp != '\0'; bp += strlen(bp) + 1) {
170		if (hflag) {
171			if (strncmp(bp, "hint.", 5) != 0)
172				continue;
173		}
174		cp = strchr(bp, '=');
175		if (cp == NULL)
176			continue;
177		*cp++ = '\0';
178		if (Nflag)
179			printf("%s\n", bp);
180		else
181			printf("%s=\"%s\"\n", bp, cp);
182		bp = cp;
183	}
184
185	free(buf);
186	return (0);
187}
188
189static int
190kgetenv(const char *env)
191{
192	char buf[1024];
193	int ret;
194
195	ret = kenv(KENV_GET, env, buf, sizeof(buf));
196	if (ret == -1)
197		return (ret);
198	if (vflag)
199		printf("%s=\"%s\"\n", env, buf);
200	else
201		printf("%s\n", buf);
202	return (0);
203}
204
205static int
206ksetenv(const char *env, char *val)
207{
208	int ret;
209
210	ret = kenv(KENV_SET, env, val, strlen(val) + 1);
211	if (ret == 0)
212		printf("%s=\"%s\"\n", env, val);
213	return (ret);
214}
215
216static int
217kunsetenv(const char *env)
218{
219	int ret;
220
221	ret = kenv(KENV_UNSET, env, NULL, 0);
222	return (ret);
223}
224