| // 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 |