]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/util.cc
update sources to 12.2.10
[ceph.git] / ceph / src / common / util.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2012 Inktank Storage, Inc.
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <sys/utsname.h>
16 #include <boost/lexical_cast.hpp>
17
18 #include "include/compat.h"
19 #include "include/util.h"
20 #include "common/debug.h"
21 #include "common/errno.h"
22 #include "common/version.h"
23
24 #ifdef HAVE_SYS_VFS_H
25 #include <sys/vfs.h>
26 #endif
27
28 #if defined(DARWIN) || defined(__FreeBSD__)
29 #include <sys/param.h>
30 #include <sys/mount.h>
31 #endif
32
33 #include <string>
34
35 #include <stdio.h>
36
37 int get_fs_stats(ceph_data_stats_t &stats, const char *path)
38 {
39 if (!path)
40 return -EINVAL;
41
42 struct statfs stbuf;
43 int err = ::statfs(path, &stbuf);
44 if (err < 0) {
45 return -errno;
46 }
47
48 stats.byte_total = stbuf.f_blocks * stbuf.f_bsize;
49 stats.byte_used = (stbuf.f_blocks - stbuf.f_bfree) * stbuf.f_bsize;
50 stats.byte_avail = stbuf.f_bavail * stbuf.f_bsize;
51 stats.avail_percent = (((float)stats.byte_avail/stats.byte_total)*100);
52 return 0;
53 }
54
55 static char* value_sanitize(char *value)
56 {
57 while (isspace(*value) || *value == '"')
58 value++;
59
60 char* end = value + strlen(value) - 1;
61 while (end > value && (isspace(*end) || *end == '"'))
62 end--;
63
64 *(end + 1) = '\0';
65
66 return value;
67 }
68
69 static bool value_set(char *buf, const char *prefix,
70 map<string, string> *pm, const char *key)
71 {
72 if (strncmp(buf, prefix, strlen(prefix))) {
73 return false;
74 }
75
76 (*pm)[key] = value_sanitize(buf + strlen(prefix));
77 return true;
78 }
79
80 static void file_values_parse(const map<string, string>& kvm, FILE *fp, map<string, string> *m, CephContext *cct) {
81 char buf[512];
82 while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
83 for (auto& kv : kvm) {
84 if (value_set(buf, kv.second.c_str(), m, kv.first.c_str()))
85 continue;
86 }
87 }
88 }
89
90 static bool os_release_parse(map<string, string> *m, CephContext *cct)
91 {
92 static const map<string, string> kvm = {
93 { "distro", "ID=" },
94 { "distro_description", "PRETTY_NAME=" },
95 { "distro_version", "VERSION_ID=" }
96 };
97
98 FILE *fp = fopen("/etc/os-release", "r");
99 if (!fp) {
100 int ret = -errno;
101 lderr(cct) << "os_release_parse - failed to open /etc/os-release: " << cpp_strerror(ret) << dendl;
102 return false;
103 }
104
105 file_values_parse(kvm, fp, m, cct);
106
107 fclose(fp);
108
109 return true;
110 }
111
112 static void distro_detect(map<string, string> *m, CephContext *cct)
113 {
114 if (!os_release_parse(m, cct)) {
115 lderr(cct) << "distro_detect - /etc/os-release is required" << dendl;
116 }
117
118 for (const char* rk: {"distro", "distro_description"}) {
119 if (m->find(rk) == m->end())
120 lderr(cct) << "distro_detect - can't detect " << rk << dendl;
121 }
122 }
123
124 void collect_sys_info(map<string, string> *m, CephContext *cct)
125 {
126 // version
127 (*m)["ceph_version"] = pretty_version_to_str();
128
129 // kernel info
130 struct utsname u;
131 int r = uname(&u);
132 if (r >= 0) {
133 (*m)["os"] = u.sysname;
134 (*m)["kernel_version"] = u.release;
135 (*m)["kernel_description"] = u.version;
136 (*m)["hostname"] = u.nodename;
137 (*m)["arch"] = u.machine;
138 }
139
140 // but wait, am i in a container?
141 if (const char *pod_name = getenv("POD_NAME")) {
142 (*m)["pod_name"] = pod_name;
143 if (const char *node_name = getenv("NODE_NAME")) {
144 (*m)["container_hostname"] = u.nodename;
145 (*m)["hostname"] = node_name;
146 }
147 }
148 if (const char *ns = getenv("POD_NAMESPACE")) {
149 (*m)["pod_namespace"] = ns;
150 }
151
152 // memory
153 FILE *f = fopen(PROCPREFIX "/proc/meminfo", "r");
154 if (f) {
155 char buf[100];
156 while (!feof(f)) {
157 char *line = fgets(buf, sizeof(buf), f);
158 if (!line)
159 break;
160 char key[40];
161 long long value;
162 int r = sscanf(line, "%s %lld", key, &value);
163 if (r == 2) {
164 if (strcmp(key, "MemTotal:") == 0)
165 (*m)["mem_total_kb"] = boost::lexical_cast<string>(value);
166 else if (strcmp(key, "SwapTotal:") == 0)
167 (*m)["mem_swap_kb"] = boost::lexical_cast<string>(value);
168 }
169 }
170 fclose(f);
171 }
172
173 // processor
174 f = fopen(PROCPREFIX "/proc/cpuinfo", "r");
175 if (f) {
176 char buf[100];
177 while (!feof(f)) {
178 char *line = fgets(buf, sizeof(buf), f);
179 if (!line)
180 break;
181 if (strncmp(line, "model name", 10) == 0) {
182 char *c = strchr(buf, ':');
183 c++;
184 while (*c == ' ')
185 ++c;
186 char *nl = c;
187 while (*nl != '\n')
188 ++nl;
189 *nl = '\0';
190 (*m)["cpu"] = c;
191 break;
192 }
193 }
194 fclose(f);
195 }
196
197 // distro info
198 distro_detect(m, cct);
199 }
200
201 void dump_services(Formatter* f, const map<string, list<int> >& services, const char* type)
202 {
203 assert(f);
204
205 f->open_object_section(type);
206 for (map<string, list<int> >::const_iterator host = services.begin();
207 host != services.end(); ++host) {
208 f->open_array_section(host->first.c_str());
209 const list<int>& hosted = host->second;
210 for (list<int>::const_iterator s = hosted.begin();
211 s != hosted.end(); ++s) {
212 f->dump_int(type, *s);
213 }
214 f->close_section();
215 }
216 f->close_section();
217 }
218
219
220 // If non-printable characters found then convert bufferlist to
221 // base64 encoded string indicating whether it did.
222 string cleanbin(bufferlist &bl, bool &base64)
223 {
224 bufferlist::iterator it;
225 for (it = bl.begin(); it != bl.end(); ++it) {
226 if (iscntrl(*it))
227 break;
228 }
229 if (it == bl.end()) {
230 base64 = false;
231 string result(bl.c_str(), bl.length());
232 return result;
233 }
234
235 bufferlist b64;
236 bl.encode_base64(b64);
237 string encoded(b64.c_str(), b64.length());
238 base64 = true;
239 return encoded;
240 }
241
242 // If non-printable characters found then convert to "Base64:" followed by
243 // base64 encoding
244 string cleanbin(string &str)
245 {
246 bool base64;
247 bufferlist bl;
248 bl.append(str);
249 string result = cleanbin(bl, base64);
250 if (base64)
251 result = "Base64:" + result;
252 return result;
253 }
254
255 std::string bytes2str(uint64_t count) {
256 static char s[][2] = {"\0", "k", "M", "G", "T", "P", "E", "\0"};
257 int i = 0;
258 while (count >= 1024 && *s[i+1]) {
259 count >>= 10;
260 i++;
261 }
262 char str[128];
263 snprintf(str, sizeof str, "%" PRIu64 "%sB", count, s[i]);
264 return std::string(str);
265 }