Skip to content

Commit

Permalink
unix,win: add uv_os_uname()
Browse files Browse the repository at this point in the history
Fixes: libuv#2126
PR-URL: libuv#2128
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Bartosz Sosnowski <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
  • Loading branch information
cjihrig committed Jan 14, 2019
1 parent d39959c commit d4288bb
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions docs/src/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
---
Expand Down Expand Up @@ -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 changes: 15 additions & 2 deletions include/uv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
57 changes: 57 additions & 0 deletions src/unix/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 changes: 117 additions & 0 deletions src/win/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions src/win/winapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@


/* Ntdll function pointers */
sRtlGetVersion pRtlGetVersion;
sRtlNtStatusToDosError pRtlNtStatusToDosError;
sNtDeviceIoControlFile pNtDeviceIoControlFile;
sNtQueryInformationFile pNtQueryInformationFile;
Expand Down Expand Up @@ -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");
Expand Down
4 changes: 4 additions & 0 deletions src/win/winapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -4707,6 +4710,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)


/* Ntdll function pointers */
extern sRtlGetVersion pRtlGetVersion;
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
extern sNtQueryInformationFile pNtQueryInformationFile;
Expand Down
2 changes: 2 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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__
Expand Down
9 changes: 9 additions & 0 deletions test/test-platform-output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Loading

0 comments on commit d4288bb

Please sign in to comment.