Write a timestamped transcript per run
A run whose result nobody recorded is a run that has to be repeated on a human's finger, and this daemon printed to stdout and nowhere else. Two real authentication runs -- an enrolled finger and a wrong-finger control -- were performed and their output is simply gone. A single shared log path would be worse than none: the next run, including a quick control, overwrites the interesting one. That very nearly cost this project the transcript of its first successful authentication, which is why the harness moved to per-run files. Teeing is done at the file-descriptor level rather than by wrapping a stream. std::println writes to stdout through C stdio, so an ostream wrapper captures nothing; routing fd 1 through tee catches every line, including whatever the library prints.
This commit is contained in:
parent
c33076ca9b
commit
a8c989857a
1 changed files with 29 additions and 1 deletions
|
|
@ -56,6 +56,7 @@ bool g_listeners = false;
|
||||||
bool g_auth = false;
|
bool g_auth = false;
|
||||||
int g_frames = 40;
|
int g_frames = 40;
|
||||||
int g_frameGapMs = 500;
|
int g_frameGapMs = 500;
|
||||||
|
std::string g_logDir = "/var/log/fingerprintd";
|
||||||
std::uint32_t g_gid = 0;
|
std::uint32_t g_gid = 0;
|
||||||
std::string g_taPath = "/lib/firmware/focal64.mbn";
|
std::string g_taPath = "/lib/firmware/focal64.mbn";
|
||||||
std::string g_cfgPath = "/lib/firmware/fingerprintd.json";
|
std::string g_cfgPath = "/lib/firmware/fingerprintd.json";
|
||||||
|
|
@ -66,6 +67,30 @@ qcomtee_object* g_root = QCOMTEE_OBJECT_NULL;
|
||||||
// around it so the supplicant thread can be stopped while blocked in the
|
// around it so the supplicant thread can be stopped while blocked in the
|
||||||
// kernel waiting for QTEE.
|
// kernel waiting for QTEE.
|
||||||
//
|
//
|
||||||
|
// Every run writes its own timestamped transcript. Not a convenience: a run
|
||||||
|
// whose result nobody recorded is a run that has to be repeated on a human's
|
||||||
|
// finger. And a SINGLE shared log path is worse than none -- the next run,
|
||||||
|
// including a quick control, destroys the interesting one, which is how the
|
||||||
|
// first successful authentication in this project was very nearly lost.
|
||||||
|
//
|
||||||
|
// Done at the file-descriptor level rather than by wrapping a stream, because
|
||||||
|
// std::println writes to stdout through C stdio: an ostream wrapper would
|
||||||
|
// capture nothing. Routing fd 1 through tee catches every line including the
|
||||||
|
// ones libqcomtee prints.
|
||||||
|
bool StartTranscript(const std::string& dir) {
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::create_directories(dir, ec);
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::string path = std::format("{}/{:%Y%m%d-%H%M%S}.log", dir,
|
||||||
|
std::chrono::floor<std::chrono::seconds>(now));
|
||||||
|
FILE* t = ::popen(std::format("tee {}", path).c_str(), "w");
|
||||||
|
if (!t) return false;
|
||||||
|
::dup2(::fileno(t), 1);
|
||||||
|
::setvbuf(stdout, nullptr, _IOLBF, 0);
|
||||||
|
std::println("transcript: {}", path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// tee_call_t's second parameter is `unsigned long` on glibc and `int` on musl
|
// tee_call_t's second parameter is `unsigned long` on glibc and `int` on musl
|
||||||
// (qcomtee_object.h keys it off __GLIBC__), so the signature has to match or
|
// (qcomtee_object.h keys it off __GLIBC__), so the signature has to match or
|
||||||
// the function pointer will not convert. The native build is glibc and the
|
// the function pointer will not convert. The native build is glibc and the
|
||||||
|
|
@ -1136,12 +1161,15 @@ int main(int argc, char** argv) {
|
||||||
if (a == "--rpmb-write") g_rpmbWrite = true;
|
if (a == "--rpmb-write") g_rpmbWrite = true;
|
||||||
if (a == "--auth") { g_auth = true; g_listeners = true; }
|
if (a == "--auth") { g_auth = true; g_listeners = true; }
|
||||||
if (a.starts_with("--frames=")) g_frames = std::stoi(std::string(a.substr(9)));
|
if (a.starts_with("--frames=")) g_frames = std::stoi(std::string(a.substr(9)));
|
||||||
|
if (a.starts_with("--log-dir=")) g_logDir = a.substr(10);
|
||||||
if (a.starts_with("--sfs-root=")) g_sfsRoot = a.substr(11);
|
if (a.starts_with("--sfs-root=")) g_sfsRoot = a.substr(11);
|
||||||
if (a.starts_with("--gid=")) g_gid = static_cast<std::uint32_t>(
|
if (a.starts_with("--gid=")) g_gid = static_cast<std::uint32_t>(
|
||||||
std::stoul(std::string(a.substr(6))));
|
std::stoul(std::string(a.substr(6))));
|
||||||
}
|
}
|
||||||
if (probe)
|
if (probe) {
|
||||||
|
StartTranscript(g_logDir);
|
||||||
return Probe();
|
return Probe();
|
||||||
|
}
|
||||||
|
|
||||||
std::println(std::cerr,
|
std::println(std::cerr,
|
||||||
"fingerprintd {}: no runtime yet. --probe-tee reaches QTEE; "
|
"fingerprintd {}: no runtime yet. --probe-tee reaches QTEE; "
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue