unix,win: add uv_os_uname()
Fixes: https://github.com/libuv/libuv/issues/2126 PR-URL: https://github.com/libuv/libuv/pull/2128 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com>
This commit is contained in:
parent
d39959c80d
commit
d4288bbeab
@ -167,6 +167,7 @@ set(uv_test_sources
|
||||
test/test-udp-send-immediate.c
|
||||
test/test-udp-send-unreachable.c
|
||||
test/test-udp-try-send.c
|
||||
test/test-uname.c
|
||||
test/test-walk-handles.c
|
||||
test/test-watcher-cross-stop.c)
|
||||
|
||||
@ -211,7 +212,7 @@ if(WIN32)
|
||||
else()
|
||||
list(APPEND uv_defines _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE)
|
||||
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
# Android has pthread as part of its c library, not as a separate
|
||||
# Android has pthread as part of its c library, not as a separate
|
||||
# libpthread.so.
|
||||
list(APPEND uv_libraries pthread)
|
||||
endif()
|
||||
|
||||
@ -293,6 +293,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-udp-send-immediate.c \
|
||||
test/test-udp-send-unreachable.c \
|
||||
test/test-udp-try-send.c \
|
||||
test/test-uname.c \
|
||||
test/test-walk-handles.c \
|
||||
test/test-watcher-cross-stop.c
|
||||
test_run_tests_LDADD = libuv.la
|
||||
|
||||
@ -145,6 +145,19 @@ Data types
|
||||
char* homedir;
|
||||
} uv_passwd_t;
|
||||
|
||||
.. c:type:: uv_utsname_t
|
||||
|
||||
Data type for operating system name and version information.
|
||||
|
||||
::
|
||||
|
||||
typedef struct uv_utsname_s {
|
||||
char sysname[256];
|
||||
char release[256];
|
||||
char version[256];
|
||||
char machine[256];
|
||||
} uv_utsname_t;
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
@ -549,3 +562,12 @@ API
|
||||
for others it will be silently reduced to `PRIORITY_HIGH`.
|
||||
|
||||
.. versionadded:: 1.23.0
|
||||
|
||||
.. c:function:: int uv_os_uname(uv_utsname_t* buffer)
|
||||
|
||||
Retrieves system information in `buffer`. The populated data includes the
|
||||
operating system name, release, version, and machine. On non-Windows
|
||||
systems, `uv_os_uname()` is a thin wrapper around :man:`uname(3)`. Returns
|
||||
zero on success, and a non-zero error value otherwise.
|
||||
|
||||
.. versionadded:: 1.25.0
|
||||
|
||||
17
include/uv.h
17
include/uv.h
@ -234,6 +234,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t;
|
||||
typedef struct uv_interface_address_s uv_interface_address_t;
|
||||
typedef struct uv_dirent_s uv_dirent_t;
|
||||
typedef struct uv_passwd_s uv_passwd_t;
|
||||
typedef struct uv_utsname_s uv_utsname_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL
|
||||
@ -968,13 +969,13 @@ enum uv_process_flags {
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE = (1 << 4),
|
||||
/*
|
||||
* Hide the subprocess console window that would normally be created. This
|
||||
* Hide the subprocess console window that would normally be created. This
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE = (1 << 5),
|
||||
/*
|
||||
* Hide the subprocess GUI window that would normally be created. This
|
||||
* Hide the subprocess GUI window that would normally be created. This
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
@ -1054,6 +1055,16 @@ struct uv_passwd_s {
|
||||
char* homedir;
|
||||
};
|
||||
|
||||
struct uv_utsname_s {
|
||||
char sysname[256];
|
||||
char release[256];
|
||||
char version[256];
|
||||
char machine[256];
|
||||
/* This struct does not contain the nodename and domainname fields present in
|
||||
the utsname type. domainname is a GNU extension. Both fields are referred
|
||||
to as meaningless in the docs. */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_DIRENT_UNKNOWN,
|
||||
UV_DIRENT_FILE,
|
||||
@ -1135,6 +1146,8 @@ UV_EXTERN int uv_os_unsetenv(const char* name);
|
||||
|
||||
UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
|
||||
|
||||
UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
|
||||
|
||||
|
||||
typedef enum {
|
||||
UV_FS_UNKNOWN = -1,
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
#include <sys/uio.h> /* writev */
|
||||
#include <sys/resource.h> /* getrusage */
|
||||
#include <pwd.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#ifdef __sun
|
||||
# include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
|
||||
@ -1357,3 +1358,59 @@ int uv_os_setpriority(uv_pid_t pid, int priority) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
struct utsname buf;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uname(&buf) == -1) {
|
||||
r = UV__ERR(errno);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
#ifdef _AIX
|
||||
r = snprintf(buffer->release,
|
||||
sizeof(buffer->release),
|
||||
"%s.%s",
|
||||
buf.version,
|
||||
buf.release);
|
||||
if (r >= sizeof(buffer->release)) {
|
||||
r = UV_E2BIG;
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
#if defined(_AIX) || defined(__PASE__)
|
||||
r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine));
|
||||
#else
|
||||
r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine));
|
||||
#endif
|
||||
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
buffer->sysname[0] = '\0';
|
||||
buffer->release[0] = '\0';
|
||||
buffer->version[0] = '\0';
|
||||
buffer->machine[0] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
117
src/win/util.c
117
src/win/util.c
@ -1627,3 +1627,120 @@ int uv_os_setpriority(uv_pid_t pid, int priority) {
|
||||
CloseHandle(handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
/* Implementation loosely based on
|
||||
https://github.com/gagern/gnulib/blob/master/lib/uname.c */
|
||||
OSVERSIONINFOW os_info;
|
||||
SYSTEM_INFO system_info;
|
||||
int processor_level;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__once_init();
|
||||
os_info.dwOSVersionInfoSize = sizeof(os_info);
|
||||
os_info.szCSDVersion[0] = L'\0';
|
||||
|
||||
/* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
|
||||
if RtlGetVersion() is not available. */
|
||||
if (pRtlGetVersion) {
|
||||
pRtlGetVersion(&os_info);
|
||||
} else {
|
||||
/* Silence GetVersionEx() deprecation warning. */
|
||||
#pragma warning(suppress : 4996)
|
||||
if (GetVersionExW(&os_info) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the version field. */
|
||||
if (WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
os_info.szCSDVersion,
|
||||
-1,
|
||||
buffer->version,
|
||||
sizeof(buffer->version),
|
||||
NULL,
|
||||
NULL) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Populate the sysname field. */
|
||||
#ifdef __MINGW32__
|
||||
r = snprintf(buffer->sysname,
|
||||
sizeof(buffer->sysname),
|
||||
"MINGW32_NT-%u.%u",
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion);
|
||||
assert(r < sizeof(buffer->sysname));
|
||||
#else
|
||||
uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
|
||||
#endif
|
||||
|
||||
/* Populate the release field. */
|
||||
r = snprintf(buffer->release,
|
||||
sizeof(buffer->release),
|
||||
"%d.%d.%d",
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion,
|
||||
(unsigned int) os_info.dwBuildNumber);
|
||||
assert(r < sizeof(buffer->release));
|
||||
|
||||
/* Populate the machine field. */
|
||||
GetSystemInfo(&system_info);
|
||||
|
||||
switch (system_info.wProcessorArchitecture) {
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
|
||||
|
||||
if (system_info.wProcessorLevel > 3) {
|
||||
processor_level = system_info.wProcessorLevel < 6 ?
|
||||
system_info.wProcessorLevel : 6;
|
||||
buffer->machine[1] = '0' + processor_level;
|
||||
}
|
||||
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
|
||||
uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_MIPS:
|
||||
uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA64:
|
||||
uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_PPC:
|
||||
uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_SHX:
|
||||
uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM:
|
||||
uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
|
||||
break;
|
||||
default:
|
||||
uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
buffer->sysname[0] = '\0';
|
||||
buffer->release[0] = '\0';
|
||||
buffer->version[0] = '\0';
|
||||
buffer->machine[0] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
sRtlGetVersion pRtlGetVersion;
|
||||
sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
sNtQueryInformationFile pNtQueryInformationFile;
|
||||
@ -55,6 +56,9 @@ void uv_winapi_init(void) {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
}
|
||||
|
||||
pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module,
|
||||
"RtlGetVersion");
|
||||
|
||||
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
|
||||
ntdll_module,
|
||||
"RtlNtStatusToDosError");
|
||||
|
||||
@ -4519,6 +4519,9 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE)
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG Reserved);
|
||||
|
||||
typedef NTSTATUS (NTAPI *sRtlGetVersion)
|
||||
(PRTL_OSVERSIONINFOW lpVersionInformation);
|
||||
|
||||
typedef ULONG (NTAPI *sRtlNtStatusToDosError)
|
||||
(NTSTATUS Status);
|
||||
|
||||
@ -4707,6 +4710,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlGetVersion pRtlGetVersion;
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
extern sNtQueryInformationFile pNtQueryInformationFile;
|
||||
|
||||
@ -450,6 +450,7 @@ TEST_DECLARE (fork_threadpool_queue_work_simple)
|
||||
|
||||
TEST_DECLARE (idna_toascii)
|
||||
TEST_DECLARE (utf8_decode1)
|
||||
TEST_DECLARE (uname)
|
||||
|
||||
TASK_LIST_START
|
||||
TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000)
|
||||
@ -960,6 +961,7 @@ TASK_LIST_START
|
||||
#endif
|
||||
|
||||
TEST_ENTRY (utf8_decode1)
|
||||
TEST_ENTRY (uname)
|
||||
|
||||
/* Doesn't work on z/OS because that platform uses EBCDIC, not ASCII. */
|
||||
#ifndef __MVS__
|
||||
|
||||
@ -35,6 +35,7 @@ TEST_IMPL(platform_output) {
|
||||
uv_cpu_info_t* cpus;
|
||||
uv_interface_address_t* interfaces;
|
||||
uv_passwd_t pwd;
|
||||
uv_utsname_t uname;
|
||||
int count;
|
||||
int i;
|
||||
int err;
|
||||
@ -153,5 +154,13 @@ TEST_IMPL(platform_output) {
|
||||
ASSERT(ppid > 0);
|
||||
printf("uv_os_getppid: %d\n", (int) ppid);
|
||||
|
||||
err = uv_os_uname(&uname);
|
||||
ASSERT(err == 0);
|
||||
printf("uv_os_uname:\n");
|
||||
printf(" sysname: %s\n", uname.sysname);
|
||||
printf(" release: %s\n", uname.release);
|
||||
printf(" version: %s\n", uname.version);
|
||||
printf(" machine: %s\n", uname.machine);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
69
test/test-uname.c
Normal file
69
test/test-uname.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
TEST_IMPL(uname) {
|
||||
#ifndef _WIN32
|
||||
struct utsname buf;
|
||||
#endif
|
||||
#ifdef _AIX
|
||||
char temp[256];
|
||||
#endif
|
||||
uv_utsname_t buffer;
|
||||
int r;
|
||||
|
||||
/* Verify that NULL is handled properly. */
|
||||
r = uv_os_uname(NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
/* Verify the happy path. */
|
||||
r = uv_os_uname(&buffer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
#ifndef _WIN32
|
||||
ASSERT(uname(&buf) != -1);
|
||||
ASSERT(strcmp(buffer.sysname, buf.sysname) == 0);
|
||||
ASSERT(strcmp(buffer.version, buf.version) == 0);
|
||||
|
||||
# ifdef _AIX
|
||||
snprintf(temp, sizeof(temp), "%s.%s", buf.version, buf.release);
|
||||
ASSERT(strcmp(buffer.release, temp) == 0);
|
||||
# else
|
||||
ASSERT(strcmp(buffer.release, buf.release) == 0);
|
||||
# endif /* _AIX */
|
||||
|
||||
# if defined(_AIX) || defined(__PASE__)
|
||||
ASSERT(strcmp(buffer.machine, "ppc64") == 0);
|
||||
# else
|
||||
ASSERT(strcmp(buffer.machine, buf.machine) == 0);
|
||||
# endif /* defined(_AIX) || defined(__PASE__) */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -154,6 +154,7 @@
|
||||
'test-udp-multicast-interface.c',
|
||||
'test-udp-multicast-interface6.c',
|
||||
'test-udp-try-send.c',
|
||||
'test-uname.c',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'OS=="win"', {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user