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