1+ #pragma once
2+
3+ #include < stdexcept>
4+ #include " logger.h"
5+
6+ namespace libsinsp
7+ {
8+
9+ /* *
10+ * Simple helper to read a comma-separated list that includes ranges and
11+ * determine the total count of the values within.
12+ * Examples: 1,4-5 = 3; 0-15 = 16; 3,7,11 = 3
13+ *
14+ * See the "List Format" section of
15+ * http://man7.org/linux/man-pages/man7/cpuset.7.html
16+ *
17+ * Returns -1 if string is invalid.
18+ */
19+ class cgroup_list_counter
20+ {
21+ public:
22+ const int INVALID_CPU_COUNT = -1 ;
23+
24+ /* *
25+ * Return the number of elements given by the buffer. If needed, log at the
26+ * given log-level.
27+ */
28+ int operator ()(const char *buffer, sinsp_logger::severity log_level)
29+ {
30+ reset ();
31+
32+ int cpu_count = 0 ;
33+
34+ try
35+ {
36+ const char *position = buffer;
37+ for (; ' \0 ' != *position; ++position)
38+ {
39+ if (' -' == *position)
40+ {
41+ if (nullptr == m_section_start)
42+ {
43+ throw std::runtime_error (" duplicate range indicator before start" );
44+ }
45+ if (nullptr != m_range_indicator)
46+ {
47+ throw std::runtime_error (" duplicate range indicators" );
48+ }
49+
50+ m_range_indicator = position;
51+ }
52+ else if (' ,' == *position)
53+ {
54+ cpu_count += process_section (m_section_start, position, m_range_indicator);
55+ reset ();
56+ }
57+ else if (nullptr == m_section_start)
58+ {
59+ m_section_start = position;
60+ }
61+
62+ }
63+
64+ // There is never a trailing comma so always process the
65+ // final section
66+ cpu_count += process_section (m_section_start, position, m_range_indicator);
67+
68+ }
69+ catch (const std::exception& ex)
70+ {
71+ g_logger.format (log_level,
72+ " Invalid List Format: %s. Detail: %s" ,
73+ buffer,
74+ ex.what ());
75+ return INVALID_CPU_COUNT;
76+ }
77+
78+ return cpu_count;
79+ }
80+
81+ private:
82+
83+ static int process_number (const char *section_start, const char *section_end)
84+ {
85+ std::string section (section_start, section_end - section_start);
86+ return std::stoi (section.c_str ());
87+
88+ }
89+
90+ static int process_section (const char *section_start, const char *section_end, const char *range_indicator)
91+ {
92+ if (nullptr == section_start)
93+ {
94+ throw std::runtime_error (" invalid end of section before start of section" );
95+ }
96+
97+ if (nullptr == section_end)
98+ {
99+ throw std::runtime_error (" invalid end of section" );
100+ }
101+
102+ if (section_end <= section_start)
103+ {
104+ throw std::runtime_error (" invalid section" );
105+ }
106+
107+ if (range_indicator)
108+ {
109+ // Split into two sections
110+ int first = process_number (section_start, range_indicator);
111+ int second = process_number (range_indicator + 1 , section_end);
112+
113+ if (second <= first)
114+ {
115+ throw std::runtime_error (" invalid range" );
116+ }
117+
118+ return second - first + 1 ;
119+ }
120+
121+ // We don't care what the value is, we just want to know that it is a number
122+ (void )process_number (section_start, section_end);
123+ return 1 ;
124+ }
125+
126+ void reset ()
127+ {
128+ m_section_start = nullptr ;
129+ m_range_indicator = nullptr ;
130+ }
131+
132+ const char *m_section_start = nullptr ;
133+ const char *m_range_indicator = nullptr ;
134+ };
135+
136+ }
0 commit comments