Loading src/journal.cpp +8 −1 Changes for src/journal.cpp: 8 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ namespace syslite { namespace { bool consoleEcho = true; class TeeBuf : public std::streambuf { public: explicit TeeBuf(int console) : _console(console) {} Loading @@ -116,7 +118,7 @@ namespace syslite { private: void emit() { std::string out = _line + "\n"; if (_console >= 0) (void)!::write(_console, out.data(), out.size()); if (_console >= 0 && consoleEcho) (void)!::write(_console, out.data(), out.size()); // "[syslite] Starting x" -> "Starting x": the tag says syslite std::string l = _line; if (l.rfind("[syslite] ", 0) == 0) l = l.substr(10); Loading @@ -130,6 +132,11 @@ namespace syslite { } // namespace void setConsoleEcho(bool on) { std::cout.flush(); consoleEcho = on; } void captureStandardStreams() { // one buffer for both: interleaved lines stay whole static TeeBuf buf([] { Loading src/journal.h +7 −2 Changes for src/journal.h: 7 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -37,10 +37,15 @@ namespace syslite { long long _nextTryMs = 0; }; // std::cout and std::cerr: each line to the console (as before) and // into the journal as "syslite" // std::cout and std::cerr: each line into the journal as "syslite", // and to the console while that is on void captureStandardStreams(); // syslite's lines on the console too: on while booting, off once the // TTYs run (the installer's screen, login prompts) -- then only the // journal has them void setConsoleEcho(bool on); // "2026-10-04T08:12:33.123+0200" std::string journalTimestamp(); Loading src/service.cpp +151 −33 Changes for src/service.cpp: 151 added lines, 33 removed lines. Original line number Diff line number Diff line Loading @@ -544,6 +544,10 @@ namespace syslite { void ServiceManager::handleChild(pid_t pid, int status) { for (auto &[name, entry] : _services) { if (entry.pid == pid && entry.unit.kind == UnitKind::Mount) { finishMountHelper(entry, status); return; } if (entry.pid == pid) { entry.exitCode = WIFEXITED(status) ? WEXITSTATUS(status) : -1; entry.pid = -1; Loading Loading @@ -652,26 +656,116 @@ namespace syslite { // ---- mounts ---- bool ServiceManager::tryMount(ServiceEntry &entry) { bool ServiceManager::spawnMountHelper(ServiceEntry &entry, bool unmount) { if (entry.outFd >= 0) drainOutput(entry); if (entry.outFd >= 0) { close(entry.outFd); entry.outFd = -1; } int out[2]; if (pipe2(out, O_CLOEXEC) != 0) { entry.lastError = std::string("pipe: ") + strerror(errno); return false; } fcntl(out[0], F_SETFL, O_NONBLOCK); pid_t pid = fork(); if (pid < 0) { entry.lastError = std::string("fork: ") + strerror(errno); close(out[0]); close(out[1]); return false; } if (pid == 0) { // only write(2) here: syslite's own streams go to the console dup2(out[1], STDOUT_FILENO); dup2(out[1], STDERR_FILENO); const UnitFile &u = entry.unit; std::string type = u.mountType; std::string probed; auto say = [](const std::string &l) { std::string line = l + "\n"; (void)!::write(STDOUT_FILENO, line.data(), line.size()); }; std::string err; if (unmount) { if (!unmountFilesystem(u.mountWhere, false, &err)) { say(err); _exit(1); } say("Unmounted " + u.mountWhere); _exit(0); } std::string probed, type = u.mountType; std::string dev = resolveMountSource(u.mountWhat, &probed); if (dev.empty()) return false; // not there (yet) if (dev.empty()) _exit(3); // not there (yet) if (type.empty()) type = probed; std::string err; entry.mountRetryMs = entry.mountDeadlineMs = 0; if (!mountFilesystem(dev, u.mountWhere, type, u.mountOptions, &err)) { entry.lastError = err; entry.state = ServiceState::Failed; std::cerr << "[syslite] " << u.name << ": " << err << std::endl; if (!mountFilesystem(dev, u.mountWhere, type, u.mountOptions, &err)) { say(err); _exit(1); } say("Mounted " + dev + " on " + u.mountWhere); _exit(0); } close(out[1]); entry.outFd = out[0]; entry.pid = entry.outPid = pid; entry.helperUnmounts = unmount; return true; } entry.mountSource = dev; bool ServiceManager::waitMountHelper(ServiceEntry &entry, int ms) { for (int waited = 0; entry.pid > 0; waited += 10) { drainOutput(entry); int status; pid_t r = waitpid(entry.pid, &status, WNOHANG); if (r == entry.pid) { finishMountHelper(entry, status); return true; } if (r < 0 && errno != EINTR) { entry.pid = -1; return true; } if (waited >= ms) return false; usleep(10000); } return true; } void ServiceManager::finishMountHelper(ServiceEntry &entry, int status) { drainOutput(entry); entry.pid = -1; const UnitFile &u = entry.unit; int code = WIFEXITED(status) ? WEXITSTATUS(status) : -1; long long now = monotonicMs(); if (entry.helperUnmounts) { entry.helperUnmounts = false; if (code == 0) { entry.state = ServiceState::Stopped; entry.lastError.clear(); std::cout << "[syslite] Unmounted " << u.mountWhere << std::endl; } else { entry.lastError = entry.outLast.empty() ? "umount " + u.mountWhere + " failed" : entry.outLast; entry.state = isMountPoint(u.mountWhere) ? ServiceState::Running : ServiceState::Stopped; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } return; } if (code == 0) { entry.state = ServiceState::Running; std::cout << "[syslite] Mounted " << dev << " on " << u.mountWhere << std::endl; return true; entry.lastError.clear(); entry.mountRetryMs = entry.mountDeadlineMs = 0; // "Mounted /dev/x on /where" if (entry.outLast.rfind("Mounted ", 0) == 0) entry.mountSource = entry.outLast.substr(8, entry.outLast.find(" on ") - 8); std::cout << "[syslite] " << entry.outLast << std::endl; } else if (code == 3 && entry.state == ServiceState::Starting) { // the device isn't there yet (an md array or LVM volume set up // later, a slow USB disk): checkMounts() tries again if (now >= entry.mountDeadlineMs) { entry.mountRetryMs = entry.mountDeadlineMs = 0; entry.state = ServiceState::Failed; entry.lastError = u.mountWhat + " didn't show up"; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } else { if (entry.lastError.rfind("waiting for ", 0) != 0) std::cout << "[syslite] " << u.name << ": waiting for " << u.mountWhat << std::endl; entry.lastError = "waiting for " + u.mountWhat; entry.mountRetryMs = now + 1000; } } else if (code != 3) { entry.mountRetryMs = entry.mountDeadlineMs = 0; entry.state = ServiceState::Failed; entry.lastError = WIFSIGNALED(status) ? "mount helper killed (signal " + std::to_string(WTERMSIG(status)) + ")" : entry.outLast.empty() ? "mount failed" : entry.outLast; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } } bool ServiceManager::startMount(ServiceEntry &entry) { Loading @@ -689,52 +783,75 @@ namespace syslite { entry.state = ServiceState::Running; return true; } if (tryMount(entry)) return entry.state == ServiceState::Running; // the device isn't there yet (an md array or LVM volume set up // later, a slow USB disk): checkMounts() tries again if (entry.pid > 0) return true; // a helper is at it already long long now = monotonicMs(); entry.state = ServiceState::Starting; entry.lastError = "waiting for " + u.mountWhat; entry.mountRetryMs = now + 1000; entry.lastError.clear(); entry.mountRetryMs = 0; entry.mountDeadlineMs = now + 1000LL * (u.mountTimeoutSec > 0 ? u.mountTimeoutSec : 90); std::cout << "[syslite] " << u.name << ": waiting for " << u.mountWhat << std::endl; return true; if (!spawnMountHelper(entry, false)) { entry.state = ServiceState::Failed; return false; } // usually done at once; a helper still at it after 10 s (a disk // that doesn't answer) finishes later, through handleChild() if (!waitMountHelper(entry, 10000)) { entry.lastError = "still mounting (the device is slow or doesn't answer)"; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } return entry.state != ServiceState::Failed; } bool ServiceManager::stopMount(ServiceEntry &entry, bool lazy) { entry.mountRetryMs = entry.mountDeadlineMs = 0; const std::string &where = entry.unit.mountWhere; if (!isMountPoint(where)) { entry.state = ServiceState::Stopped; if (entry.pid <= 0) entry.state = ServiceState::Stopped; return true; } std::string err; sync(); if (!unmountFilesystem(where, lazy, &err)) { if (lazy) { // the shutdown: detaching doesn't wait for anything if (!unmountFilesystem(where, true, &err)) { entry.lastError = err; std::cerr << "[syslite] " << entry.unit.name << ": " << err << std::endl; return false; } entry.lastError.clear(); entry.state = ServiceState::Stopped; std::cout << "[syslite] Unmounted " << where << std::endl; return true; } if (entry.pid > 0) { entry.lastError = entry.helperUnmounts ? "still unmounting" : "still mounting"; return false; } entry.state = ServiceState::Stopping; if (!spawnMountHelper(entry, true)) { entry.state = ServiceState::Running; return false; } if (!waitMountHelper(entry, 10000)) { entry.lastError = "still unmounting (the device is slow or doesn't answer)"; std::cerr << "[syslite] " << entry.unit.name << ": " << entry.lastError << std::endl; return false; } return entry.state == ServiceState::Stopped; } void ServiceManager::checkMounts() { long long now = monotonicMs(); for (auto &[name, entry] : _services) { if (entry.unit.kind != UnitKind::Mount) continue; if (entry.state == ServiceState::Starting && entry.mountRetryMs && now >= entry.mountRetryMs) { if (tryMount(entry)) continue; if (now >= entry.mountDeadlineMs) { entry.mountRetryMs = entry.mountDeadlineMs = 0; if (entry.state != ServiceState::Starting) continue; if (entry.pid > 0) { // a helper that hangs past the deadline: the device doesn't answer if (entry.mountDeadlineMs && now >= entry.mountDeadlineMs) { entry.mountDeadlineMs = entry.mountRetryMs = 0; entry.state = ServiceState::Failed; entry.lastError = entry.unit.mountWhat + " didn't show up"; entry.lastError = entry.unit.mountWhat + " doesn't answer (mounting hangs)"; std::cerr << "[syslite] " << name << ": " << entry.lastError << std::endl; } else { entry.mountRetryMs = now + 1000; } } else if (entry.mountRetryMs && now >= entry.mountRetryMs) { entry.mountRetryMs = 0; spawnMountHelper(entry, false); // handleChild() takes its end } } // unmounted (or mounted) behind syslite's back: once a second Loading Loading @@ -770,6 +887,7 @@ namespace syslite { if (buf[i] == '\n' || entry.outLine.size() >= 8192) { if (!entry.outLine.empty() && entry.outLine.back() == '\r') entry.outLine.pop_back(); Journal::instance().write(entry.unit.name, entry.outPid, entry.outLine); entry.outLast = entry.outLine; entry.outLine.clear(); if (buf[i] == '\n') continue; } Loading src/service.h +7 −1 Changes for src/service.h: 7 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ namespace syslite { int outFd = -1; // read end of its pipe pid_t outPid = -1; // whose lines they are std::string outLine; // an unfinished line std::string outLast; // the last whole line bool helperUnmounts = false; // a mount's helper (pid) unmounts }; Loading Loading @@ -94,9 +96,13 @@ namespace syslite { // waitpid() for a child that writes into entry's pipe meanwhile void waitDraining(ServiceEntry &entry, pid_t pid, int *status); bool startMount(ServiceEntry &entry); bool tryMount(ServiceEntry &entry); bool stopMount(ServiceEntry &entry, bool lazy); void checkMounts(); // mounting and unmounting run in a helper process (a dying disk // stalls that, not PID 1); waiting for it at most ms bool spawnMountHelper(ServiceEntry &entry, bool unmount); bool waitMountHelper(ServiceEntry &entry, int ms); void finishMountHelper(ServiceEntry &entry, int status); void setupChildProcess(const ServiceEntry &entry); void createRuntimeDirectory(const ServiceEntry &entry); std::vector<std::string> buildArgv(const std::string &cmdline); Loading src/syslite.cpp +14 −3 Changes for src/syslite.cpp: 14 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -34,7 +34,8 @@ namespace syslite { // Configuration is compile-time (config.h). Hostname from /etc/hostname. // Register TTYs based on compiled-in count. // On a live ISO (squashfs boot), run the installer on tty1. bool liveMode = std::filesystem::exists("/usr/sbin/fenriros-install") bool &liveMode = _liveMode; liveMode = std::filesystem::exists("/usr/sbin/fenriros-install") && !std::filesystem::exists("/etc/fstab") && !std::filesystem::exists("/etc/fstab.yaml"); // systempp's fstab for (int i = 1; i <= _numTtys; ++i) { Loading Loading @@ -518,8 +519,17 @@ namespace syslite { std::cout << "[syslite] Starting target: " << _defaultTarget << std::endl; _services.startTarget(_defaultTarget); // Spawn TTYs // Spawn TTYs. From now on the console is theirs (the installer's // screen on a live system, login prompts): syslite's messages go // only into the journal, and while the installer runs the kernel // shows only emergencies there if (isPid1) { std::cout << "[syslite] Boot finished; messages from now on: journalctl" << std::endl; setConsoleEcho(false); if (_liveMode) { std::ofstream printk("/proc/sys/kernel/printk"); printk << "1"; } _ttys.startAll(); } Loading Loading @@ -564,7 +574,8 @@ namespace syslite { } _bus.close(); // Shutdown sequence // Shutdown sequence: on the console again (the TTYs go away) if (isPid1) setConsoleEcho(true); std::cout << std::endl; std::cout << "[syslite] Shutting down..." << std::endl; Loading Loading
src/journal.cpp +8 −1 Changes for src/journal.cpp: 8 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ namespace syslite { namespace { bool consoleEcho = true; class TeeBuf : public std::streambuf { public: explicit TeeBuf(int console) : _console(console) {} Loading @@ -116,7 +118,7 @@ namespace syslite { private: void emit() { std::string out = _line + "\n"; if (_console >= 0) (void)!::write(_console, out.data(), out.size()); if (_console >= 0 && consoleEcho) (void)!::write(_console, out.data(), out.size()); // "[syslite] Starting x" -> "Starting x": the tag says syslite std::string l = _line; if (l.rfind("[syslite] ", 0) == 0) l = l.substr(10); Loading @@ -130,6 +132,11 @@ namespace syslite { } // namespace void setConsoleEcho(bool on) { std::cout.flush(); consoleEcho = on; } void captureStandardStreams() { // one buffer for both: interleaved lines stay whole static TeeBuf buf([] { Loading
src/journal.h +7 −2 Changes for src/journal.h: 7 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -37,10 +37,15 @@ namespace syslite { long long _nextTryMs = 0; }; // std::cout and std::cerr: each line to the console (as before) and // into the journal as "syslite" // std::cout and std::cerr: each line into the journal as "syslite", // and to the console while that is on void captureStandardStreams(); // syslite's lines on the console too: on while booting, off once the // TTYs run (the installer's screen, login prompts) -- then only the // journal has them void setConsoleEcho(bool on); // "2026-10-04T08:12:33.123+0200" std::string journalTimestamp(); Loading
src/service.cpp +151 −33 Changes for src/service.cpp: 151 added lines, 33 removed lines. Original line number Diff line number Diff line Loading @@ -544,6 +544,10 @@ namespace syslite { void ServiceManager::handleChild(pid_t pid, int status) { for (auto &[name, entry] : _services) { if (entry.pid == pid && entry.unit.kind == UnitKind::Mount) { finishMountHelper(entry, status); return; } if (entry.pid == pid) { entry.exitCode = WIFEXITED(status) ? WEXITSTATUS(status) : -1; entry.pid = -1; Loading Loading @@ -652,26 +656,116 @@ namespace syslite { // ---- mounts ---- bool ServiceManager::tryMount(ServiceEntry &entry) { bool ServiceManager::spawnMountHelper(ServiceEntry &entry, bool unmount) { if (entry.outFd >= 0) drainOutput(entry); if (entry.outFd >= 0) { close(entry.outFd); entry.outFd = -1; } int out[2]; if (pipe2(out, O_CLOEXEC) != 0) { entry.lastError = std::string("pipe: ") + strerror(errno); return false; } fcntl(out[0], F_SETFL, O_NONBLOCK); pid_t pid = fork(); if (pid < 0) { entry.lastError = std::string("fork: ") + strerror(errno); close(out[0]); close(out[1]); return false; } if (pid == 0) { // only write(2) here: syslite's own streams go to the console dup2(out[1], STDOUT_FILENO); dup2(out[1], STDERR_FILENO); const UnitFile &u = entry.unit; std::string type = u.mountType; std::string probed; auto say = [](const std::string &l) { std::string line = l + "\n"; (void)!::write(STDOUT_FILENO, line.data(), line.size()); }; std::string err; if (unmount) { if (!unmountFilesystem(u.mountWhere, false, &err)) { say(err); _exit(1); } say("Unmounted " + u.mountWhere); _exit(0); } std::string probed, type = u.mountType; std::string dev = resolveMountSource(u.mountWhat, &probed); if (dev.empty()) return false; // not there (yet) if (dev.empty()) _exit(3); // not there (yet) if (type.empty()) type = probed; std::string err; entry.mountRetryMs = entry.mountDeadlineMs = 0; if (!mountFilesystem(dev, u.mountWhere, type, u.mountOptions, &err)) { entry.lastError = err; entry.state = ServiceState::Failed; std::cerr << "[syslite] " << u.name << ": " << err << std::endl; if (!mountFilesystem(dev, u.mountWhere, type, u.mountOptions, &err)) { say(err); _exit(1); } say("Mounted " + dev + " on " + u.mountWhere); _exit(0); } close(out[1]); entry.outFd = out[0]; entry.pid = entry.outPid = pid; entry.helperUnmounts = unmount; return true; } entry.mountSource = dev; bool ServiceManager::waitMountHelper(ServiceEntry &entry, int ms) { for (int waited = 0; entry.pid > 0; waited += 10) { drainOutput(entry); int status; pid_t r = waitpid(entry.pid, &status, WNOHANG); if (r == entry.pid) { finishMountHelper(entry, status); return true; } if (r < 0 && errno != EINTR) { entry.pid = -1; return true; } if (waited >= ms) return false; usleep(10000); } return true; } void ServiceManager::finishMountHelper(ServiceEntry &entry, int status) { drainOutput(entry); entry.pid = -1; const UnitFile &u = entry.unit; int code = WIFEXITED(status) ? WEXITSTATUS(status) : -1; long long now = monotonicMs(); if (entry.helperUnmounts) { entry.helperUnmounts = false; if (code == 0) { entry.state = ServiceState::Stopped; entry.lastError.clear(); std::cout << "[syslite] Unmounted " << u.mountWhere << std::endl; } else { entry.lastError = entry.outLast.empty() ? "umount " + u.mountWhere + " failed" : entry.outLast; entry.state = isMountPoint(u.mountWhere) ? ServiceState::Running : ServiceState::Stopped; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } return; } if (code == 0) { entry.state = ServiceState::Running; std::cout << "[syslite] Mounted " << dev << " on " << u.mountWhere << std::endl; return true; entry.lastError.clear(); entry.mountRetryMs = entry.mountDeadlineMs = 0; // "Mounted /dev/x on /where" if (entry.outLast.rfind("Mounted ", 0) == 0) entry.mountSource = entry.outLast.substr(8, entry.outLast.find(" on ") - 8); std::cout << "[syslite] " << entry.outLast << std::endl; } else if (code == 3 && entry.state == ServiceState::Starting) { // the device isn't there yet (an md array or LVM volume set up // later, a slow USB disk): checkMounts() tries again if (now >= entry.mountDeadlineMs) { entry.mountRetryMs = entry.mountDeadlineMs = 0; entry.state = ServiceState::Failed; entry.lastError = u.mountWhat + " didn't show up"; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } else { if (entry.lastError.rfind("waiting for ", 0) != 0) std::cout << "[syslite] " << u.name << ": waiting for " << u.mountWhat << std::endl; entry.lastError = "waiting for " + u.mountWhat; entry.mountRetryMs = now + 1000; } } else if (code != 3) { entry.mountRetryMs = entry.mountDeadlineMs = 0; entry.state = ServiceState::Failed; entry.lastError = WIFSIGNALED(status) ? "mount helper killed (signal " + std::to_string(WTERMSIG(status)) + ")" : entry.outLast.empty() ? "mount failed" : entry.outLast; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } } bool ServiceManager::startMount(ServiceEntry &entry) { Loading @@ -689,52 +783,75 @@ namespace syslite { entry.state = ServiceState::Running; return true; } if (tryMount(entry)) return entry.state == ServiceState::Running; // the device isn't there yet (an md array or LVM volume set up // later, a slow USB disk): checkMounts() tries again if (entry.pid > 0) return true; // a helper is at it already long long now = monotonicMs(); entry.state = ServiceState::Starting; entry.lastError = "waiting for " + u.mountWhat; entry.mountRetryMs = now + 1000; entry.lastError.clear(); entry.mountRetryMs = 0; entry.mountDeadlineMs = now + 1000LL * (u.mountTimeoutSec > 0 ? u.mountTimeoutSec : 90); std::cout << "[syslite] " << u.name << ": waiting for " << u.mountWhat << std::endl; return true; if (!spawnMountHelper(entry, false)) { entry.state = ServiceState::Failed; return false; } // usually done at once; a helper still at it after 10 s (a disk // that doesn't answer) finishes later, through handleChild() if (!waitMountHelper(entry, 10000)) { entry.lastError = "still mounting (the device is slow or doesn't answer)"; std::cerr << "[syslite] " << u.name << ": " << entry.lastError << std::endl; } return entry.state != ServiceState::Failed; } bool ServiceManager::stopMount(ServiceEntry &entry, bool lazy) { entry.mountRetryMs = entry.mountDeadlineMs = 0; const std::string &where = entry.unit.mountWhere; if (!isMountPoint(where)) { entry.state = ServiceState::Stopped; if (entry.pid <= 0) entry.state = ServiceState::Stopped; return true; } std::string err; sync(); if (!unmountFilesystem(where, lazy, &err)) { if (lazy) { // the shutdown: detaching doesn't wait for anything if (!unmountFilesystem(where, true, &err)) { entry.lastError = err; std::cerr << "[syslite] " << entry.unit.name << ": " << err << std::endl; return false; } entry.lastError.clear(); entry.state = ServiceState::Stopped; std::cout << "[syslite] Unmounted " << where << std::endl; return true; } if (entry.pid > 0) { entry.lastError = entry.helperUnmounts ? "still unmounting" : "still mounting"; return false; } entry.state = ServiceState::Stopping; if (!spawnMountHelper(entry, true)) { entry.state = ServiceState::Running; return false; } if (!waitMountHelper(entry, 10000)) { entry.lastError = "still unmounting (the device is slow or doesn't answer)"; std::cerr << "[syslite] " << entry.unit.name << ": " << entry.lastError << std::endl; return false; } return entry.state == ServiceState::Stopped; } void ServiceManager::checkMounts() { long long now = monotonicMs(); for (auto &[name, entry] : _services) { if (entry.unit.kind != UnitKind::Mount) continue; if (entry.state == ServiceState::Starting && entry.mountRetryMs && now >= entry.mountRetryMs) { if (tryMount(entry)) continue; if (now >= entry.mountDeadlineMs) { entry.mountRetryMs = entry.mountDeadlineMs = 0; if (entry.state != ServiceState::Starting) continue; if (entry.pid > 0) { // a helper that hangs past the deadline: the device doesn't answer if (entry.mountDeadlineMs && now >= entry.mountDeadlineMs) { entry.mountDeadlineMs = entry.mountRetryMs = 0; entry.state = ServiceState::Failed; entry.lastError = entry.unit.mountWhat + " didn't show up"; entry.lastError = entry.unit.mountWhat + " doesn't answer (mounting hangs)"; std::cerr << "[syslite] " << name << ": " << entry.lastError << std::endl; } else { entry.mountRetryMs = now + 1000; } } else if (entry.mountRetryMs && now >= entry.mountRetryMs) { entry.mountRetryMs = 0; spawnMountHelper(entry, false); // handleChild() takes its end } } // unmounted (or mounted) behind syslite's back: once a second Loading Loading @@ -770,6 +887,7 @@ namespace syslite { if (buf[i] == '\n' || entry.outLine.size() >= 8192) { if (!entry.outLine.empty() && entry.outLine.back() == '\r') entry.outLine.pop_back(); Journal::instance().write(entry.unit.name, entry.outPid, entry.outLine); entry.outLast = entry.outLine; entry.outLine.clear(); if (buf[i] == '\n') continue; } Loading
src/service.h +7 −1 Changes for src/service.h: 7 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ namespace syslite { int outFd = -1; // read end of its pipe pid_t outPid = -1; // whose lines they are std::string outLine; // an unfinished line std::string outLast; // the last whole line bool helperUnmounts = false; // a mount's helper (pid) unmounts }; Loading Loading @@ -94,9 +96,13 @@ namespace syslite { // waitpid() for a child that writes into entry's pipe meanwhile void waitDraining(ServiceEntry &entry, pid_t pid, int *status); bool startMount(ServiceEntry &entry); bool tryMount(ServiceEntry &entry); bool stopMount(ServiceEntry &entry, bool lazy); void checkMounts(); // mounting and unmounting run in a helper process (a dying disk // stalls that, not PID 1); waiting for it at most ms bool spawnMountHelper(ServiceEntry &entry, bool unmount); bool waitMountHelper(ServiceEntry &entry, int ms); void finishMountHelper(ServiceEntry &entry, int status); void setupChildProcess(const ServiceEntry &entry); void createRuntimeDirectory(const ServiceEntry &entry); std::vector<std::string> buildArgv(const std::string &cmdline); Loading
src/syslite.cpp +14 −3 Changes for src/syslite.cpp: 14 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -34,7 +34,8 @@ namespace syslite { // Configuration is compile-time (config.h). Hostname from /etc/hostname. // Register TTYs based on compiled-in count. // On a live ISO (squashfs boot), run the installer on tty1. bool liveMode = std::filesystem::exists("/usr/sbin/fenriros-install") bool &liveMode = _liveMode; liveMode = std::filesystem::exists("/usr/sbin/fenriros-install") && !std::filesystem::exists("/etc/fstab") && !std::filesystem::exists("/etc/fstab.yaml"); // systempp's fstab for (int i = 1; i <= _numTtys; ++i) { Loading Loading @@ -518,8 +519,17 @@ namespace syslite { std::cout << "[syslite] Starting target: " << _defaultTarget << std::endl; _services.startTarget(_defaultTarget); // Spawn TTYs // Spawn TTYs. From now on the console is theirs (the installer's // screen on a live system, login prompts): syslite's messages go // only into the journal, and while the installer runs the kernel // shows only emergencies there if (isPid1) { std::cout << "[syslite] Boot finished; messages from now on: journalctl" << std::endl; setConsoleEcho(false); if (_liveMode) { std::ofstream printk("/proc/sys/kernel/printk"); printk << "1"; } _ttys.startAll(); } Loading Loading @@ -564,7 +574,8 @@ namespace syslite { } _bus.close(); // Shutdown sequence // Shutdown sequence: on the console again (the TTYs go away) if (isPid1) setConsoleEcho(true); std::cout << std::endl; std::cout << "[syslite] Shutting down..." << std::endl; Loading