Skip to content

Commit a5ffcc4

Browse files
committed
fix(doctor): avoid false production service matches
2 parents 71372e6 + f0d2079 commit a5ffcc4

1 file changed

Lines changed: 109 additions & 11 deletions

File tree

src/commands/DoctorCommand.cpp

Lines changed: 109 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -617,20 +617,41 @@ namespace vix::commands
617617
return std::system(cmd.c_str()) == 0;
618618
}
619619

620-
std::optional<std::string> detect_systemd_service(const std::string &projectName)
620+
std::vector<std::string> list_systemd_services()
621621
{
622-
const std::string lower = lower_copy(projectName);
622+
std::vector<std::string> services;
623623

624624
auto out = run_capture(
625-
"systemctl list-units --type=service --all --no-legend 2>/dev/null | "
626-
"awk '{print $1}' | grep -i " +
627-
shell_quote(lower) +
628-
" | head -1");
625+
"systemctl list-unit-files --type=service --no-legend 2>/dev/null | "
626+
"awk '{print $1}'");
627+
628+
if (!out)
629+
return services;
630+
631+
std::string current;
632+
633+
for (char c : *out)
634+
{
635+
if (c == '\n' || c == '\r')
636+
{
637+
current = trim_copy(current);
638+
639+
if (!current.empty())
640+
services.push_back(current);
641+
642+
current.clear();
643+
continue;
644+
}
645+
646+
current.push_back(c);
647+
}
629648

630-
if (out && !trim_copy(*out).empty())
631-
return trim_copy(*out);
649+
current = trim_copy(current);
632650

633-
return lower + ".service";
651+
if (!current.empty())
652+
services.push_back(current);
653+
654+
return services;
634655
}
635656

636657
std::optional<std::string> systemctl_property(
@@ -655,6 +676,54 @@ namespace vix::commands
655676
return value;
656677
}
657678

679+
bool service_points_to_project(
680+
const std::string &service,
681+
const fs::path &projectDir,
682+
const std::optional<fs::path> &binary)
683+
{
684+
const auto workingDir = systemctl_property(service, "WorkingDirectory");
685+
const auto execStart = systemctl_property(service, "ExecStart");
686+
687+
std::error_code ec;
688+
const fs::path canonicalProject =
689+
fs::weakly_canonical(projectDir, ec);
690+
691+
if (workingDir && !workingDir->empty())
692+
{
693+
std::error_code wdEc;
694+
const fs::path canonicalWorkingDir =
695+
fs::weakly_canonical(fs::path(*workingDir), wdEc);
696+
697+
if (!wdEc && !ec && canonicalWorkingDir == canonicalProject)
698+
return true;
699+
700+
if (trim_copy(*workingDir) == projectDir.string())
701+
return true;
702+
}
703+
704+
if (binary && execStart && !execStart->empty())
705+
{
706+
const std::string exec = *execStart;
707+
const std::string bin = binary->string();
708+
709+
if (!bin.empty() && exec.find(bin) != std::string::npos)
710+
return true;
711+
712+
if (binary->has_filename())
713+
{
714+
const std::string filename = binary->filename().string();
715+
716+
if (!filename.empty() && exec.find(filename) != std::string::npos)
717+
{
718+
if (workingDir && trim_copy(*workingDir) == projectDir.string())
719+
return true;
720+
}
721+
}
722+
}
723+
724+
return false;
725+
}
726+
658727
bool systemd_service_exists(const std::string &service)
659728
{
660729
const std::string cmd =
@@ -663,6 +732,31 @@ namespace vix::commands
663732
return std::system(cmd.c_str()) == 0;
664733
}
665734

735+
std::optional<std::string> detect_systemd_service(
736+
const std::string &projectName,
737+
const fs::path &projectDir,
738+
const std::optional<fs::path> &binary)
739+
{
740+
const std::string lower = lower_copy(projectName);
741+
const std::string exactService = lower + ".service";
742+
743+
if (systemd_service_exists(exactService) &&
744+
service_points_to_project(exactService, projectDir, binary))
745+
{
746+
return exactService;
747+
}
748+
749+
const auto services = list_systemd_services();
750+
751+
for (const auto &service : services)
752+
{
753+
if (service_points_to_project(service, projectDir, binary))
754+
return service;
755+
}
756+
757+
return std::nullopt;
758+
}
759+
666760
std::optional<std::string> detect_listening_port_for_binary(const fs::path &binary)
667761
{
668762
if (binary.empty() || !have_cmd("ss"))
@@ -781,8 +875,12 @@ namespace vix::commands
781875
const auto buildDir = detect_build_dir();
782876
const auto binary = detect_binary_path(projectName);
783877

784-
const auto service = detect_systemd_service(projectName);
785-
const bool serviceExists = service && systemd_service_exists(*service);
878+
const auto service = detect_systemd_service(
879+
projectName,
880+
fs::current_path(),
881+
binary);
882+
883+
const bool serviceExists = service.has_value();
786884

787885
const auto serviceStatus =
788886
serviceExists ? systemctl_property(*service, "ActiveState") : std::nullopt;

0 commit comments

Comments
 (0)