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
main(int argc,char * argv[])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
CHECK_ENV(const char * envname,get_t * getp,get_t nativep,char ** varp)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
setup_get(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
print_uname(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
NATIVE_SYSCTL2_GET(sysname,CTL_KERN,KERN_OSTYPE)246 NATIVE_SYSCTL2_GET(sysname, CTL_KERN, KERN_OSTYPE) {
247 } NATIVE_SET;
248
NATIVE_SYSCTL2_GET(hostname,CTL_KERN,KERN_HOSTNAME)249 NATIVE_SYSCTL2_GET(hostname, CTL_KERN, KERN_HOSTNAME) {
250 } NATIVE_SET;
251
NATIVE_SYSCTL2_GET(release,CTL_KERN,KERN_OSRELEASE)252 NATIVE_SYSCTL2_GET(release, CTL_KERN, KERN_OSRELEASE) {
253 } NATIVE_SET;
254
NATIVE_SYSCTL2_GET(version,CTL_KERN,KERN_VERSION)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
NATIVE_SYSCTL2_GET(machine,CTL_HW,HW_MACHINE)266 NATIVE_SYSCTL2_GET(machine, CTL_HW, HW_MACHINE) {
267 } NATIVE_SET;
268
NATIVE_SYSCTL2_GET(arch,CTL_HW,HW_MACHINE_ARCH)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 \
native_pkgabi(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
native_kernvers(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
native_uservers(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
usage(void)329 usage(void)
330 {
331 fprintf(stderr, "usage: uname [-aiKmnprsUvP]\n");
332 exit(1);
333 }
334