tools/nolibc: add support for uname(2)

All supported kernels are assumed to use struct new_utsname.
This is validated in test_uname().

uname(2) can for example be used in ksft_min_kernel_version() from the
kernels selftest framework.

Link: https://lore.kernel.org/lkml/20240412123536.GA32444@redhat.com/
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Acked-by: Willy Tarreau <w@1wt.eu>
This commit is contained in:
Thomas Weißschuh 2024-04-14 01:45:09 +02:00
parent e93b912ecf
commit 0adab2b6b7
2 changed files with 69 additions and 0 deletions

View File

@ -22,6 +22,7 @@
#include <linux/stat.h> /* for statx() */
#include <linux/prctl.h>
#include <linux/resource.h>
#include <linux/utsname.h>
#include "arch.h"
#include "errno.h"
@ -1139,6 +1140,32 @@ int umount2(const char *path, int flags)
}
/*
* int uname(struct utsname *buf);
*/
struct utsname {
char sysname[65];
char nodename[65];
char release[65];
char version[65];
char machine[65];
char domainname[65];
};
static __attribute__((unused))
int sys_uname(struct utsname *buf)
{
return my_syscall1(__NR_uname, buf);
}
static __attribute__((unused))
int uname(struct utsname *buf)
{
return __sysret(sys_uname(buf));
}
/*
* int unlink(const char *path);
*/

View File

@ -27,6 +27,7 @@
#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <dirent.h>
#include <errno.h>
@ -780,6 +781,45 @@ int test_stat_timestamps(void)
return 0;
}
int test_uname(void)
{
struct utsname buf;
char osrelease[sizeof(buf.release)];
ssize_t r;
int fd;
memset(&buf.domainname, 'P', sizeof(buf.domainname));
if (uname(&buf))
return 1;
if (strncmp("Linux", buf.sysname, sizeof(buf.sysname)))
return 1;
fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
if (fd == -1)
return 1;
r = read(fd, osrelease, sizeof(osrelease));
if (r == -1)
return 1;
close(fd);
if (osrelease[r - 1] == '\n')
r--;
/* Validate one of the later fields to ensure field sizes are correct */
if (strncmp(osrelease, buf.release, r))
return 1;
/* Ensure the field domainname is set, it is missing from struct old_utsname */
if (strnlen(buf.domainname, sizeof(buf.domainname)) == sizeof(buf.domainname))
return 1;
return 0;
}
int test_mmap_munmap(void)
{
int ret, fd, i, page_size;
@ -985,6 +1025,8 @@ int run_syscall(int min, int max)
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break;
CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
CASE_TEST(uname); EXPECT_SYSZR(proc, test_uname()); break;
CASE_TEST(uname_fault); EXPECT_SYSER(1, uname(NULL), -1, EFAULT); break;
CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break;
CASE_TEST(unlink_blah); EXPECT_SYSER(1, unlink("/proc/self/blah"), -1, ENOENT); break;
CASE_TEST(wait_child); EXPECT_SYSER(1, wait(&tmp), -1, ECHILD); break;