1 /**
2  * Copyright © 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "internal_interface.hpp"
18 
19 #include <sdbusplus/message.hpp>
20 
21 #include <algorithm>
22 #include <iterator>
23 #include <numeric>
24 
25 namespace phosphor
26 {
27 namespace led
28 {
29 namespace sysfs
30 {
31 namespace interface
32 {
33 
InternalInterface(sdbusplus::bus_t & bus,const char * path)34 InternalInterface::InternalInterface(sdbusplus::bus_t& bus, const char* path) :
35     bus(bus), serverInterface(bus, path, internalInterface, vtable.data(), this)
36 {}
37 
getDbusName(const LedDescr & ledDescr)38 std::string InternalInterface::getDbusName(const LedDescr& ledDescr)
39 {
40     std::vector<std::string> words;
41     if (ledDescr.devicename.has_value())
42     {
43         words.emplace_back(ledDescr.devicename.value());
44     }
45     if (ledDescr.function.has_value())
46     {
47         words.emplace_back(ledDescr.function.value());
48     }
49 
50     if (ledDescr.color.has_value())
51     {
52         words.emplace_back(ledDescr.color.value());
53     }
54 
55     std::string s =
56         std::accumulate(std::next(words.begin()), words.end(), words[0],
57                         [](std::string a, const std::string& b) {
58                             return std::move(a) + "_" + b;
59                         });
60 
61     // we assume the string to be a correct dbus name besides
62     // this detail
63     std::replace(s.begin(), s.end(), '-', '_');
64 
65     return s;
66 }
67 
createLEDPath(const std::string & ledName)68 void InternalInterface::createLEDPath(const std::string& ledName)
69 {
70     std::string name;
71     std::string path = devParent + ledName;
72 
73     if (!std::filesystem::exists(fs::path(path)))
74     {
75         lg2::error("No such directory {PATH}", "PATH", path);
76         return;
77     }
78 
79     auto sled = std::make_unique<phosphor::led::SysfsLed>(fs::path(path));
80 
81     // Convert LED name in sysfs into DBus name
82     const LedDescr ledDescr = sled->getLedDescr();
83 
84     name = getDbusName(ledDescr);
85 
86     lg2::debug("LED {NAME} receives dbus name {DBUSNAME}", "NAME", ledName,
87                "DBUSNAME", name);
88 
89     // Unique path name representing a single LED.
90     std::string objPath = std::string(physParent) + "/" + name;
91 
92     if (leds.contains(objPath))
93     {
94         return;
95     }
96 
97     leds.emplace(objPath, std::make_unique<phosphor::led::Physical>(
98                               bus, objPath, std::move(sled),
99                               ledDescr.color.value_or("")));
100 }
101 
addLED(const std::string & name)102 void InternalInterface::addLED(const std::string& name)
103 {
104     createLEDPath(name);
105 }
106 
107 // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
removeLED(const std::string & name)108 void InternalInterface::removeLED(const std::string& name)
109 {
110     lg2::debug("RemoveLED is not configured {NAME}", "NAME", name);
111 }
112 
addLedConfigure(sd_bus_message * msg,void * context,sd_bus_error * error)113 int InternalInterface::addLedConfigure(sd_bus_message* msg, void* context,
114                                        sd_bus_error* error)
115 {
116     if (msg == nullptr && context == nullptr)
117     {
118         lg2::error("Unable to configure addLed");
119         return -EINVAL;
120     }
121 
122     try
123     {
124         auto message = sdbusplus::message_t(msg);
125         auto ledName = message.unpack<std::string>();
126 
127         auto* self = static_cast<InternalInterface*>(context);
128         self->addLED(ledName);
129 
130         auto reply = message.new_method_return();
131         reply.method_return();
132     }
133     catch (const sdbusplus::exception_t& e)
134     {
135         return sd_bus_error_set(error, e.name(), e.description());
136     }
137 
138     return 1;
139 }
140 
removeLedConfigure(sd_bus_message * msg,void * context,sd_bus_error * error)141 int InternalInterface::removeLedConfigure(sd_bus_message* msg, void* context,
142                                           sd_bus_error* error)
143 {
144     if (msg == nullptr && context == nullptr)
145     {
146         lg2::error("Unable to configure removeLed");
147         return -EINVAL;
148     }
149 
150     try
151     {
152         auto message = sdbusplus::message_t(msg);
153         auto ledName = message.unpack<std::string>();
154 
155         auto* self = static_cast<InternalInterface*>(context);
156         self->removeLED(ledName);
157 
158         auto reply = message.new_method_return();
159         reply.method_return();
160     }
161     catch (const sdbusplus::exception_t& e)
162     {
163         return sd_bus_error_set(error, e.name(), e.description());
164     }
165 
166     return 1;
167 }
168 
169 const std::array<sdbusplus::vtable::vtable_t, 4> InternalInterface::vtable = {
170     sdbusplus::vtable::start(),
171     // AddLed method takes a string parameter and returns void
172     sdbusplus::vtable::method("AddLED", "s", "", addLedConfigure),
173     // RemoveLed method takes a string parameter and returns void
174     sdbusplus::vtable::method("RemoveLED", "s", "", removeLedConfigure),
175     sdbusplus::vtable::end()};
176 
177 } // namespace interface
178 } // namespace sysfs
179 } // namespace led
180 } // namespace phosphor
181