fix(libc): honor openlog identity and facility
This commit is contained in:
parent
77b9f7270c
commit
653c5449f9
|
|
@ -4,9 +4,13 @@
|
|||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include "prx/libc/include/WindowsFormatting.hpp"
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -20,7 +24,11 @@ constexpr int priorityMask = 0x07;
|
|||
constexpr int facilityMask = 0x3f8;
|
||||
constexpr int userFacility = 1 << 3;
|
||||
constexpr int internalLogPriority = 3 | 0x02 | 0x20 | 0x01;
|
||||
constexpr int logPid = 0x01;
|
||||
int logMask = 0xff;
|
||||
int logOptions = 0;
|
||||
int logFacility = userFacility;
|
||||
std::optional<std::string> logIdentity;
|
||||
|
||||
std::mutex& OutputMutex() {
|
||||
static std::mutex mutex;
|
||||
|
|
@ -28,7 +36,17 @@ std::mutex& OutputMutex() {
|
|||
}
|
||||
|
||||
void Emit(int priority, const std::string& message) {
|
||||
std::fprintf(stderr, "[syslog:%d] %s", priority, message.c_str());
|
||||
std::fprintf(stderr, "[syslog:%d] ", priority);
|
||||
if (logIdentity) std::fputs(logIdentity->c_str(), stderr);
|
||||
if (logOptions & logPid) {
|
||||
#ifdef _WIN32
|
||||
std::fprintf(stderr, "[%d]", ::_getpid());
|
||||
#else
|
||||
std::fprintf(stderr, "[%d]", static_cast<int>(::getpid()));
|
||||
#endif
|
||||
}
|
||||
if (logIdentity) std::fputs(": ", stderr);
|
||||
std::fputs(message.c_str(), stderr);
|
||||
if (message.empty() || message.back() != '\n') std::fputc('\n', stderr);
|
||||
std::fflush(stderr);
|
||||
}
|
||||
|
|
@ -71,6 +89,18 @@ std::string Format(const char* format, VaList* args) {
|
|||
}
|
||||
|
||||
extern "C" {
|
||||
void APS5_VABI openlog_nid_postfix(const char* identity, int options, int facility) {
|
||||
std::lock_guard lock(OutputMutex());
|
||||
if (identity) logIdentity = identity;
|
||||
logOptions = options;
|
||||
if (facility != 0 && (facility & ~facilityMask) == 0) logFacility = facility;
|
||||
}
|
||||
|
||||
void APS5_VABI closelog_nid_postfix() {
|
||||
std::lock_guard lock(OutputMutex());
|
||||
logIdentity.reset();
|
||||
}
|
||||
|
||||
int APS5_VABI setlogmask_nid_postfix(int mask) {
|
||||
std::lock_guard lock(OutputMutex());
|
||||
const int previous = logMask;
|
||||
|
|
@ -90,7 +120,7 @@ void APS5_VABI vsyslog_nid_postfix(int priority, const char* format, VaList* arg
|
|||
priority &= priorityMask | facilityMask;
|
||||
}
|
||||
if (logMask & (1 << (priority & priorityMask))) {
|
||||
if ((priority & facilityMask) == 0) priority |= userFacility;
|
||||
if ((priority & facilityMask) == 0) priority |= logFacility;
|
||||
Emit(priority, format ? Format(ExpandErrorText(format, saved).c_str(), args) : std::string());
|
||||
}
|
||||
*__error_nid_postfix() = saved;
|
||||
|
|
|
|||
|
|
@ -2,15 +2,19 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
void APS5_VABI syslog_nid_postfix(int, const char*, ...);
|
||||
void APS5_VABI openlog_nid_postfix(const char*, int, int);
|
||||
void APS5_VABI closelog_nid_postfix();
|
||||
int APS5_VABI setlogmask_nid_postfix(int);
|
||||
int* APS5_VABI __error_nid_postfix();
|
||||
}
|
||||
|
|
@ -60,6 +64,15 @@ int main() {
|
|||
Require(setlogmask_nid_postfix(0) == 0xff);
|
||||
syslog_nid_postfix(7, "mask shared across threads");
|
||||
syslog_nid_postfix(7, "wide %ls %d %S", u"guest", 5, u"text");
|
||||
openlog_nid_postfix("worker", 1, 16 << 3);
|
||||
syslog_nid_postfix(6, "configured default facility");
|
||||
openlog_nid_postfix(nullptr, 1, 0);
|
||||
syslog_nid_postfix(6, "null identity keeps tag");
|
||||
openlog_nid_postfix("daemon", 0, 24 << 3);
|
||||
syslog_nid_postfix(16 | 3, "explicit facility");
|
||||
openlog_nid_postfix("closing", 1, 0);
|
||||
closelog_nid_postfix();
|
||||
syslog_nid_postfix(6, "identity cleared, options and facility retained");
|
||||
std::fflush(stderr);
|
||||
#ifdef _WIN32
|
||||
Require(::_dup2(saved, ::_fileno(stderr)) == 0 && ::_close(saved) == 0);
|
||||
|
|
@ -86,6 +99,18 @@ int main() {
|
|||
"[syslog:22] level 6\n"
|
||||
"[syslog:15] mask shared across threads\n"
|
||||
"[syslog:15] wide guest 5 text\n";
|
||||
Require(length == std::strlen(expected) && std::strcmp(text, expected) == 0);
|
||||
const std::string prefix = expected;
|
||||
const std::string pid = std::to_string(
|
||||
#ifdef _WIN32
|
||||
::_getpid()
|
||||
#else
|
||||
::getpid()
|
||||
#endif
|
||||
);
|
||||
const std::string configured = "[syslog:134] worker[" + pid + "]: configured default facility\n"
|
||||
"[syslog:134] worker[" + pid + "]: null identity keeps tag\n"
|
||||
"[syslog:19] daemon: explicit facility\n"
|
||||
"[syslog:198] [" + pid + "] identity cleared, options and facility retained\n";
|
||||
Require(length == prefix.size() + configured.size() && std::string(text, length) == prefix + configured);
|
||||
Require(std::fclose(captured) == 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
- [localtime, mktime](../../../core/libs/prx/libc/src/Time.cpp) (libc) on Windows convert through the CRT's `localtime_s` and `mktime`, which accept about 1970 to January 3001 UTC and apply the CRT's daylight-saving rule. A time outside that range is converted a whole number of 400-year Gregorian cycles away, where the calendar repeats, so it gets the rule the CRT applies to that year and not the zone's historical one. `gmtime` converts every time whose year fits an `int` on both hosts.
|
||||
- [strftime](../../../core/libs/prx/libc/src/Time.cpp) (libc) expands FreeBSD's `%k`, `%l`, `%s`, `%v` and `%+` itself, ignoring a leading `E` or `O` as FreeBSD does. Unknown conversions, repeated modifiers and incomplete conversions emit literals as in FreeBSD 11; recognized conversions otherwise go to the host's `strftime`. On Windows the `%-`, `%_` and `%0` padding flags still produce nothing, including on the five expanded conversions (`%-k`, `%_k` and `%0k` go to the host), and a standalone `%z` or `%Z` uses the host's zone instead of the broken-down time's `tm_zone`. `%s` follows FreeBSD 9 and 11 and is the local-time `mktime` of the broken-down time (current FreeBSD uses `tm_gmtoff`), which is -1 on Windows outside the range above. `%+` is the C locale's `%a %b %e %H:%M:%S %Z %Y` with `%Z` taken from `tm_zone`, or from `tzname[tm_isdst != 0]` when it is null.
|
||||
- [wcsftime](../../../core/libs/prx/libc/src/Time.cpp) (libc) follows FreeBSD 11.4's [wcsftime.c](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libc/locale/wcsftime.c) over this library's `wcsrtombs`, `strftime` and `mbsrtowcs` in the single-byte C locale of [none.c](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libc/locale/none.c), with the guest's 16-bit `wchar_t`, without console verification. It has the `strftime` gaps above. A format unit above 255 returns 0 with `EILSEQ`; an empty result, a result that does not fit and a null buffer return 0 with `errno` unchanged, discarding the `ERANGE` or `EINVAL` that the Windows CRT's `strftime` sets. A null format or `tm` throws, where FreeBSD dereferences it (a null `tm` is read there only when the format has a conversion that needs it)
|
||||
- [syslog](../../../core/libs/prx/libc/src/Syslog.cpp) (libc) writes each message to `stderr` as `[syslog:<priority>] <message>`, with a newline added when missing, instead of sending it to the console's system log. Priority and facility handling follow FreeBSD's `vsyslog`: `%m` expands to the guest errno's message, unknown bits are reported (as priority 0x23, since FreeBSD passes `LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID` as the priority) and masked, a missing facility becomes `LOG_USER`, and errno is preserved. `setlogmask` follows [FreeBSD 11](https://github.com/freebsd/freebsd-src/blob/8d2708de5d6112a492744d367cfdfb8fd219227a/lib/libc/gen/syslog.c): the process-wide mask defaults to 0xff, zero queries it, and nonzero values replace it; masked messages are skipped before formatting, including the unknown-priority diagnostic. The console's mask behaviour is unverified. `openlog` and `closelog` are not implemented, so their identity and options are not applied
|
||||
- [syslog](../../../core/libs/prx/libc/src/Syslog.cpp) (libc) writes each message to `stderr` as `[syslog:<priority>] <message>`, with a newline added when missing, instead of sending it to the console's system log. Priority and facility handling follow FreeBSD's `vsyslog`: `%m` expands to the guest errno's message, unknown bits are reported (as priority 0x23, since FreeBSD passes `LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID` as the priority) and masked, a missing facility becomes `LOG_USER` or the facility set by `openlog`, and errno is preserved. `openlog` applies its identity and `LOG_PID`; a null identity retains the previous one, and a valid nonzero facility replaces the default. `closelog` clears the identity but retains the options and facility, as in FreeBSD 11. `LOG_PERROR` has no extra effect because stderr is the emulated log sink; `LOG_NDELAY`/`LOG_ODELAY`, `LOG_NOWAIT` and `LOG_CONS` have no daemon, child or console backend to control. `setlogmask` follows [FreeBSD 11](https://github.com/freebsd/freebsd-src/blob/8d2708de5d6112a492744d367cfdfb8fd219227a/lib/libc/gen/syslog.c): the process-wide mask defaults to 0xff, zero queries it, and nonzero values replace it; masked messages are skipped before formatting, including the unknown-priority diagnostic. The console's mask behaviour is unverified
|
||||
- [daemon](../../../core/libs/prx/libc/src/Process.cpp) (libc) throws: forking into the background is not supported. PPSA85300 imports it and fails to load without it. VLC 3.0 calls it only when its `daemon` option is set ([libvlc.c](https://github.com/videolan/vlc/blob/6de05adcbaf2e8b85fe86aad4169393098628119/src/libvlc.c#L190-L197)), and the title starts libVLC with `--ignore-config` and without `--daemon` ([player.cc](https://github.com/ZiZc3/VLC/blob/f3253020a64368153233ede29183014c0b6c8979/src/player.cc#L960-L981))
|
||||
- [_WStoul](../../../core/libs/prx/libc/src/Strings.cpp), [_Iswctype](../../../core/libs/prx/libc/src/RuneLocale.cpp) and [swscanf_s](../../../core/libs/prx/libc/src/ScanningWide.cpp) (libc) - `_WStoul` is `wcstoul` and throws for a base other than 0 or 2 to 36. `_Iswctype` takes the class numbers of Dinkumware's [xwcc.h](https://github.com/superna9999/ti-cgt6x/blob/cgt6x_7_3_4/include/xwcc.h) (1 `alnum` to 11 `xdigit`, 12 `blank`) and throws for any other value, including the FreeBSD masks `wctype` returns; the numbering is not confirmed on the console's `libc.prx`. `swscanf_s` follows C11 7.29.2.2 and K.3.9.1.5, but reads the size argument as `unsigned int` like `sscanf_s` where K.3.9.1.5 specifies `rsize_t`; the console's width is unverified. A runtime-constraint violation (null buffer, format or receiving pointer) only returns `EOF`, and a too small array gets a null first element as in `sscanf_s`. A literal mismatch is a matching failure and a field that is only a prefix, such as `0x` or `1e`, does not convert, as C11 requires; FreeBSD's `vfwscanf` reports an input failure for the first and converts the second. Integers out of range are truncated from `strtoll`/`strtoull`. It throws for `%p`, `%S`, `%C`, unknown length modifiers, scanset ranges, `%n` with suppression or width, and narrow `%s`, `%c` or `%[` input that the C-locale `wcrtomb` cannot convert
|
||||
- [flock](../../../core/libs/prx/libc/src/FileLock.cpp) (libkernel) on Windows shares one lock state between duplicated descriptors, following FreeBSD 11.4's [flock(2)](https://github.com/freebsd/freebsd-src/blob/releng/11.4/lib/libc/sys/flock.2). Independent opens have separate states; closing a descriptor or reopening a stream drops only its reference. Lock transitions on one open file description are serialized. The host's [LockFileEx](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex) locks also restrict ordinary reads and writes through other handles, unlike FreeBSD's advisory locks, and do not restrict mapped views. Console behavior, signal interruption and concurrent closure of a descriptor while its lock call is pending are unverified.
|
||||
|
|
|
|||
Loading…
Reference in New Issue