1 /* uname replacement.
2    Copyright (C) 2009-2020 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 <https://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 __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 /* Don't assume that UNICODE is not defined.  */
50 # undef OSVERSIONINFO
51 # define OSVERSIONINFO OSVERSIONINFOA
52 # undef GetVersionEx
53 # define GetVersionEx GetVersionExA
54 
55 int
uname(struct utsname * buf)56 uname (struct utsname *buf)
57 {
58   OSVERSIONINFO version;
59   OSVERSIONINFOEX versionex;
60   BOOL have_versionex; /* indicates whether versionex is filled */
61   const char *super_version;
62 
63   /* Preparation: Fill version and, if possible, also versionex.
64      But try to call GetVersionEx only once in the common case.  */
65   versionex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
66   have_versionex = GetVersionEx ((OSVERSIONINFO *) &versionex);
67   if (have_versionex)
68     {
69       /* We know that OSVERSIONINFO is a subset of OSVERSIONINFOEX.  */
70       memcpy (&version, &versionex, sizeof (OSVERSIONINFO));
71     }
72   else
73     {
74       version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
75       if (!GetVersionEx (&version))
76         abort ();
77     }
78 
79   /* Fill in nodename.  */
80   if (gethostname (buf->nodename, sizeof (buf->nodename)) < 0)
81     strcpy (buf->nodename, "localhost");
82 
83   /* Determine major-major Windows version.  */
84   if (version.dwPlatformId == VER_PLATFORM_WIN32_NT)
85     {
86       /* Windows NT or newer.  */
87       super_version = "NT";
88     }
89   else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE)
90     {
91       /* Windows CE or Embedded CE.  */
92       super_version = "CE";
93     }
94   else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
95     {
96       /* Windows 95/98/ME.  */
97       switch (version.dwMinorVersion)
98         {
99         case 0:
100           super_version = "95";
101           break;
102         case 10:
103           super_version = "98";
104           break;
105         case 90:
106           super_version = "ME";
107           break;
108         default:
109           super_version = "";
110           break;
111         }
112     }
113   else
114     super_version = "";
115 
116   /* Fill in sysname.  */
117 # ifdef __MINGW32__
118   /* Returns a string compatible with the MSYS uname.exe program,
119      so that no further changes are needed to GNU config.guess.
120      For example,
121        $ ./uname.exe -s      => MINGW32_NT-5.1
122    */
123   sprintf (buf->sysname, "MINGW32_%s-%u.%u", super_version,
124            (unsigned int) version.dwMajorVersion,
125            (unsigned int) version.dwMinorVersion);
126 # else
127   sprintf (buf->sysname, "Windows%s", super_version);
128 # endif
129 
130   /* Fill in release, version.  */
131   /* The MSYS uname.exe programs uses strings from a modified Cygwin runtime:
132        $ ./uname.exe -r      => 1.0.11(0.46/3/2)
133        $ ./uname.exe -v      => 2008-08-25 23:40
134      There is no point in imitating this behaviour.  */
135   if (version.dwPlatformId == VER_PLATFORM_WIN32_NT)
136     {
137       /* Windows NT or newer.  */
138       struct windows_version
139         {
140           int major;
141           int minor;
142           unsigned int server_offset;
143           const char *name;
144         };
145 
146       /* Storing the workstation and server version names in a single
147          stream does not waste memory when they are the same.  These
148          macros abstract the representation.  VERSION1 is used if
149          version.wProductType does not matter, VERSION2 if it does.  */
150       #define VERSION1(major, minor, name) \
151         { major, minor, 0, name }
152       #define VERSION2(major, minor, workstation, server) \
153         { major, minor, sizeof workstation, workstation "\0" server }
154       static const struct windows_version versions[] =
155         {
156           VERSION2 (3, -1, "Windows NT Workstation", "Windows NT Server"),
157           VERSION2 (4, -1, "Windows NT Workstation", "Windows NT Server"),
158           VERSION1 (5, 0, "Windows 2000"),
159           VERSION1 (5, 1, "Windows XP"),
160           VERSION1 (5, 2, "Windows Server 2003"),
161           VERSION2 (6, 0, "Windows Vista", "Windows Server 2008"),
162           VERSION2 (6, 1, "Windows 7", "Windows Server 2008 R2"),
163           VERSION2 (-1, -1, "Windows", "Windows Server")
164         };
165       const char *base;
166       const struct windows_version *v = versions;
167 
168       /* Find a version that matches ours.  The last element is a
169          wildcard that always ends the loop.  */
170       while ((v->major != version.dwMajorVersion && v->major != -1)
171              || (v->minor != version.dwMinorVersion && v->minor != -1))
172         v++;
173 
174       if (have_versionex && versionex.wProductType != VER_NT_WORKSTATION)
175         base = v->name + v->server_offset;
176       else
177         base = v->name;
178       if (v->major == -1 || v->minor == -1)
179         sprintf (buf->release, "%s %u.%u",
180                  base,
181                  (unsigned int) version.dwMajorVersion,
182                  (unsigned int) version.dwMinorVersion);
183       else
184         strcpy (buf->release, base);
185     }
186   else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE)
187     {
188       /* Windows CE or Embedded CE.  */
189       sprintf (buf->release, "Windows CE %u.%u",
190                (unsigned int) version.dwMajorVersion,
191                (unsigned int) version.dwMinorVersion);
192     }
193   else
194     {
195       /* Windows 95/98/ME.  */
196       sprintf (buf->release, "Windows %s", super_version);
197     }
198   strcpy (buf->version, version.szCSDVersion);
199 
200   /* Fill in machine.  */
201   {
202     SYSTEM_INFO info;
203 
204     GetSystemInfo (&info);
205     /* Check for Windows NT or CE, since the info.wProcessorLevel is
206        garbage on Windows 95. */
207     if (version.dwPlatformId == VER_PLATFORM_WIN32_NT
208         || version.dwPlatformId == VER_PLATFORM_WIN32_CE)
209       {
210         /* Windows NT or newer, or Windows CE or Embedded CE.  */
211         switch (info.wProcessorArchitecture)
212           {
213           case PROCESSOR_ARCHITECTURE_AMD64:
214             strcpy (buf->machine, "x86_64");
215             break;
216           case PROCESSOR_ARCHITECTURE_IA64:
217             strcpy (buf->machine, "ia64");
218             break;
219           case PROCESSOR_ARCHITECTURE_INTEL:
220             strcpy (buf->machine, "i386");
221             if (info.wProcessorLevel >= 3)
222               buf->machine[1] =
223                 '0' + (info.wProcessorLevel <= 6 ? info.wProcessorLevel : 6);
224             break;
225           case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
226             strcpy (buf->machine, "i686");
227             break;
228           case PROCESSOR_ARCHITECTURE_MIPS:
229             strcpy (buf->machine, "mips");
230             break;
231           case PROCESSOR_ARCHITECTURE_ALPHA:
232           case PROCESSOR_ARCHITECTURE_ALPHA64:
233             strcpy (buf->machine, "alpha");
234             break;
235           case PROCESSOR_ARCHITECTURE_PPC:
236             strcpy (buf->machine, "powerpc");
237             break;
238           case PROCESSOR_ARCHITECTURE_SHX:
239             strcpy (buf->machine, "sh");
240             break;
241           case PROCESSOR_ARCHITECTURE_ARM:
242             strcpy (buf->machine, "arm");
243             break;
244           default:
245             strcpy (buf->machine, "unknown");
246             break;
247           }
248       }
249     else
250       {
251         /* Windows 95/98/ME.  */
252         switch (info.dwProcessorType)
253           {
254           case PROCESSOR_AMD_X8664:
255             strcpy (buf->machine, "x86_64");
256             break;
257           case PROCESSOR_INTEL_IA64:
258             strcpy (buf->machine, "ia64");
259             break;
260           default:
261             if (info.dwProcessorType % 100 == 86)
262               sprintf (buf->machine, "i%u",
263                        (unsigned int) info.dwProcessorType);
264             else
265               strcpy (buf->machine, "unknown");
266             break;
267           }
268       }
269   }
270 
271   return 0;
272 }
273 
274 #endif
275