xref: /openbmc/telemetry/src/utils/make_id_name.cpp (revision 583ba441654657bb4ba9d051b747144a7258c159)
1 #include "utils/make_id_name.hpp"
2 
3 #include "utils/dbus_path_utils.hpp"
4 
5 #include <sdbusplus/exception.hpp>
6 
7 #include <algorithm>
8 #include <system_error>
9 
10 namespace utils
11 {
12 namespace details
13 {
14 
countDigits(size_t value)15 size_t countDigits(size_t value)
16 {
17     size_t result = 1;
18     while (value >= 10)
19     {
20         ++result;
21         value /= 10;
22     }
23     return result;
24 }
25 
generateId(std::string_view idIn,std::string_view nameIn,std::string_view defaultName,const std::vector<std::string> & conflictIds)26 std::string generateId(std::string_view idIn, std::string_view nameIn,
27                        std::string_view defaultName,
28                        const std::vector<std::string>& conflictIds)
29 {
30     verifyIdCharacters(idIn);
31     verifyIdPrefixes(idIn);
32 
33     if (!idIn.empty() && !idIn.ends_with('/'))
34     {
35         if (std::find(conflictIds.begin(), conflictIds.end(), idIn) !=
36             conflictIds.end())
37         {
38             throw sdbusplus::exception::SdBusError(
39                 static_cast<int>(std::errc::file_exists), "Duplicated id");
40         }
41         return std::string(idIn);
42     }
43 
44     const std::string prefixes(idIn);
45 
46     std::string strippedId(nameIn);
47     if (strippedId.find_first_of(utils::constants::allowedCharactersInPath) ==
48         std::string::npos)
49     {
50         strippedId = defaultName;
51     }
52     strippedId.erase(
53         std::remove_if(
54             strippedId.begin(), strippedId.end(),
55             [](char c) {
56                 return c == '/' ||
57                        utils::constants::allowedCharactersInPath.find(c) ==
58                            std::string_view::npos;
59             }),
60         strippedId.end());
61 
62     size_t idx = 0;
63     std::string tmpId =
64         prefixes + strippedId.substr(0, constants::maxIdNameLength);
65 
66     while (std::find(conflictIds.begin(), conflictIds.end(), tmpId) !=
67            conflictIds.end())
68     {
69         size_t digitsInIdx = countDigits(idx);
70 
71         if (digitsInIdx > constants::maxIdNameLength)
72         {
73             throw sdbusplus::exception::SdBusError(
74                 static_cast<int>(std::errc::file_exists),
75                 "Unique indices are depleted");
76         }
77 
78         tmpId = prefixes +
79                 strippedId.substr(0, constants::maxIdNameLength - digitsInIdx) +
80                 std::to_string(idx);
81         ++idx;
82     }
83 
84     return tmpId;
85 }
86 
87 } // namespace details
88 
makeIdName(std::string_view id,std::string_view name,std::string_view defaultName,const std::vector<std::string> & conflictIds)89 std::pair<std::string, std::string> makeIdName(
90     std::string_view id, std::string_view name, std::string_view defaultName,
91     const std::vector<std::string>& conflictIds)
92 {
93     if (name.length() > constants::maxIdNameLength)
94     {
95         throw errors::InvalidArgument("Name", "Too long.");
96     }
97 
98     if (name.empty() && !id.ends_with('/'))
99     {
100         name = id;
101 
102         if (auto pos = name.find_last_of("/"); pos != std::string::npos)
103         {
104             name = name.substr(pos + 1);
105         }
106 
107         name = name.substr(0, constants::maxIdNameLength);
108     }
109 
110     if (name.empty())
111     {
112         name = defaultName;
113     }
114 
115     return std::make_pair(
116         details::generateId(id, name, defaultName, conflictIds),
117         std::string{name});
118 }
119 
120 } // namespace utils
121