test: cover streq
This commit is contained in:
1 parent
144f0b619f
commit
8065a01f7b
2 files changed
+195
No files matched your search
@@ -0,0 +1,47 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exercises argv/argc plumbing added this wave (elfBuildInitialStack in
|
||||||
|
* elf.c, copyUserArgv in syscall.c, crt.S's _start now reading argc/argv
|
||||||
|
* off the initial stack instead of calling main() with nothing). Only ever
|
||||||
|
* spawned by proctest.c, with a specific, known argv -- if the kernel-side
|
||||||
|
* stack layout is wrong in any way (misaligned rsp, wrong argc, a string
|
||||||
|
* copied to the wrong address, an argv[i] pointer landing on garbage),
|
||||||
|
* these comparisons catch it directly instead of a lucky match papering
|
||||||
|
* over a bug. userspace has no libc string.h, so the comparison is spelled
|
||||||
|
* out by hand exactly the way spawntarget.c/proctest.c already avoid
|
||||||
|
* pulling in anything beyond ulib.h.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int streq(const char* a, const char* b)
|
||||||
|
{
|
||||||
|
while (*a && *a == *b) {
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
return *a == *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
print("argtest: argc=");
|
||||||
|
printDec(argc);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
print("argtest: argv[");
|
||||||
|
printDec(i);
|
||||||
|
print("]=");
|
||||||
|
print(argv[i]);
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ok = argc == 4 &&
|
||||||
|
streq(argv[0], "/bin/argtest") &&
|
||||||
|
streq(argv[1], "alpha") &&
|
||||||
|
streq(argv[2], "beta") &&
|
||||||
|
streq(argv[3], "gamma");
|
||||||
|
|
||||||
|
print(ok ? "argtest: argv-ok\n" : "argtest: argv-FAIL\n");
|
||||||
|
return ok ? 0 : 1;
|
||||||
|
}
|
||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boot-time driver for real per-process working directories (sched.h's new
|
||||||
|
* Thread.cwd, vfs.h's new vfsChdir/vfsGetcwd/vfsResolvePath). Before this
|
||||||
|
* fala the only "current directory" concept anywhere in this kernel was a
|
||||||
|
* single static local inside shell.c, shared by nothing else -- a spawned
|
||||||
|
* user process calling open()/mkdir()/etc with a RELATIVE path had never
|
||||||
|
* actually worked, since vfs.c's lookupNode/sfsLookup always resolved
|
||||||
|
* relative to the filesystem root, never to any per-process notion of
|
||||||
|
* "here".
|
||||||
|
*
|
||||||
|
* This proves three things a single shared global cannot: (1) THIS
|
||||||
|
* process's own chdir() makes its OWN later relative opens resolve there,
|
||||||
|
* (2) cwdtarget, spawned AFTER that chdir(), inherits the new directory at
|
||||||
|
* creation time (real fork()'s own cwd-copy semantics, sched.c's new
|
||||||
|
* initialCwd mirroring initialPgid's own shape exactly), and (3)
|
||||||
|
* cwdtarget's own later chdir() does NOT reach back and change THIS
|
||||||
|
* process's -- each Thread owns an independent buffer, never a pointer to
|
||||||
|
* shared state. No pipes, signals, or injected keystrokes anywhere in this
|
||||||
|
* pair: every step is ordered by a real userWait, so unlike most of this
|
||||||
|
* kernel's other live demos this one has no scheduling-timing race to flake
|
||||||
|
* on at all.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int streq(const char* a, const char* b)
|
||||||
|
{
|
||||||
|
while (*a && *a == *b) {
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
return *a == *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("cwdtest: start, pid=");
|
||||||
|
printDec(userGetpid());
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
userMkdir("/tmp/cwda");
|
||||||
|
userMkdir("/tmp/cwdb");
|
||||||
|
|
||||||
|
if (userChdir("/tmp/cwda") != 0) {
|
||||||
|
print("cwdtest: FAIL chdir /tmp/cwda\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char cwdBuf[64];
|
||||||
|
long len = userGetcwd(cwdBuf, sizeof(cwdBuf));
|
||||||
|
if (len < 0 || !streq(cwdBuf, "/tmp/cwda")) {
|
||||||
|
print("cwdtest: FAIL getcwd after chdir, got: ");
|
||||||
|
print(len < 0 ? "(error)" : cwdBuf);
|
||||||
|
print("\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("cwdtest: chdir-cwda-ok\n");
|
||||||
|
|
||||||
|
/* Relative path -- no leading '/' -- must resolve against the cwd just
|
||||||
|
set above, landing at /tmp/cwda/note, not the filesystem root. */
|
||||||
|
int fd = (int)userOpen("note", oCreate | oWriteOnly | oTrunc);
|
||||||
|
if (fd < 0) {
|
||||||
|
print("cwdtest: FAIL create relative note in cwda\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const char* cwdaPayload = "cwda-payload";
|
||||||
|
unsigned long cwdaLen = stringLength(cwdaPayload);
|
||||||
|
if (userWrite(fd, cwdaPayload, cwdaLen) != (long)cwdaLen) {
|
||||||
|
print("cwdtest: FAIL write relative note in cwda\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
userClose(fd);
|
||||||
|
print("cwdtest: relative-write-cwda-ok\n");
|
||||||
|
|
||||||
|
long target = userSpawn("/bin/cwdtarget", 0);
|
||||||
|
if (target < 0) {
|
||||||
|
print("cwdtest: FAIL spawn cwdtarget\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long status = userWait(target);
|
||||||
|
print("cwdtest: cwdtarget exit status=");
|
||||||
|
printDec(status);
|
||||||
|
print("\n");
|
||||||
|
if (status != 0) {
|
||||||
|
print("cwdtest: FAIL cwdtarget did not exit cleanly\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cwdtarget's own chdir("/tmp/cwdb") must never have reached back into
|
||||||
|
THIS process's Thread.cwd -- each is an independent buffer, not a
|
||||||
|
pointer to shared state (unlike shell.c's OLD single static global
|
||||||
|
this subsystem replaces). */
|
||||||
|
len = userGetcwd(cwdBuf, sizeof(cwdBuf));
|
||||||
|
if (len < 0 || !streq(cwdBuf, "/tmp/cwda")) {
|
||||||
|
print("cwdtest: FAIL own cwd changed after child exited, got: ");
|
||||||
|
print(len < 0 ? "(error)" : cwdBuf);
|
||||||
|
print("\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("cwdtest: parent-cwd-unaffected-ok\n");
|
||||||
|
|
||||||
|
/* Re-read using an absolute path this time -- still resolves to the
|
||||||
|
exact same file the earlier relative open created, and must still
|
||||||
|
hold the ORIGINAL payload, untouched by anything cwdtarget did in
|
||||||
|
its own, completely separate directory. */
|
||||||
|
char readBuf[32];
|
||||||
|
fd = (int)userOpen("/tmp/cwda/note", oReadOnly);
|
||||||
|
if (fd < 0) {
|
||||||
|
print("cwdtest: FAIL reopen /tmp/cwda/note\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
long got = userRead(fd, readBuf, sizeof(readBuf) - 1);
|
||||||
|
userClose(fd);
|
||||||
|
if (got < 0) {
|
||||||
|
print("cwdtest: FAIL read /tmp/cwda/note\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
readBuf[got] = 0;
|
||||||
|
if (!streq(readBuf, cwdaPayload)) {
|
||||||
|
print("cwdtest: FAIL /tmp/cwda/note payload mismatch, got: ");
|
||||||
|
print(readBuf);
|
||||||
|
print("\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = (int)userOpen("/tmp/cwdb/note", oReadOnly);
|
||||||
|
if (fd < 0) {
|
||||||
|
print("cwdtest: FAIL reopen /tmp/cwdb/note\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
got = userRead(fd, readBuf, sizeof(readBuf) - 1);
|
||||||
|
userClose(fd);
|
||||||
|
if (got < 0) {
|
||||||
|
print("cwdtest: FAIL read /tmp/cwdb/note\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
readBuf[got] = 0;
|
||||||
|
if (!streq(readBuf, "cwdb-payload")) {
|
||||||
|
print("cwdtest: FAIL /tmp/cwdb/note payload mismatch, got: ");
|
||||||
|
print(readBuf);
|
||||||
|
print("\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("cwdtest: isolation-verified-ok\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user