maint: update copyright
[gnulib.git] / lib / uname.c
1 /* uname replacement.
2    Copyright (C) 2009-2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include <config.h>
18
19 /* Specification.  */
20 #include <sys/utsname.h>
21
22 /* This file provides an implementation only for the native Windows API.  */
23 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <windows.h>
30
31 /* Mingw headers don't have all the platform codes.  */
32 #ifndef VER_PLATFORM_WIN32_CE
33 # define VER_PLATFORM_WIN32_CE 3
34 #endif
35
36 /* Some headers don't have all the processor architecture codes.  */
37 #ifndef PROCESSOR_ARCHITECTURE_AMD64
38 # define PROCESSOR_ARCHITECTURE_AMD64 9
39 #endif
40 #ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
41 # define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
42 #endif
43
44 /* Mingw headers don't have the latest processor codes.  */
45 #ifndef PROCESSOR_AMD_X8664
46 # define PROCESSOR_AMD_X8664 8664
47 #endif
48
49 int
50 uname (struct utsname *buf)
51 {
52   OSVERSIONINFO version;
53   OSVERSIONINFOEX versionex;
54   BOOL have_versionex; /* indicates whether versionex is filled */
55   const char *super_version;
56
57   /* Preparation: Fill version and, if possible, also versionex.
58      But try to call GetVersionEx only once in the common case.  */
59   versionex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
60   have_versionex = GetVersionEx ((OSVERSIONINFO *) &versionex);
61   if (have_versionex)
62     {
63       /* We know that OSVERSIONINFO is a subset of OSVERSIONINFOEX.  */
64       memcpy (&version, &versionex, sizeof (OSVERSIONINFO));
65     }
66   else
67     {
68       version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
69       if (!GetVersionEx (&version))
70         abort ();
71     }
72
73   /* Fill in nodename.  */
74   if (gethostname (buf->nodename, sizeof (buf->nodename)) < 0)
75     strcpy (buf->nodename, "localhost");
76
77   /* Determine major-major Windows version.  */
78   if (version.dwPlatformId == VER_PLATFORM_WIN32_NT)
79     {
80       /* Windows NT or newer.  */
81       super_version = "NT";
82     }
83   else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE)
84     {
85       /* Windows CE or Embedded CE.  */
86       super_version = "CE";
87     }
88   else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
89     {
90       /* Windows 95/98/ME.  */
91       switch (version.dwMinorVersion)
92         {
93         case 0:
94           super_version = "95";
95           break;
96         case 10:
97           super_version = "98";
98           break;
99         case 90:
100           super_version = "ME";
101           break;
102         default:
103           super_version = "";
104           break;
105         }
106     }
107   else
108     super_version = "";
109
110   /* Fill in sysname.  */
111 #ifdef __MINGW32__
112   /* Returns a string compatible with the MSYS uname.exe program,
113      so that no further changes are needed to GNU config.guess.
114      For example,
115        $ ./uname.exe -s      => MINGW32_NT-5.1
116    */
117   sprintf (buf->sysname, "MINGW32_%s-%u.%u", super_version,
118            (unsigned int) version.dwMajorVersion,
119            (unsigned int) version.dwMinorVersion);
120 #else
121   sprintf (buf->sysname, "Windows%s", super_version);
122 #endif
123
124   /* Fill in release, version.  */
125   /* The MSYS uname.exe programs uses strings from a modified Cygwin runtime:
126        $ ./uname.exe -r      => 1.0.11(0.46/3/2)
127        $ ./uname.exe -v      => 2008-08-25 23:40
128      There is no point in imitating this behaviour.  */
129   if (version.dwPlatformId == VER_PLATFORM_WIN32_NT)
130     {
131       /* Windows NT or newer.  */
132       struct windows_version
133         {
134           int major;
135           int minor;
136           unsigned int server_offset;
137           const char *name;
138         };
139
140       /* Storing the workstation and server version names in a single
141          stream does not waste memory when they are the same.  These
142          macros abstract the representation.  VERSION1 is used if
143          version.wProductType does not matter, VERSION2 if it does.  */
144       #define VERSION1(major, minor, name) \
145         { major, minor, 0, name }
146       #define VERSION2(major, minor, workstation, server) \
147         { major, minor, sizeof workstation, workstation "\0" server }
148       static const struct windows_version versions[] =
149         {
150           VERSION2 (3, -1, "Windows NT Workstation", "Windows NT Server"),
151           VERSION2 (4, -1, "Windows NT Workstation", "Windows NT Server"),
152           VERSION1 (5, 0, "Windows 2000"),
153           VERSION1 (5, 1, "Windows XP"),
154           VERSION1 (5, 2, "Windows Server 2003"),
155           VERSION2 (6, 0, "Windows Vista", "Windows Server 2008"),
156           VERSION2 (6, 1, "Windows 7", "Windows Server 2008 R2"),
157           VERSION2 (-1, -1, "Windows", "Windows Server")
158         };
159       const char *base;
160       const struct windows_version *v = versions;
161
162       /* Find a version that matches ours.  The last element is a
163          wildcard that always ends the loop.  */
164       while ((v->major != version.dwMajorVersion && v->major != -1)
165              || (v->minor != version.dwMinorVersion && v->minor != -1))
166         v++;
167
168       if (have_versionex && versionex.wProductType != VER_NT_WORKSTATION)
169         base = v->name + v->server_offset;
170       else
171         base = v->name;
172       if (v->major == -1 || v->minor == -1)
173         sprintf (buf->release, "%s %u.%u",
174                  base,
175                  (unsigned int) version.dwMajorVersion,
176                  (unsigned int) version.dwMinorVersion);
177       else
178         strcpy (buf->release, base);
179     }
180   else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE)
181     {
182       /* Windows CE or Embedded CE.  */
183       sprintf (buf->release, "Windows CE %u.%u",
184                (unsigned int) version.dwMajorVersion,
185                (unsigned int) version.dwMinorVersion);
186     }
187   else
188     {
189       /* Windows 95/98/ME.  */
190       sprintf (buf->release, "Windows %s", super_version);
191     }
192   strcpy (buf->version, version.szCSDVersion);
193
194   /* Fill in machine.  */
195   {
196     SYSTEM_INFO info;
197
198     GetSystemInfo (&info);
199     /* Check for Windows NT or CE, since the info.wProcessorLevel is
200        garbage on Windows 95. */
201     if (version.dwPlatformId == VER_PLATFORM_WIN32_NT
202         || version.dwPlatformId == VER_PLATFORM_WIN32_CE)
203       {
204         /* Windows NT or newer, or Windows CE or Embedded CE.  */
205         switch (info.wProcessorArchitecture)
206           {
207           case PROCESSOR_ARCHITECTURE_AMD64:
208             strcpy (buf->machine, "x86_64");
209             break;
210           case PROCESSOR_ARCHITECTURE_IA64:
211             strcpy (buf->machine, "ia64");
212             break;
213           case PROCESSOR_ARCHITECTURE_INTEL:
214             strcpy (buf->machine, "i386");
215             if (info.wProcessorLevel >= 3)
216               buf->machine[1] =
217                 '0' + (info.wProcessorLevel <= 6 ? info.wProcessorLevel : 6);
218             break;
219           case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
220             strcpy (buf->machine, "i686");
221             break;
222           case PROCESSOR_ARCHITECTURE_MIPS:
223             strcpy (buf->machine, "mips");
224             break;
225           case PROCESSOR_ARCHITECTURE_ALPHA:
226           case PROCESSOR_ARCHITECTURE_ALPHA64:
227             strcpy (buf->machine, "alpha");
228             break;
229           case PROCESSOR_ARCHITECTURE_PPC:
230             strcpy (buf->machine, "powerpc");
231             break;
232           case PROCESSOR_ARCHITECTURE_SHX:
233             strcpy (buf->machine, "sh");
234             break;
235           case PROCESSOR_ARCHITECTURE_ARM:
236             strcpy (buf->machine, "arm");
237             break;
238           default:
239             strcpy (buf->machine, "unknown");
240             break;
241           }
242       }
243     else
244       {
245         /* Windows 95/98/ME.  */
246         switch (info.dwProcessorType)
247           {
248           case PROCESSOR_AMD_X8664:
249             strcpy (buf->machine, "x86_64");
250             break;
251           case PROCESSOR_INTEL_IA64:
252             strcpy (buf->machine, "ia64");
253             break;
254           default:
255             if (info.dwProcessorType % 100 == 86)
256               sprintf (buf->machine, "i%u",
257                        (unsigned int) info.dwProcessorType);
258             else
259               strcpy (buf->machine, "unknown");
260             break;
261           }
262       }
263   }
264
265   return 0;
266 }
267
268 #endif