xref: /dragonfly/usr.bin/uname/uname.c (revision 7d3e9a5b)
1 /*-
2  * Copyright (c) 2002 Juli Mallett.
3  * Copyright (c) 1993
4  *	The Regents of the University of California.  All rights reserved.
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  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * @(#) Copyright (c) 1993 The Regents of the University of California.  All rights reserved.
31  * @(#)uname.c	8.2 (Berkeley) 5/4/95
32  * $FreeBSD: src/usr.bin/uname/uname.c,v 1.4.6.2 2002/10/17 07:47:29 jmallett Exp $
33  */
34 
35 #include <sys/param.h>
36 #include <sys/sysctl.h>
37 #include <sys/varsym.h>
38 
39 #include <err.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <string.h>
44 
45 #define	MFLAG	0x0001
46 #define	NFLAG	0x0002
47 #define	PFLAG	0x0004
48 #define	RFLAG	0x0008
49 #define	SFLAG	0x0010
50 #define	VFLAG	0x0020
51 #define	IFLAG	0x0040
52 #define	UFLAG	0x0080
53 #define	KFLAG	0x0100
54 #define	GFLAG	0x0200
55 #define	GFLAG2	0x0400
56 
57 typedef void (*get_t)(void);
58 static get_t get_ident, get_machine, get_hostname, get_arch;
59 static get_t get_release, get_sysname, get_version, get_pkgabi;
60 static get_t get_kernvers, get_uservers;
61 
62 static void native_ident(void);
63 static void native_machine(void);
64 static void native_hostname(void);
65 static void native_arch(void);
66 static void native_release(void);
67 static void native_sysname(void);
68 static void native_version(void);
69 static void native_pkgabi(void);
70 static void native_kernvers(void);
71 static void native_uservers(void);
72 static void print_uname(void);
73 static void setup_get(void);
74 static void usage(void) __dead2;
75 
76 static char *ident, *machine, *hostname, *arch;
77 static char *release, *sysname, *version, *pkgabi;
78 static char *kernvers, *uservers;
79 static int space;
80 static u_int flags;
81 
82 int
83 main(int argc, char *argv[])
84 {
85 	int ch;
86 
87 	setup_get();
88 
89 	while ((ch = getopt(argc, argv, "aiKmnprsUvP")) != -1) {
90 		switch(ch) {
91 		case 'a':
92 			flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG);
93 			break;
94 		case 'i':
95 			flags |= IFLAG;
96 			break;
97 		case 'K':
98 			flags |= KFLAG;
99 			break;
100 		case 'm':
101 			flags |= MFLAG;
102 			break;
103 		case 'n':
104 			flags |= NFLAG;
105 			break;
106 		case 'p':
107 			flags |= PFLAG;
108 			break;
109 		case 'r':
110 			flags |= RFLAG;
111 			break;
112 		case 's':
113 			flags |= SFLAG;
114 			break;
115 		case 'U':
116 			flags |= UFLAG;
117 			break;
118 		case 'v':
119 			flags |= VFLAG;
120 			break;
121 		case 'P':
122 			if (flags & GFLAG)	/* don't adjust odd numbers */
123 				flags |= GFLAG2;
124 			flags |= GFLAG;
125 			break;
126 		case '?':
127 		default:
128 			usage();
129 		}
130 	}
131 
132 	argc -= optind;
133 	argv += optind;
134 
135 	if (argc)
136 		usage();
137 
138 	if (!flags)
139 		flags |= SFLAG;
140 
141 	print_uname();
142 	exit(0);
143 }
144 
145 /*
146  * Overrides.
147  *
148  * UNAME_x env variables have the highest priority
149  * UNAME_x varsyms have the next highest priority
150  * values retrieved from sysctls have the lowest priority
151  */
152 static
153 void
154 CHECK_ENV(const char *envname, get_t *getp, get_t nativep, char **varp)
155 {
156 	char buf[MAXVARSYM_DATA];
157 
158 	if ((*varp = getenv(envname)) == NULL) {
159 		if (varsym_get(VARSYM_ALL_MASK, envname,
160 			       buf, sizeof(buf)) < 0) {
161 			*getp = nativep;
162 			return;
163 		}
164 		*varp = strdup(buf);
165 	}
166 	*getp = NULL;
167 }
168 
169 static void
170 setup_get(void)
171 {
172 	CHECK_ENV("UNAME_s", &get_sysname, native_sysname, &sysname);
173 	CHECK_ENV("UNAME_n", &get_hostname, native_hostname, &hostname);
174 	CHECK_ENV("UNAME_r", &get_release, native_release, &release);
175 	CHECK_ENV("UNAME_v", &get_version, native_version, &version);
176 	CHECK_ENV("UNAME_m", &get_machine, native_machine, &machine);
177 	CHECK_ENV("UNAME_p", &get_arch, native_arch, &arch);
178 	CHECK_ENV("UNAME_i", &get_ident, native_ident, &ident);
179 	CHECK_ENV("UNAME_K", &get_kernvers, native_kernvers, &kernvers);
180 	CHECK_ENV("UNAME_U", &get_uservers, native_uservers, &uservers);
181 	CHECK_ENV("UNAME_G", &get_pkgabi, native_pkgabi, &pkgabi);
182 }
183 
184 #define	PRINT_FLAG(flags,flag,var)		\
185 	if ((flags & flag) == flag) {		\
186 		if (space)			\
187 			printf(" ");		\
188 		else				\
189 			space++;		\
190 		if (get_##var != NULL)		\
191 			(*get_##var)();		\
192 		printf("%s", var);		\
193 	}
194 
195 static void
196 print_uname(void)
197 {
198 	PRINT_FLAG(flags, SFLAG, sysname);
199 	PRINT_FLAG(flags, NFLAG, hostname);
200 	PRINT_FLAG(flags, RFLAG, release);
201 	PRINT_FLAG(flags, VFLAG, version);
202 	PRINT_FLAG(flags, MFLAG, machine);
203 	PRINT_FLAG(flags, PFLAG, arch);
204 	PRINT_FLAG(flags, IFLAG, ident);
205 	PRINT_FLAG(flags, KFLAG, kernvers);
206 	PRINT_FLAG(flags, UFLAG, uservers);
207 	PRINT_FLAG(flags, GFLAG, pkgabi);
208 	printf("\n");
209 }
210 
211 #define	NATIVE_SYSCTL2_GET(var,mib0,mib1)	\
212 static void						\
213 native_##var(void)				\
214 {						\
215 	int mib[] = { (mib0), (mib1) };		\
216 	size_t len;				\
217 	static char buf[1024];			\
218 	char **varp = &(var);			\
219 						\
220 	len = sizeof buf;			\
221 	if (sysctl(mib, NELEM(mib),		\
222 	   &buf, &len, NULL, 0) == -1)		\
223 		err(1, "sysctl");
224 
225 #define	NATIVE_SYSCTLNAME_GET(var,name)		\
226 static void						\
227 native_##var(void)				\
228 {						\
229 	size_t len;				\
230 	static char buf[1024];			\
231 	char **varp = &(var);			\
232 						\
233 	len = sizeof buf;			\
234 	if (sysctlbyname(name, &buf, &len, NULL,\
235 	    0) == -1)				\
236 		err(1, "sysctlbyname");
237 
238 #define	NATIVE_SET				\
239 	*varp = buf;				\
240 	return;					\
241 }	struct __hack
242 
243 #define	NATIVE_BUFFER	(buf)
244 #define	NATIVE_LENGTH	(len)
245 
246 NATIVE_SYSCTL2_GET(sysname, CTL_KERN, KERN_OSTYPE) {
247 } NATIVE_SET;
248 
249 NATIVE_SYSCTL2_GET(hostname, CTL_KERN, KERN_HOSTNAME) {
250 } NATIVE_SET;
251 
252 NATIVE_SYSCTL2_GET(release, CTL_KERN, KERN_OSRELEASE) {
253 } NATIVE_SET;
254 
255 NATIVE_SYSCTL2_GET(version, CTL_KERN, KERN_VERSION) {
256 	size_t n;
257 	char *p;
258 
259 	p = NATIVE_BUFFER;
260 	n = NATIVE_LENGTH;
261 	for (; n--; ++p)
262 		if (*p == '\n' || *p == '\t')
263 			*p = ' ';
264 } NATIVE_SET;
265 
266 NATIVE_SYSCTL2_GET(machine, CTL_HW, HW_MACHINE) {
267 } NATIVE_SET;
268 
269 NATIVE_SYSCTL2_GET(arch, CTL_HW, HW_MACHINE_ARCH) {
270 } NATIVE_SET;
271 
272 NATIVE_SYSCTLNAME_GET(ident, "kern.ident") {
273 } NATIVE_SET;
274 
275 static void						\
276 native_pkgabi(void)				\
277 {
278 	char osrel[64];
279 	char mach[64];
280 	size_t len;
281 	double d;
282 
283 	len = sizeof(osrel);
284 	if (sysctlbyname("kern.osrelease", osrel, &len, NULL, 0) == -1)
285 		err(1, "sysctlbyname");
286 	len = sizeof(mach);
287 	if (sysctlbyname("hw.machine", mach, &len, NULL, 0) == -1)
288 		err(1, "sysctlbyname");
289 
290 	/*
291 	 * Current convention is to adjust odd release numbers to even.
292 	 */
293 	d = strtod(osrel, NULL);
294 	if ((flags & GFLAG2) == 0) {
295 		if ((int)(d * 10) & 1)
296 			d = d + 0.1;	/* force to nearest even release */
297 	}
298 
299 	/*
300 	 * pkgng expects the ABI in a different form
301 	 */
302 	if (strcmp(mach, "x86_64") == 0)
303 		snprintf(mach, sizeof(mach), "x86:64");
304 	else if (strcmp(mach, "i386") == 0)
305 		snprintf(mach, sizeof(mach), "x86:32");
306 
307 	asprintf(&pkgabi, "dragonfly:%3.1f:%s", d, mach);
308 }
309 
310 static void
311 native_kernvers(void)
312 {
313 	static char buf[128];
314 
315 	snprintf(buf, sizeof(buf), "%d", getosreldate());
316 	kernvers = buf;
317 }
318 
319 static void
320 native_uservers(void)
321 {
322 	static char buf[128];
323 
324 	snprintf(buf, sizeof(buf), "%d", __DragonFly_version);
325 	uservers = buf;
326 }
327 
328 static void
329 usage(void)
330 {
331 	fprintf(stderr, "usage: uname [-aiKmnprsUvP]\n");
332 	exit(1);
333 }
334