New program: arch
[platform/upstream/coreutils.git] / src / uname.c
1 /* uname -- print system information
2
3    Copyright (C) 1989, 1992, 1993, 1996, 1997, 1999-2005, 2007
4    Free Software Foundation, Inc.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19
20 /* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/utsname.h>
26 #include <getopt.h>
27
28 #if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
29 # include <sys/systeminfo.h>
30 #endif
31
32 #if HAVE_SYS_SYSCTL_H
33 # if HAVE_SYS_PARAM_H
34 #  include <sys/param.h> /* needed for OpenBSD 3.0 */
35 # endif
36 # include <sys/sysctl.h>
37 # ifdef HW_MODEL
38 #  ifdef HW_MACHINE_ARCH
39 /* E.g., FreeBSD 4.5, NetBSD 1.5.2 */
40 #   define UNAME_HARDWARE_PLATFORM HW_MODEL
41 #   define UNAME_PROCESSOR HW_MACHINE_ARCH
42 #  else
43 /* E.g., OpenBSD 3.0 */
44 #   define UNAME_PROCESSOR HW_MODEL
45 #  endif
46 # endif
47 #endif
48
49 #ifdef __APPLE__
50 # include <mach/machine.h>
51 # include <mach-o/arch.h>
52 #endif
53
54 #include "system.h"
55 #include "error.h"
56 #include "quote.h"
57 #include "uname.h"
58
59 /* The official name of this program (e.g., no `g' prefix).  */
60 #define PROGRAM_NAME (uname_mode == UNAME_UNAME ? "uname" : "arch")
61
62 #define AUTHORS "David MacKenzie"
63 #define ARCH_AUTHORS "David MacKenzie", "Karel Zak"
64
65 /* Values that are bitwise or'd into `toprint'. */
66 /* Kernel name. */
67 #define PRINT_KERNEL_NAME 1
68
69 /* Node name on a communications network. */
70 #define PRINT_NODENAME 2
71
72 /* Kernel release. */
73 #define PRINT_KERNEL_RELEASE 4
74
75 /* Kernel version. */
76 #define PRINT_KERNEL_VERSION 8
77
78 /* Machine hardware name. */
79 #define PRINT_MACHINE 16
80
81 /* Processor type. */
82 #define PRINT_PROCESSOR 32
83
84 /* Hardware platform.  */
85 #define PRINT_HARDWARE_PLATFORM 64
86
87 /* Operating system.  */
88 #define PRINT_OPERATING_SYSTEM 128
89
90 /* The name this program was run with, for error messages. */
91 char *program_name;
92
93 static struct option const uname_long_options[] =
94 {
95   {"all", no_argument, NULL, 'a'},
96   {"kernel-name", no_argument, NULL, 's'},
97   {"sysname", no_argument, NULL, 's'},  /* Obsolescent.  */
98   {"nodename", no_argument, NULL, 'n'},
99   {"kernel-release", no_argument, NULL, 'r'},
100   {"release", no_argument, NULL, 'r'},  /* Obsolescent.  */
101   {"kernel-version", no_argument, NULL, 'v'},
102   {"machine", no_argument, NULL, 'm'},
103   {"processor", no_argument, NULL, 'p'},
104   {"hardware-platform", no_argument, NULL, 'i'},
105   {"operating-system", no_argument, NULL, 'o'},
106   {GETOPT_HELP_OPTION_DECL},
107   {GETOPT_VERSION_OPTION_DECL},
108   {NULL, 0, NULL, 0}
109 };
110
111 static struct option const arch_long_options[] =
112 {
113   {GETOPT_HELP_OPTION_DECL},
114   {GETOPT_VERSION_OPTION_DECL},
115   {NULL, 0, NULL, 0}
116 };
117
118 void
119 usage (int status)
120 {
121   if (status != EXIT_SUCCESS)
122     fprintf (stderr, _("Try `%s --help' for more information.\n"),
123              program_name);
124   else
125     {
126       printf (_("Usage: %s [OPTION]...\n"), program_name);
127
128       if (uname_mode == UNAME_UNAME)
129         {
130           fputs (_("\
131 Print certain system information.  With no OPTION, same as -s.\n\
132 \n\
133   -a, --all                print all information, in the following order,\n\
134                              except omit -p and -i if unknown:\n\
135   -s, --kernel-name        print the kernel name\n\
136   -n, --nodename           print the network node hostname\n\
137   -r, --kernel-release     print the kernel release\n\
138 "), stdout);
139           fputs (_("\
140   -v, --kernel-version     print the kernel version\n\
141   -m, --machine            print the machine hardware name\n\
142   -p, --processor          print the processor type or \"unknown\"\n\
143   -i, --hardware-platform  print the hardware platform or \"unknown\"\n\
144   -o, --operating-system   print the operating system\n\
145 "), stdout);
146         }
147       else
148         {
149           fputs (_("\
150 Print machine architecture.\n\
151 \n\
152 "), stdout);
153         }
154
155       fputs (HELP_OPTION_DESCRIPTION, stdout);
156       fputs (VERSION_OPTION_DESCRIPTION, stdout);
157       emit_bug_reporting_address ();
158     }
159   exit (status);
160 }
161
162 /* Print ELEMENT, preceded by a space if something has already been
163    printed.  */
164
165 static void
166 print_element (char const *element)
167 {
168   static bool printed;
169   if (printed)
170     putchar (' ');
171   printed = true;
172   fputs (element, stdout);
173 }
174
175
176 /* Set all the option flags according to the switches specified.
177    Return the mask indicating which elements to print.  */
178
179 static int
180 decode_switches (int argc, char **argv)
181 {
182   int c;
183   unsigned int toprint = 0;
184
185   if (uname_mode == UNAME_ARCH)
186     {
187       while ((c = getopt_long (argc, argv, "",
188                                arch_long_options, NULL)) != -1)
189         {
190           switch (c)
191             {
192             case_GETOPT_HELP_CHAR;
193
194             case_GETOPT_VERSION_CHAR (PROGRAM_NAME, ARCH_AUTHORS);
195
196             default:
197               usage (EXIT_FAILURE);
198             }
199         }
200       toprint = PRINT_MACHINE;
201     }
202   else
203     {
204       while ((c = getopt_long (argc, argv, "asnrvmpio",
205                                uname_long_options, NULL)) != -1)
206         {
207           switch (c)
208             {
209             case 'a':
210               toprint = UINT_MAX;
211               break;
212
213             case 's':
214               toprint |= PRINT_KERNEL_NAME;
215               break;
216
217             case 'n':
218               toprint |= PRINT_NODENAME;
219               break;
220
221             case 'r':
222               toprint |= PRINT_KERNEL_RELEASE;
223               break;
224
225             case 'v':
226               toprint |= PRINT_KERNEL_VERSION;
227               break;
228
229             case 'm':
230               toprint |= PRINT_MACHINE;
231               break;
232
233             case 'p':
234               toprint |= PRINT_PROCESSOR;
235               break;
236
237             case 'i':
238               toprint |= PRINT_HARDWARE_PLATFORM;
239               break;
240
241             case 'o':
242               toprint |= PRINT_OPERATING_SYSTEM;
243               break;
244
245             case_GETOPT_HELP_CHAR;
246
247             case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
248
249             default:
250               usage (EXIT_FAILURE);
251             }
252         }
253     }
254
255   if (argc != optind)
256     {
257       error (0, 0, _("extra operand %s"), quote (argv[optind]));
258       usage (EXIT_FAILURE);
259     }
260
261   return toprint;
262 }
263
264 int
265 main (int argc, char **argv)
266 {
267   static char const unknown[] = "unknown";
268
269   /* Mask indicating which elements to print. */
270   unsigned int toprint = 0;
271
272   initialize_main (&argc, &argv);
273   program_name = argv[0];
274   setlocale (LC_ALL, "");
275   bindtextdomain (PACKAGE, LOCALEDIR);
276   textdomain (PACKAGE);
277
278   atexit (close_stdout);
279
280   toprint = decode_switches (argc, argv);
281
282   if (toprint == 0)
283     toprint = PRINT_KERNEL_NAME;
284
285   if (toprint
286        & (PRINT_KERNEL_NAME | PRINT_NODENAME | PRINT_KERNEL_RELEASE
287           | PRINT_KERNEL_VERSION | PRINT_MACHINE))
288     {
289       struct utsname name;
290
291       if (uname (&name) == -1)
292         error (EXIT_FAILURE, errno, _("cannot get system name"));
293
294       if (toprint & PRINT_KERNEL_NAME)
295         print_element (name.sysname);
296       if (toprint & PRINT_NODENAME)
297         print_element (name.nodename);
298       if (toprint & PRINT_KERNEL_RELEASE)
299         print_element (name.release);
300       if (toprint & PRINT_KERNEL_VERSION)
301         print_element (name.version);
302       if (toprint & PRINT_MACHINE)
303         print_element (name.machine);
304     }
305
306   if (toprint & PRINT_PROCESSOR)
307     {
308       char const *element = unknown;
309 #if HAVE_SYSINFO && defined SI_ARCHITECTURE
310       {
311         static char processor[257];
312         if (0 <= sysinfo (SI_ARCHITECTURE, processor, sizeof processor))
313           element = processor;
314       }
315 #endif
316 #ifdef UNAME_PROCESSOR
317       if (element == unknown)
318         {
319           static char processor[257];
320           size_t s = sizeof processor;
321           static int mib[] = { CTL_HW, UNAME_PROCESSOR };
322           if (sysctl (mib, 2, processor, &s, 0, 0) >= 0)
323             element = processor;
324
325 # ifdef __APPLE__
326           /* This kludge works around a bug in Mac OS X.  */
327           if (element == unknown)
328             {
329               cpu_type_t cputype;
330               size_t s = sizeof cputype;
331               NXArchInfo const *ai;
332               if (sysctlbyname ("hw.cputype", &cputype, &s, NULL, 0) == 0
333                   && (ai = NXGetArchInfoFromCpuType (cputype,
334                                                      CPU_SUBTYPE_MULTIPLE))
335                   != NULL)
336                 element = ai->name;
337
338               /* Hack "safely" around the ppc vs. powerpc return value. */
339               if (cputype == CPU_TYPE_POWERPC
340                   && strncmp (element, "ppc", 3) == 0)
341                 element = "powerpc";
342             }
343 # endif
344         }
345 #endif
346       if (! (toprint == UINT_MAX && element == unknown))
347         print_element (element);
348     }
349
350   if (toprint & PRINT_HARDWARE_PLATFORM)
351     {
352       char const *element = unknown;
353 #if HAVE_SYSINFO && defined SI_PLATFORM
354       {
355         static char hardware_platform[257];
356         if (0 <= sysinfo (SI_PLATFORM,
357                           hardware_platform, sizeof hardware_platform))
358           element = hardware_platform;
359       }
360 #endif
361 #ifdef UNAME_HARDWARE_PLATFORM
362       if (element == unknown)
363         {
364           static char hardware_platform[257];
365           size_t s = sizeof hardware_platform;
366           static int mib[] = { CTL_HW, UNAME_HARDWARE_PLATFORM };
367           if (sysctl (mib, 2, hardware_platform, &s, 0, 0) >= 0)
368             element = hardware_platform;
369         }
370 #endif
371       if (! (toprint == UINT_MAX && element == unknown))
372         print_element (element);
373     }
374
375   if (toprint & PRINT_OPERATING_SYSTEM)
376     print_element (HOST_OPERATING_SYSTEM);
377
378   putchar ('\n');
379
380   exit (EXIT_SUCCESS);
381 }