xref: /openbmc/service-config-manager/src/srvcfg_manager.cpp (revision e55cfd6e22bbc851981905b41b7098f80779da52)
10084047dSAppaRao Puli /*
20084047dSAppaRao Puli // Copyright (c) 2018 Intel Corporation
30084047dSAppaRao Puli //
40084047dSAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
50084047dSAppaRao Puli // you may not use this file except in compliance with the License.
60084047dSAppaRao Puli // You may obtain a copy of the License at
70084047dSAppaRao Puli //
80084047dSAppaRao Puli //      http://www.apache.org/licenses/LICENSE-2.0
90084047dSAppaRao Puli //
100084047dSAppaRao Puli // Unless required by applicable law or agreed to in writing, software
110084047dSAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
120084047dSAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130084047dSAppaRao Puli // See the License for the specific language governing permissions and
140084047dSAppaRao Puli // limitations under the License.
150084047dSAppaRao Puli */
160084047dSAppaRao Puli #include <fstream>
170084047dSAppaRao Puli #include <regex>
180084047dSAppaRao Puli #include "srvcfg_manager.hpp"
190084047dSAppaRao Puli 
200084047dSAppaRao Puli extern std::shared_ptr<boost::asio::deadline_timer> timer;
210084047dSAppaRao Puli extern std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
220084047dSAppaRao Puli     srvMgrObjects;
230084047dSAppaRao Puli 
240084047dSAppaRao Puli namespace phosphor
250084047dSAppaRao Puli {
260084047dSAppaRao Puli namespace service
270084047dSAppaRao Puli {
280084047dSAppaRao Puli 
290084047dSAppaRao Puli static constexpr const char *overrideConfFileName = "override.conf";
300084047dSAppaRao Puli static constexpr const size_t restartTimeout = 15; // seconds
310084047dSAppaRao Puli 
320084047dSAppaRao Puli static constexpr const char *systemd1UnitBasePath =
330084047dSAppaRao Puli     "/org/freedesktop/systemd1/unit/";
340084047dSAppaRao Puli static constexpr const char *systemdOverrideUnitBasePath =
350084047dSAppaRao Puli     "/etc/systemd/system/";
360084047dSAppaRao Puli 
370084047dSAppaRao Puli void ServiceConfig::syncWithSystemD1Properties()
380084047dSAppaRao Puli {
390084047dSAppaRao Puli     // Read systemd1 socket/service property and load.
400084047dSAppaRao Puli     conn->async_method_call(
410084047dSAppaRao Puli         [this](boost::system::error_code ec,
420084047dSAppaRao Puli                const sdbusplus::message::variant<
430084047dSAppaRao Puli                    std::vector<std::tuple<std::string, std::string>>> &value) {
440084047dSAppaRao Puli             if (ec)
450084047dSAppaRao Puli             {
460084047dSAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
470084047dSAppaRao Puli                     "async_method_call error: Failed to get property");
480084047dSAppaRao Puli                 return;
490084047dSAppaRao Puli             }
500084047dSAppaRao Puli 
510084047dSAppaRao Puli             try
520084047dSAppaRao Puli             {
530084047dSAppaRao Puli                 auto listenVal = sdbusplus::message::variant_ns::get<
540084047dSAppaRao Puli                     std::vector<std::tuple<std::string, std::string>>>(value);
550084047dSAppaRao Puli                 protocol = std::get<0>(listenVal[0]);
560084047dSAppaRao Puli                 std::string port = std::get<1>(listenVal[0]);
570084047dSAppaRao Puli                 auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1),
580084047dSAppaRao Puli                                       nullptr, 10);
590084047dSAppaRao Puli                 if (tmp > std::numeric_limits<uint16_t>::max())
600084047dSAppaRao Puli                 {
610084047dSAppaRao Puli                     throw std::out_of_range("Out of range");
620084047dSAppaRao Puli                 }
630084047dSAppaRao Puli                 portNum = tmp;
640084047dSAppaRao Puli             }
650084047dSAppaRao Puli             catch (const std::exception &e)
660084047dSAppaRao Puli             {
670084047dSAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
680084047dSAppaRao Puli                     "Exception for port number",
690084047dSAppaRao Puli                     phosphor::logging::entry("WHAT=%s", e.what()));
700084047dSAppaRao Puli                 return;
710084047dSAppaRao Puli             }
720084047dSAppaRao Puli             conn->async_method_call(
730084047dSAppaRao Puli                 [](boost::system::error_code ec) {
740084047dSAppaRao Puli                     if (ec)
750084047dSAppaRao Puli                     {
760084047dSAppaRao Puli                         phosphor::logging::log<phosphor::logging::level::ERR>(
770084047dSAppaRao Puli                             "async_method_call error: Failed to set property");
780084047dSAppaRao Puli                         return;
790084047dSAppaRao Puli                     }
800084047dSAppaRao Puli                 },
810084047dSAppaRao Puli                 serviceConfigSrvName, objPath.c_str(),
820084047dSAppaRao Puli                 "org.freedesktop.DBus.Properties", "Set", serviceConfigIntfName,
830084047dSAppaRao Puli                 "Port", sdbusplus::message::variant<uint16_t>(portNum));
840084047dSAppaRao Puli         },
850084047dSAppaRao Puli         "org.freedesktop.systemd1", sysDSockObjPath.c_str(),
860084047dSAppaRao Puli         "org.freedesktop.DBus.Properties", "Get",
870084047dSAppaRao Puli         "org.freedesktop.systemd1.Socket", "Listen");
880084047dSAppaRao Puli 
890084047dSAppaRao Puli     conn->async_method_call(
900084047dSAppaRao Puli         [this](boost::system::error_code ec,
910084047dSAppaRao Puli                const sdbusplus::message::variant<std::string> &pValue) {
920084047dSAppaRao Puli             if (ec)
930084047dSAppaRao Puli             {
940084047dSAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
950084047dSAppaRao Puli                     "async_method_call error: Failed to get property");
960084047dSAppaRao Puli                 return;
970084047dSAppaRao Puli             }
980084047dSAppaRao Puli 
990084047dSAppaRao Puli             channelList.clear();
1000084047dSAppaRao Puli             std::istringstream stm(
1010084047dSAppaRao Puli                 sdbusplus::message::variant_ns::get<std::string>(pValue));
1020084047dSAppaRao Puli             std::string token;
1030084047dSAppaRao Puli             while (std::getline(stm, token, ','))
1040084047dSAppaRao Puli             {
1050084047dSAppaRao Puli                 channelList.push_back(token);
1060084047dSAppaRao Puli             }
1070084047dSAppaRao Puli             conn->async_method_call(
1080084047dSAppaRao Puli                 [](boost::system::error_code ec) {
1090084047dSAppaRao Puli                     if (ec)
1100084047dSAppaRao Puli                     {
1110084047dSAppaRao Puli                         phosphor::logging::log<phosphor::logging::level::ERR>(
1120084047dSAppaRao Puli                             "async_method_call error: Failed to set property");
1130084047dSAppaRao Puli                         return;
1140084047dSAppaRao Puli                     }
1150084047dSAppaRao Puli                 },
1160084047dSAppaRao Puli                 serviceConfigSrvName, objPath.c_str(),
1170084047dSAppaRao Puli                 "org.freedesktop.DBus.Properties", "Set", serviceConfigIntfName,
1180084047dSAppaRao Puli                 "Channel",
1190084047dSAppaRao Puli                 sdbusplus::message::variant<std::vector<std::string>>(
1200084047dSAppaRao Puli                     channelList));
1210084047dSAppaRao Puli         },
1220084047dSAppaRao Puli         "org.freedesktop.systemd1", sysDSockObjPath.c_str(),
1230084047dSAppaRao Puli         "org.freedesktop.DBus.Properties", "Get",
1240084047dSAppaRao Puli         "org.freedesktop.systemd1.Socket", "BindToDevice");
1250084047dSAppaRao Puli 
1260084047dSAppaRao Puli     std::string srvUnitName(sysDUnitName);
1270084047dSAppaRao Puli     if (srvUnitName == "dropbear")
1280084047dSAppaRao Puli     {
129*e55cfd6eSAppaRao Puli         // Dropbear service expects template arguments.
1300084047dSAppaRao Puli         srvUnitName.append("@");
1310084047dSAppaRao Puli     }
1320084047dSAppaRao Puli     srvUnitName.append(".service");
1330084047dSAppaRao Puli     conn->async_method_call(
1340084047dSAppaRao Puli         [this](boost::system::error_code ec, const std::string &pValue) {
1350084047dSAppaRao Puli             if (ec)
1360084047dSAppaRao Puli             {
1370084047dSAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
1380084047dSAppaRao Puli                     "async_method_call error: Failed to get property");
1390084047dSAppaRao Puli                 return;
1400084047dSAppaRao Puli             }
141*e55cfd6eSAppaRao Puli             if ((pValue == "enabled") || (pValue == "static") ||
142*e55cfd6eSAppaRao Puli                 (pValue == "unmasked"))
143*e55cfd6eSAppaRao Puli             {
144*e55cfd6eSAppaRao Puli                 stateValue = "enabled";
145*e55cfd6eSAppaRao Puli             }
146*e55cfd6eSAppaRao Puli             else if ((pValue == "disabled") || (pValue == "masked"))
147*e55cfd6eSAppaRao Puli             {
148*e55cfd6eSAppaRao Puli                 stateValue = "disabled";
149*e55cfd6eSAppaRao Puli             }
1500084047dSAppaRao Puli             conn->async_method_call(
1510084047dSAppaRao Puli                 [](boost::system::error_code ec) {
1520084047dSAppaRao Puli                     if (ec)
1530084047dSAppaRao Puli                     {
1540084047dSAppaRao Puli                         phosphor::logging::log<phosphor::logging::level::ERR>(
1550084047dSAppaRao Puli                             "async_method_call error: Failed to set property");
1560084047dSAppaRao Puli                         return;
1570084047dSAppaRao Puli                     }
1580084047dSAppaRao Puli                 },
1590084047dSAppaRao Puli                 serviceConfigSrvName, objPath.c_str(),
1600084047dSAppaRao Puli                 "org.freedesktop.DBus.Properties", "Set", serviceConfigIntfName,
1610084047dSAppaRao Puli                 "State", sdbusplus::message::variant<std::string>(stateValue));
1620084047dSAppaRao Puli         },
1630084047dSAppaRao Puli         "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1640084047dSAppaRao Puli         "org.freedesktop.systemd1.Manager", "GetUnitFileState", srvUnitName);
1650084047dSAppaRao Puli 
1660084047dSAppaRao Puli     return;
1670084047dSAppaRao Puli }
1680084047dSAppaRao Puli 
1690084047dSAppaRao Puli ServiceConfig::ServiceConfig(
1700084047dSAppaRao Puli     sdbusplus::asio::object_server &srv_,
1710084047dSAppaRao Puli     std::shared_ptr<sdbusplus::asio::connection> &conn_, std::string objPath_,
1720084047dSAppaRao Puli     std::string unitName) :
1730084047dSAppaRao Puli     server(srv_),
1740084047dSAppaRao Puli     conn(conn_), objPath(objPath_), sysDUnitName(unitName)
1750084047dSAppaRao Puli {
1760084047dSAppaRao Puli     std::string socketUnitName(sysDUnitName + ".socket");
1770084047dSAppaRao Puli     // .socket systemd service files are handled.
1780084047dSAppaRao Puli     // Regular .service only files are ignored.
1790084047dSAppaRao Puli     if (!checkSystemdUnitExist(socketUnitName))
1800084047dSAppaRao Puli     {
1810084047dSAppaRao Puli         phosphor::logging::log<phosphor::logging::level::ERR>(
1820084047dSAppaRao Puli             "Unit doesn't exist.",
1830084047dSAppaRao Puli             phosphor::logging::entry("UNITNAME=%s", socketUnitName.c_str()));
1840084047dSAppaRao Puli         phosphor::logging::elog<
1850084047dSAppaRao Puli             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
1860084047dSAppaRao Puli     }
1870084047dSAppaRao Puli 
1880084047dSAppaRao Puli     /// Check override socket directory exist, if not create it.
1890084047dSAppaRao Puli     std::experimental::filesystem::path ovrUnitFileDir(
1900084047dSAppaRao Puli         systemdOverrideUnitBasePath);
1910084047dSAppaRao Puli     ovrUnitFileDir += socketUnitName;
1920084047dSAppaRao Puli     ovrUnitFileDir += ".d";
1930084047dSAppaRao Puli     if (!std::experimental::filesystem::exists(ovrUnitFileDir))
1940084047dSAppaRao Puli     {
1950084047dSAppaRao Puli         if (!std::experimental::filesystem::create_directories(ovrUnitFileDir))
1960084047dSAppaRao Puli         {
1970084047dSAppaRao Puli             phosphor::logging::log<phosphor::logging::level::ERR>(
1980084047dSAppaRao Puli                 "Unable to create the directory.",
1990084047dSAppaRao Puli                 phosphor::logging::entry("DIR=%s", ovrUnitFileDir.c_str()));
2000084047dSAppaRao Puli             phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
2010084047dSAppaRao Puli                                         Error::InternalFailure>();
2020084047dSAppaRao Puli         }
2030084047dSAppaRao Puli     }
2040084047dSAppaRao Puli 
2050084047dSAppaRao Puli     /* Store require info locally */
2060084047dSAppaRao Puli     unitSocketFilePath = std::string(ovrUnitFileDir);
2070084047dSAppaRao Puli 
2080084047dSAppaRao Puli     sysDSockObjPath = systemd1UnitBasePath;
2090084047dSAppaRao Puli     sysDSockObjPath.append(
2100084047dSAppaRao Puli         std::regex_replace(sysDUnitName, std::regex("-"), "_2d"));
2110084047dSAppaRao Puli     sysDSockObjPath.append("_2esocket");
2120084047dSAppaRao Puli 
2130084047dSAppaRao Puli     // Adds interface, object and Properties....
2140084047dSAppaRao Puli     registerProperties();
2150084047dSAppaRao Puli 
2160084047dSAppaRao Puli     syncWithSystemD1Properties();
2170084047dSAppaRao Puli 
2180084047dSAppaRao Puli     updatedFlag = 0;
2190084047dSAppaRao Puli     return;
2200084047dSAppaRao Puli }
2210084047dSAppaRao Puli 
2220084047dSAppaRao Puli void ServiceConfig::applySystemDServiceConfig()
2230084047dSAppaRao Puli {
224*e55cfd6eSAppaRao Puli     if (updatedFlag)
225*e55cfd6eSAppaRao Puli     {
226*e55cfd6eSAppaRao Puli         // No updates. Just return.
227*e55cfd6eSAppaRao Puli         return;
228*e55cfd6eSAppaRao Puli     }
229*e55cfd6eSAppaRao Puli 
2300084047dSAppaRao Puli     phosphor::logging::log<phosphor::logging::level::INFO>(
2310084047dSAppaRao Puli         "Applying new settings.",
2320084047dSAppaRao Puli         phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
2330084047dSAppaRao Puli     if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::channel)) |
2340084047dSAppaRao Puli                        (1 << static_cast<uint8_t>(UpdatedProp::port))))
2350084047dSAppaRao Puli     {
2360084047dSAppaRao Puli         // Create override config file and write data.
2370084047dSAppaRao Puli         std::string ovrCfgFile{unitSocketFilePath + "/" + overrideConfFileName};
2380084047dSAppaRao Puli         std::string tmpFile{ovrCfgFile + "_tmp"};
2390084047dSAppaRao Puli         std::ofstream cfgFile(tmpFile, std::ios::out);
2400084047dSAppaRao Puli         if (!cfgFile.good())
2410084047dSAppaRao Puli         {
2420084047dSAppaRao Puli             phosphor::logging::log<phosphor::logging::level::ERR>(
2430084047dSAppaRao Puli                 "Failed to open override.conf_tmp file");
2440084047dSAppaRao Puli             phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
2450084047dSAppaRao Puli                                         Error::InternalFailure>();
2460084047dSAppaRao Puli         }
2470084047dSAppaRao Puli 
2480084047dSAppaRao Puli         // Write the socket header
2490084047dSAppaRao Puli         cfgFile << "[Socket]\n";
2500084047dSAppaRao Puli         // Listen
2510084047dSAppaRao Puli         cfgFile << "Listen" << protocol << "="
2520084047dSAppaRao Puli                 << "\n";
2530084047dSAppaRao Puli         cfgFile << "Listen" << protocol << "=" << portNum << "\n";
2540084047dSAppaRao Puli         // BindToDevice
2550084047dSAppaRao Puli         bool firstElement = true;
2560084047dSAppaRao Puli         cfgFile << "BindToDevice=";
2570084047dSAppaRao Puli         for (const auto &it : channelList)
2580084047dSAppaRao Puli         {
2590084047dSAppaRao Puli             if (firstElement)
2600084047dSAppaRao Puli             {
2610084047dSAppaRao Puli                 cfgFile << it;
2620084047dSAppaRao Puli                 firstElement = false;
2630084047dSAppaRao Puli             }
2640084047dSAppaRao Puli             else
2650084047dSAppaRao Puli             {
2660084047dSAppaRao Puli                 cfgFile << "," << it;
2670084047dSAppaRao Puli             }
2680084047dSAppaRao Puli         }
2690084047dSAppaRao Puli         cfgFile.close();
2700084047dSAppaRao Puli 
2710084047dSAppaRao Puli         if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0)
2720084047dSAppaRao Puli         {
2730084047dSAppaRao Puli             phosphor::logging::log<phosphor::logging::level::ERR>(
2740084047dSAppaRao Puli                 "Failed to rename tmp file as override.conf");
2750084047dSAppaRao Puli             std::remove(tmpFile.c_str());
2760084047dSAppaRao Puli             phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
2770084047dSAppaRao Puli                                         Error::InternalFailure>();
2780084047dSAppaRao Puli         }
279*e55cfd6eSAppaRao Puli     }
2800084047dSAppaRao Puli 
2810084047dSAppaRao Puli     std::string socketUnitName(sysDUnitName + ".socket");
282*e55cfd6eSAppaRao Puli     std::string srvUnitName(sysDUnitName);
283*e55cfd6eSAppaRao Puli     if (srvUnitName == "dropbear")
284*e55cfd6eSAppaRao Puli     {
285*e55cfd6eSAppaRao Puli         // Dropbear service expects template arguments.
286*e55cfd6eSAppaRao Puli         // Todo: Unit action for service, fails with error
287*e55cfd6eSAppaRao Puli         // "missing the instance name". Needs to implement
288*e55cfd6eSAppaRao Puli         // getting all running instances and use it. This
289*e55cfd6eSAppaRao Puli         // impact runtime but works fine during reboot.
290*e55cfd6eSAppaRao Puli         srvUnitName.append("@");
291*e55cfd6eSAppaRao Puli     }
292*e55cfd6eSAppaRao Puli     srvUnitName.append(".service");
293*e55cfd6eSAppaRao Puli     // Stop the running service in below scenarios.
294*e55cfd6eSAppaRao Puli     // 1. State changed from "enabled" to "disabled"
295*e55cfd6eSAppaRao Puli     // 2. No change in state and existing stateValue is
296*e55cfd6eSAppaRao Puli     //    "enabled" and there is change in other properties.
297*e55cfd6eSAppaRao Puli     if (((stateValue == "disabled") &&
298*e55cfd6eSAppaRao Puli          (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::state)))) ||
299*e55cfd6eSAppaRao Puli         (!(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::state))) &&
300*e55cfd6eSAppaRao Puli          (stateValue == "enabled") && (updatedFlag)))
301*e55cfd6eSAppaRao Puli     {
302*e55cfd6eSAppaRao Puli         systemdUnitAction(conn, socketUnitName, "StopUnit");
303*e55cfd6eSAppaRao Puli         systemdUnitAction(conn, srvUnitName, "StopUnit");
3040084047dSAppaRao Puli     }
3050084047dSAppaRao Puli 
3060084047dSAppaRao Puli     if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::state)))
3070084047dSAppaRao Puli     {
308*e55cfd6eSAppaRao Puli         std::vector<std::string> unitFiles = {socketUnitName, srvUnitName};
309*e55cfd6eSAppaRao Puli         systemdUnitFilesStateChange(conn, unitFiles, stateValue);
3100084047dSAppaRao Puli     }
311*e55cfd6eSAppaRao Puli 
312*e55cfd6eSAppaRao Puli     // Perform daemon reload to read new settings
313*e55cfd6eSAppaRao Puli     systemdDaemonReload(conn);
314*e55cfd6eSAppaRao Puli 
315*e55cfd6eSAppaRao Puli     if (stateValue == "enabled")
316*e55cfd6eSAppaRao Puli     {
317*e55cfd6eSAppaRao Puli         // Restart the socket
318*e55cfd6eSAppaRao Puli         systemdUnitAction(conn, socketUnitName, "StartUnit");
3190084047dSAppaRao Puli     }
3200084047dSAppaRao Puli 
3210084047dSAppaRao Puli     // Reset the flag
3220084047dSAppaRao Puli     updatedFlag = 0;
3230084047dSAppaRao Puli 
3240084047dSAppaRao Puli     // All done. Lets reload the properties which are applied on systemd1.
3250084047dSAppaRao Puli     // TODO: We need to capture the service restart signal and reload data
326*e55cfd6eSAppaRao Puli     // inside the signal handler. So that we can update the service
327*e55cfd6eSAppaRao Puli     // properties modified, outside of this service as well.
3280084047dSAppaRao Puli     syncWithSystemD1Properties();
3290084047dSAppaRao Puli 
3300084047dSAppaRao Puli     return;
3310084047dSAppaRao Puli }
3320084047dSAppaRao Puli 
3330084047dSAppaRao Puli void ServiceConfig::startServiceRestartTimer()
3340084047dSAppaRao Puli {
3350084047dSAppaRao Puli     timer->expires_from_now(boost::posix_time::seconds(restartTimeout));
3360084047dSAppaRao Puli     timer->async_wait([this](const boost::system::error_code &ec) {
3370084047dSAppaRao Puli         if (ec == boost::asio::error::operation_aborted)
3380084047dSAppaRao Puli         {
3390084047dSAppaRao Puli             // Timer reset.
3400084047dSAppaRao Puli             return;
3410084047dSAppaRao Puli         }
3420084047dSAppaRao Puli         else if (ec)
3430084047dSAppaRao Puli         {
3440084047dSAppaRao Puli             phosphor::logging::log<phosphor::logging::level::ERR>(
3450084047dSAppaRao Puli                 "async wait error.");
3460084047dSAppaRao Puli             return;
3470084047dSAppaRao Puli         }
3480084047dSAppaRao Puli         for (auto &srvMgrObj : srvMgrObjects)
3490084047dSAppaRao Puli         {
3500084047dSAppaRao Puli             auto &srvObj = srvMgrObj.second;
3510084047dSAppaRao Puli             if (srvObj->updatedFlag)
3520084047dSAppaRao Puli             {
3530084047dSAppaRao Puli                 srvObj->applySystemDServiceConfig();
3540084047dSAppaRao Puli             }
3550084047dSAppaRao Puli         }
3560084047dSAppaRao Puli     });
3570084047dSAppaRao Puli }
3580084047dSAppaRao Puli 
3590084047dSAppaRao Puli void ServiceConfig::registerProperties()
3600084047dSAppaRao Puli {
3610084047dSAppaRao Puli     std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
3620084047dSAppaRao Puli         server.add_interface(objPath, serviceConfigIntfName);
3630084047dSAppaRao Puli 
3640084047dSAppaRao Puli     iface->register_property(
3650084047dSAppaRao Puli         "Port", portNum, [this](const uint16_t &req, uint16_t &res) {
3660084047dSAppaRao Puli             if (req == res)
3670084047dSAppaRao Puli             {
3680084047dSAppaRao Puli                 return 1;
3690084047dSAppaRao Puli             }
3700084047dSAppaRao Puli             portNum = req;
3710084047dSAppaRao Puli             updatedFlag |= (1 << static_cast<uint8_t>(UpdatedProp::port));
3720084047dSAppaRao Puli             startServiceRestartTimer();
3730084047dSAppaRao Puli             res = req;
3740084047dSAppaRao Puli             return 1;
3750084047dSAppaRao Puli         });
3760084047dSAppaRao Puli 
3770084047dSAppaRao Puli     iface->register_property(
3780084047dSAppaRao Puli         "Channel", channelList,
3790084047dSAppaRao Puli         [this](const std::vector<std::string> &req,
3800084047dSAppaRao Puli                std::vector<std::string> &res) {
3810084047dSAppaRao Puli             if (req == res)
3820084047dSAppaRao Puli             {
3830084047dSAppaRao Puli                 return 1;
3840084047dSAppaRao Puli             }
3850084047dSAppaRao Puli             channelList.clear();
3860084047dSAppaRao Puli             std::copy(req.begin(), req.end(), back_inserter(channelList));
3870084047dSAppaRao Puli 
3880084047dSAppaRao Puli             updatedFlag |= (1 << static_cast<uint8_t>(UpdatedProp::channel));
3890084047dSAppaRao Puli             startServiceRestartTimer();
3900084047dSAppaRao Puli             res = req;
3910084047dSAppaRao Puli             return 1;
3920084047dSAppaRao Puli         });
3930084047dSAppaRao Puli 
3940084047dSAppaRao Puli     iface->register_property(
3950084047dSAppaRao Puli         "State", stateValue, [this](const std::string &req, std::string &res) {
3960084047dSAppaRao Puli             if (req == res)
3970084047dSAppaRao Puli             {
3980084047dSAppaRao Puli                 return 1;
3990084047dSAppaRao Puli             }
400*e55cfd6eSAppaRao Puli             if ((req != "enabled") && (req != "disabled"))
4010084047dSAppaRao Puli             {
4020084047dSAppaRao Puli                 phosphor::logging::log<phosphor::logging::level::ERR>(
4030084047dSAppaRao Puli                     "Invalid value specified");
4040084047dSAppaRao Puli                 return -EINVAL;
4050084047dSAppaRao Puli             }
4060084047dSAppaRao Puli             stateValue = req;
4070084047dSAppaRao Puli             updatedFlag |= (1 << static_cast<uint8_t>(UpdatedProp::state));
4080084047dSAppaRao Puli             startServiceRestartTimer();
4090084047dSAppaRao Puli             res = req;
4100084047dSAppaRao Puli             return 1;
4110084047dSAppaRao Puli         });
4120084047dSAppaRao Puli 
4130084047dSAppaRao Puli     iface->initialize();
4140084047dSAppaRao Puli     return;
4150084047dSAppaRao Puli }
4160084047dSAppaRao Puli 
4170084047dSAppaRao Puli } // namespace service
4180084047dSAppaRao Puli } // namespace phosphor
419