blob: 28495c8e09dd160d8cf1267da476ade39c7e1837 [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "printscanmgr/daemon/printscan_tool.h"
#include <set>
#include <string>
#include <utility>
#include <base/check.h>
#include <base/functional/bind.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/run_loop.h>
#include <brillo/files/file_util.h>
#include <lorgnette/proto_bindings/lorgnette_service.pb.h>
#include <lorgnette-client/lorgnette/dbus-proxies.h>
#include <printscanmgr/proto_bindings/printscanmgr_service.pb.h>
namespace printscanmgr {
namespace {
const base::FilePath kCupsFilePath =
base::FilePath("run/cups/debug/debug-flag");
const base::FilePath kIppusbFilePath =
base::FilePath("run/ippusb/debug/debug-flag");
// Saves the values of `success` and `error` to `success_out` and `error_out`,
// respectively.
void SaveArgs(base::OnceClosure quit_closure,
bool* success_out,
std::string* error_out,
bool success,
const std::string& error) {
DCHECK(success_out);
DCHECK(error_out);
*success_out = success;
*error_out = error;
std::move(quit_closure).Run();
}
} // namespace
PrintscanTool::PrintscanTool(mojom::Executor* remote)
: PrintscanTool(remote, base::FilePath("/")) {}
PrintscanTool::PrintscanTool(mojom::Executor* remote,
const base::FilePath& root_path)
: root_path_(root_path), remote_(remote) {
DCHECK(remote_);
}
void PrintscanTool::Init(
std::unique_ptr<org::chromium::lorgnette::ManagerProxyInterface>
lorgnette_proxy) {
DCHECK(lorgnette_proxy);
lorgnette_proxy_ = std::move(lorgnette_proxy);
}
PrintscanDebugSetCategoriesResponse PrintscanTool::DebugSetCategories(
const PrintscanDebugSetCategoriesRequest& request) {
PrintscanDebugSetCategoriesResponse response;
std::set<PrintscanDebugSetCategoriesRequest::DebugLogCategory> categories;
for (const auto category : request.categories()) {
if (!PrintscanDebugSetCategoriesRequest_DebugLogCategory_IsValid(
category)) {
LOG(ERROR) << "Unknown category flag: " << category;
response.set_result(false);
return response;
}
categories.insert(
static_cast<PrintscanDebugSetCategoriesRequest::DebugLogCategory>(
category));
}
auto printing_search = categories.find(
PrintscanDebugSetCategoriesRequest::DEBUG_LOG_CATEGORY_PRINTING);
auto scanning_search = categories.find(
PrintscanDebugSetCategoriesRequest::DEBUG_LOG_CATEGORY_SCANNING);
bool enable_cups = printing_search != categories.end();
bool enable_ippusb = printing_search != categories.end() ||
scanning_search != categories.end();
bool enable_lorgnette = scanning_search != categories.end();
bool success = true;
// Enable Cups logging if the printing category is enabled.
success = ToggleCups(enable_cups);
if (success) {
// Enable Ippusb logging if the printing or scanning category is
// enabled.
success = ToggleIppusb(enable_ippusb);
}
if (success) {
// Enable Lorgnette logging if the scanning category is enabled.
success = ToggleLorgnette(enable_lorgnette);
}
if (!success) {
// Disable all logging if there were any errors setting up logging.
ToggleCups(false);
ToggleIppusb(false);
ToggleLorgnette(false);
}
success &= RestartServices();
response.set_result(success);
return response;
}
// static
std::unique_ptr<PrintscanTool> PrintscanTool::CreateAndInitForTesting(
mojom::Executor* remote,
const base::FilePath& path,
std::unique_ptr<org::chromium::lorgnette::ManagerProxyInterface>
lorgnette_proxy_mock) {
std::unique_ptr<PrintscanTool> printscan_tool(
new PrintscanTool(remote, path));
printscan_tool->Init(std::move(lorgnette_proxy_mock));
return printscan_tool;
}
// Create an empty file at the given path from root_path_.
bool PrintscanTool::CreateEmptyFile(PrintscanFilePaths path) {
base::FilePath full_path;
switch (path) {
case PRINTSCAN_CUPS_FILEPATH:
full_path = root_path_.Append(kCupsFilePath);
break;
case PRINTSCAN_IPPUSB_FILEPATH:
full_path = root_path_.Append(kIppusbFilePath);
break;
}
return base::WriteFile(full_path, "", 0) == 0;
}
// Delete a file at the given path from root_path_.
bool PrintscanTool::DeleteFile(PrintscanFilePaths path) {
base::FilePath full_path;
switch (path) {
case PRINTSCAN_CUPS_FILEPATH:
full_path = root_path_.Append(kCupsFilePath);
break;
case PRINTSCAN_IPPUSB_FILEPATH:
full_path = root_path_.Append(kIppusbFilePath);
break;
}
return brillo::DeleteFile(full_path);
}
// Enable Cups debug logs if `enable` is set, otherwise disable the logs.
// Return true on success.
bool PrintscanTool::ToggleCups(bool enable) {
if (enable) {
if (!CreateEmptyFile(PRINTSCAN_CUPS_FILEPATH)) {
LOG(ERROR) << "Failed to create cups debug-flag.";
return false;
}
LOG(INFO) << "Advanced CUPS logging enabled.";
} else {
if (!DeleteFile(PRINTSCAN_CUPS_FILEPATH)) {
LOG(ERROR) << "Failed to delete cups debug-flag.";
return false;
}
LOG(INFO) << "Advanced CUPS logging disabled.";
}
return true;
}
// Enable Ippusb debug logs if `enable` is set, otherwise disable the logs.
// Return true on success.
bool PrintscanTool::ToggleIppusb(bool enable) {
if (enable) {
if (!CreateEmptyFile(PRINTSCAN_IPPUSB_FILEPATH)) {
LOG(ERROR) << "Failed to create ippusb debug-flag.";
return false;
}
LOG(INFO) << "Advanced ippusb logging enabled.";
} else {
if (!DeleteFile(PRINTSCAN_IPPUSB_FILEPATH)) {
LOG(ERROR) << "Failed to delete ippusb delete-flag.";
return false;
}
LOG(INFO) << "Advanced ippusb logging disabled.";
}
return true;
}
// Enable Lorgnette debug logs if `enable` is set, otherwise disable the logs.
// Return true on success.
bool PrintscanTool::ToggleLorgnette(bool enable) {
DCHECK(lorgnette_proxy_);
lorgnette::SetDebugConfigRequest request;
request.set_enabled(enable);
lorgnette::SetDebugConfigResponse response;
brillo::ErrorPtr error;
if (!lorgnette_proxy_->SetDebugConfig(request, &response, &error)) {
LOG(ERROR) << "Failed to call SetDebugConfig: " << error->GetMessage();
}
if (!response.success()) {
return false;
}
if (enable) {
LOG(INFO) << "Advanced lorgnette logging enabled.";
} else {
LOG(INFO) << "Advanced lorgnette logging disabled.";
}
return true;
}
// Restart cupsd.
bool PrintscanTool::RestartServices() {
// cupsd is intended to have the same lifetime as the ui, so we need to
// fully restart it.
std::string error;
bool success;
base::RunLoop run_loop;
remote_->RestartUpstartJob(
mojom::UpstartJob::kCupsd,
base::BindOnce(&SaveArgs, run_loop.QuitClosure(), &success, &error));
run_loop.Run();
if (!success) {
LOG(ERROR) << "Executor mojo method RestartUpstartJob for cupsd failed: "
<< error;
}
return success;
}
} // namespace printscanmgr