diff --git a/user/cwdtarget.c b/user/cwdtarget.c new file mode 100644 index 0000000..28b8ec7 --- /dev/null +++ b/user/cwdtarget.c @@ -0,0 +1,75 @@ +#include "ulib.h" + +/* + * Only ever spawned by cwdtest.c, with no argv at all -- unlike every other + * *test / *target pair in this kernel (which rendezvous over a shared pipe + * handle passed as an argv string), this pair's whole point is that the + * KERNEL itself hands this process its starting directory at creation time + * (sched.c's threadCreate/threadCreateUser, via the new initialCwd helper + * that mirrors initialPgid's own "inherit from whoever is currently + * running" shape for Thread.pgid), never anything cwdtest.c has to pass + * explicitly. + * + * Proves inheritance first, then proves the inherited value is a real, + * independent COPY rather than shared state: this process's own later + * chdir() must not reach back into cwdtest.c's Thread.cwd (cwdtest.c's own + * post-wait getcwd() check is the other half of that proof). + */ + +static int streq(const char* a, const char* b) +{ + while (*a && *a == *b) { + a++; + b++; + } + return *a == *b; +} + +int main(void) +{ + print("cwdtarget: start, pid="); + printDec(userGetpid()); + print("\n"); + + char cwdBuf[64]; + long len = userGetcwd(cwdBuf, sizeof(cwdBuf)); + if (len < 0 || !streq(cwdBuf, "/tmp/cwda")) { + print("cwdtarget: FAIL inherited cwd, got: "); + print(len < 0 ? "(error)" : cwdBuf); + print("\n"); + return 1; + } + print("cwdtarget: inherited-cwd-ok\n"); + + if (userChdir("/tmp/cwdb") != 0) { + print("cwdtarget: FAIL chdir /tmp/cwdb\n"); + return 1; + } + len = userGetcwd(cwdBuf, sizeof(cwdBuf)); + if (len < 0 || !streq(cwdBuf, "/tmp/cwdb")) { + print("cwdtarget: FAIL getcwd after own chdir, got: "); + print(len < 0 ? "(error)" : cwdBuf); + print("\n"); + return 1; + } + + /* Relative path again -- must land at /tmp/cwdb/note, a COMPLETELY + different file than cwdtest.c's own /tmp/cwda/note despite the + identical relative name "note", since each process resolves it + against its own Thread.cwd. */ + int fd = (int)userOpen("note", oCreate | oWriteOnly | oTrunc); + if (fd < 0) { + print("cwdtarget: FAIL create relative note in cwdb\n"); + return 1; + } + const char* payload = "cwdb-payload"; + unsigned long payloadLen = stringLength(payload); + if (userWrite(fd, payload, payloadLen) != (long)payloadLen) { + print("cwdtarget: FAIL write relative note in cwdb\n"); + return 1; + } + userClose(fd); + print("cwdtarget: relative-write-cwdb-ok\n"); + + return 0; +} diff --git a/user/date.c b/user/date.c new file mode 100644 index 0000000..a69673d --- /dev/null +++ b/user/date.c @@ -0,0 +1,127 @@ +#include "ulib.h" + +/* + * Real ring-3 "date": the first live demo of rtc.c/sysTime's wall-clock + * time, spawned directly by kmain.c at boot exactly like nicetest.c above + * it -- fully synchronous, no injected keystroke or pipe rendezvous, so + * unlike most of this kernel's live demos this one has no scheduling- + * timing race to flake on at all. + * + * Deliberately duplicates (not shares) Howard Hinnant's civil-calendar + * algorithm rtc.c already uses: this file writes its OWN forward + * (civil -> epoch) and inverse (epoch -> civil) implementations from + * scratch, independent of the kernel side. Decoding the epoch userTime() + * returns and then re-encoding it back with this independent forward + * function must reproduce the exact same number, which proves this + * program's own encode/decode pair is a true bijection over the date it + * actually ran on -- a real, self-verifying round trip, not a print + * nobody checks. + */ + +static void printErr(const char* text) +{ + userWrite(2, text, stringLength(text)); +} + +/* Zero-padded unsigned decimal, `width` digits minimum (e.g. printPadded(7, 2) + -> "07"). Never negative here -- every field this file ever passes in is + already a non-negative calendar component. */ +static void printPadded(long value, int width) +{ + char digits[16]; + int len = 0; + long remaining = value; + + if (remaining == 0) + digits[len++] = '0'; + while (remaining > 0) { + digits[len++] = (char)('0' + (remaining % 10)); + remaining /= 10; + } + while (len < width) + digits[len++] = '0'; + + for (int i = len - 1; i >= 0; i--) + userWrite(1, &digits[i], 1); +} + +/* Howard Hinnant's days_from_civil -- forward direction, civil date to a + day count relative to 1970-01-01. See rtc.c for the same algorithm used + kernel-side; this copy is independent, not shared, on purpose (see file + header comment). */ +static long daysFromCivil(long y, long m, long d) +{ + y -= (m <= 2) ? 1 : 0; + long era = (y >= 0 ? y : y - 399) / 400; + long yoe = y - era * 400; + long doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; + long doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; + return era * 146097 + doe - 719468; +} + +/* Howard Hinnant's civil_from_days -- the inverse direction, a day count + back to a civil date. */ +static void civilFromDays(long z, long* outYear, long* outMonth, long* outDay) +{ + z += 719468; + long era = (z >= 0 ? z : z - 146096) / 146097; + long doe = z - era * 146097; + long yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; + long yy = yoe + era * 400; + long doy = doe - (365 * yoe + yoe / 4 - yoe / 100); + long mp = (5 * doy + 2) / 153; + long dd = doy - (153 * mp + 2) / 5 + 1; + long mm = mp + (mp < 10 ? 3 : -9); + + *outYear = yy + (mm <= 2 ? 1 : 0); + *outMonth = mm; + *outDay = dd; +} + +int main(void) +{ + long epoch = userTime(); + if (epoch <= 0) { + printErr("date: FAIL sysTime returned a non-positive epoch\n"); + return 1; + } + + long days = epoch / 86400; + long secondsOfDay = epoch % 86400; + long hour = secondsOfDay / 3600; + long minute = (secondsOfDay % 3600) / 60; + long second = secondsOfDay % 60; + + long year; + long month; + long day; + civilFromDays(days, &year, &month, &day); + + if (year < 2020 || year > 2099) { + printErr("date: FAIL implausible year decoded\n"); + return 1; + } + + printPadded(year, 4); + userWrite(1, "-", 1); + printPadded(month, 2); + userWrite(1, "-", 1); + printPadded(day, 2); + userWrite(1, " ", 1); + printPadded(hour, 2); + userWrite(1, ":", 1); + printPadded(minute, 2); + userWrite(1, ":", 1); + printPadded(second, 2); + userWrite(1, "\n", 1); + printErr("date: printed-ok\n"); + + long roundTrip = daysFromCivil(year, month, day) * 86400 + hour * 3600 + minute * 60 + second; + if (roundTrip != epoch) { + printErr("date: FAIL roundtrip mismatch\n"); + return 1; + } + printErr("date: roundtrip-ok\n"); + + return 0; +}