/* * \brief Sysctl facade * \author Emery Hemingway * \date 2016-04-27 */ /* * Copyright (C) 2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ /* Genode includes */ #include #include /* Genode-specific libc interfaces */ #include #include /* Libc includes */ #include #include #include #include #include #include "libc_errno.h" enum { PAGESIZE = 4096 }; extern "C" long sysconf(int name) { switch (name) { case _SC_CHILD_MAX: return CHILD_MAX; case _SC_OPEN_MAX: return getdtablesize(); case _SC_NPROCESSORS_CONF: return 1; case _SC_NPROCESSORS_ONLN: return 1; case _SC_PAGESIZE: return PAGESIZE; case _SC_PHYS_PAGES: return Genode::env()->ram_session()->quota() / PAGESIZE; default: Genode::warning(__func__, "(", name, ") not implemented"); return Libc::Errno(EINVAL); } } /* non-standard FreeBSD function not supported */ extern "C" int sysctlbyname(char const *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { Genode::warning(__func__, "(", name, ",...) not implemented"); return Libc::Errno(ENOENT); } extern "C" int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { static const ctlname ctl_names[] = CTL_NAMES; static const ctlname ctl_kern_names[] = CTL_KERN_NAMES; static const ctlname ctl_hw_names[] = CTL_HW_NAMES; static const ctlname ctl_user_names[] = CTL_USER_NAMES; static const ctlname ctl_p1003_1b_names[] = CTL_P1003_1B_NAMES; /* read only */ if (!oldp) /* check for write attempt */ return Libc::Errno(newp ? EPERM : EINVAL); ctlname const *ctl = nullptr; char *buf = (char*)oldp; int index_a = name[0]; int index_b = name[1]; if (namelen != 2) return Libc::Errno(ENOENT); if (index_a >= CTL_MAXID) return Libc::Errno(EINVAL); switch(index_a) { case CTL_KERN: if (index_b >= KERN_MAXID) return Libc::Errno(EINVAL); ctl = &ctl_kern_names[index_b]; break; case CTL_HW: if (index_b >= HW_MAXID) return Libc::Errno(EINVAL); ctl = &ctl_hw_names[index_b]; break; case CTL_USER: if (index_b >= USER_MAXID) return Libc::Errno(EINVAL); ctl = &ctl_user_names[index_b]; break; case CTL_P1003_1B: if (index_b >= CTL_P1003_1B_MAXID) return Libc::Errno(EINVAL); ctl = &ctl_p1003_1b_names[index_b]; break; } if (!ctl) return Libc::Errno(EINVAL); if (((ctl->ctl_type == CTLTYPE_INT) && (*oldlenp < sizeof(int))) || ((ctl->ctl_type == CTLTYPE_STRING) && (*oldlenp < 1)) || ((ctl->ctl_type == CTLTYPE_QUAD) && (*oldlenp < sizeof(Genode::uint64_t))) || ((ctl->ctl_type == CTLTYPE_UINT) && (*oldlenp < sizeof(unsigned int))) || ((ctl->ctl_type == CTLTYPE_LONG) && (*oldlenp < sizeof(long))) || ((ctl->ctl_type == CTLTYPE_ULONG) && (*oldlenp < sizeof(unsigned long)))) { return Libc::Errno(EINVAL); } /* builtins */ { switch(index_a) { case CTL_HW: switch(index_b) { case HW_PHYSMEM: case HW_USERMEM: *(unsigned long*)oldp = Genode::env()->ram_session()->quota(); *oldlenp = sizeof(unsigned long); return 0; case HW_PAGESIZE: *(int*)oldp = (int)PAGESIZE; *oldlenp = sizeof(int); return 0; } break; case CTL_P1003_1B: switch(index_b) { case CTL_P1003_1B_PAGESIZE: *(int*)oldp = PAGESIZE; *oldlenp = sizeof(int); return 0; } break; } } /* runtime overrides */ { Libc::Absolute_path sysctl_path(ctl_names[index_a].ctl_name, "/.sysctl/"); sysctl_path.append("/"); sysctl_path.append(ctl->ctl_name); /* * read from /.sysctl/... * * The abstracted libc interface is used to read files here * rather than to explicity resolve a file system plugin. */ int fd = open(sysctl_path.base(), 0); if (fd != -1) { auto n = read(fd, buf, *oldlenp); close(fd); if (n > 0) switch (ctl->ctl_type) { case CTLTYPE_INT: { long value = 0; Genode::ascii_to((char*)oldp, value); *(int*)oldp = int(value); *oldlenp = sizeof(int); return 0; } case CTLTYPE_STRING: *oldlenp = n; return 0; case CTLTYPE_QUAD: { Genode::uint64_t value = 0; Genode::ascii_to((char*)oldp, value); *(Genode::uint64_t*)oldp = value; *oldlenp = sizeof(Genode::uint64_t); return 0; } case CTLTYPE_UINT: { unsigned value = 0; Genode::ascii_to((char*)oldp, value); *(unsigned*)oldp = value; *oldlenp = sizeof(unsigned); return 0; } case CTLTYPE_LONG: { long value = 0; Genode::ascii_to((char*)oldp, value); *(long*)oldp = value; *oldlenp = sizeof(long); return 0; } case CTLTYPE_ULONG: { unsigned long value = 0; Genode::ascii_to((char*)oldp, value); *(unsigned long*)oldp = value; *oldlenp = sizeof(unsigned long); return 0; } default: Genode::warning("unhandled sysctl data type for ", sysctl_path); return Libc::Errno(EINVAL); } } } /* fallback values */ { switch(index_a) { case CTL_KERN: switch(index_b) { case KERN_OSTYPE: Genode::strncpy(buf, "Genode", *oldlenp); *oldlenp = Genode::strlen(buf); return 0; case KERN_OSRELEASE: case KERN_OSREV: case KERN_VERSION: *oldlenp = 0; return 0; case KERN_HOSTNAME: Genode::strncpy(buf, "localhost", *oldlenp); *oldlenp = Genode::strlen(buf); return 0; } break; case CTL_HW: switch(index_b) { case HW_MACHINE: *oldlenp = 0; return 0; case HW_NCPU: *(int*)oldp = 1; *oldlenp = sizeof(int); return 0; } break; } } Genode::warning("sysctl: no builtin or override value found for ", Genode::Cstring(ctl_names[index_a].ctl_name), ".", Genode::Cstring(ctl->ctl_name)); return Libc::Errno(ENOENT); }