File: cgroup_list_counter.h

package info (click to toggle)
falcosecurity-libs 0.1.1dev%2Bgit20220316.e5c53d64-5.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 4,732 kB
  • sloc: cpp: 55,770; ansic: 37,330; makefile: 74; sh: 13
file content (136 lines) | stat: -rw-r--r-- 2,895 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#pragma once

#include <stdexcept>
#include "logger.h"

namespace libsinsp
{

/**
 * Simple helper to read a comma-separated list that includes ranges and
 * determine the total count of the values within.
 * Examples: 1,4-5 = 3; 0-15 = 16; 3,7,11 = 3
 *
 * See the "List Format" section of
 * http://man7.org/linux/man-pages/man7/cpuset.7.html
 *
 * Returns -1 if string is invalid.
 */
class cgroup_list_counter
{
public:
	const int INVALID_CPU_COUNT = -1;

	/**
	 * Return the number of elements given by the buffer. If needed, log at the
	 * given log-level.
	 */
	int operator ()(const char *buffer)
	{
		reset();

		int cpu_count = 0;

		try
		{
			const char *position = buffer;
			for(; '\0' != *position; ++position)
			{
				if ('-' == *position)
				{
					if (nullptr == m_section_start)
					{
						throw std::runtime_error("duplicate range indicator before start");
					}
					if (nullptr != m_range_indicator)
					{
						throw std::runtime_error("duplicate range indicators");
					}

					m_range_indicator = position;
				}
				else if (',' == *position)
				{
					cpu_count += process_section(m_section_start, position, m_range_indicator);
					reset();
				}
				else if (nullptr == m_section_start)
				{
					m_section_start = position;
				}

			}

			// There is never a trailing comma so always process the
			// final section
			cpu_count += process_section(m_section_start, position, m_range_indicator);

		}
		catch (const std::exception& ex)
		{
			g_logger.format(sinsp_logger::SEV_ERROR,
					"Invalid List Format: %s. Detail: %s",
					buffer,
					ex.what());
			return INVALID_CPU_COUNT;
		}

		return cpu_count;
	}

private:

	static int process_number(const char *section_start, const char *section_end)
	{
		std::string section(section_start, section_end - section_start);
		return std::stoi(section.c_str());

	}

	static int process_section(const char *section_start, const char *section_end, const char *range_indicator)
	{
		if (nullptr == section_start)
		{
			throw std::runtime_error("invalid end of section before start of section");
		}

		if (nullptr == section_end)
		{
			throw std::runtime_error("invalid end of section");
		}

		if (section_end <= section_start)
		{
			throw std::runtime_error("invalid section");
		}

		if (range_indicator)
		{
			// Split into two sections
			int first = process_number(section_start, range_indicator);
			int second = process_number(range_indicator + 1, section_end);

			if (second <= first)
			{
				throw std::runtime_error("invalid range");
			}

			return second - first + 1;
		}

		// We don't care what the value is, we just want to know that it is a number
		(void)process_number(section_start, section_end);
		return 1;
	}

	void reset()
	{
		m_section_start = nullptr;
		m_range_indicator = nullptr;
	}

	const char *m_section_start = nullptr;
	const char *m_range_indicator = nullptr;
};

}