]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/util.cc
update sources to 12.2.8
[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 // memory
141 FILE *f = fopen(PROCPREFIX "/proc/meminfo", "r");
142 if (f) {
143 char buf[100];
144 while (!feof(f)) {
145 char *line = fgets(buf, sizeof(buf), f);
146 if (!line)
147 break;
148 char key[40];
149 long long value;
150 int r = sscanf(line, "%s %lld", key, &value);
151 if (r == 2) {
152 if (strcmp(key, "MemTotal:") == 0)
153 (*m)["mem_total_kb"] = boost::lexical_cast<string>(value);
154 else if (strcmp(key, "SwapTotal:") == 0)
155 (*m)["mem_swap_kb"] = boost::lexical_cast<string>(value);
156 }
157 }
158 fclose(f);
159 }
160
161 // processor
162 f = fopen(PROCPREFIX "/proc/cpuinfo", "r");
163 if (f) {
164 char buf[100];
165 while (!feof(f)) {
166 char *line = fgets(buf, sizeof(buf), f);
167 if (!line)
168 break;
169 if (strncmp(line, "model name", 10) == 0) {
170 char *c = strchr(buf, ':');
171 c++;
172 while (*c == ' ')
173 ++c;
174 char *nl = c;
175 while (*nl != '\n')
176 ++nl;
177 *nl = '\0';
178 (*m)["cpu"] = c;
179 break;
180 }
181 }
182 fclose(f);
183 }
184
185 // distro info
186 distro_detect(m, cct);
187 }
188
189 void dump_services(Formatter* f, const map<string, list<int> >& services, const char* type)
190 {
191 assert(f);
192
193 f->open_object_section(type);
194 for (map<string, list<int> >::const_iterator host = services.begin();
195 host != services.end(); ++host) {
196 f->open_array_section(host->first.c_str());
197 const list<int>& hosted = host->second;
198 for (list<int>::const_iterator s = hosted.begin();
199 s != hosted.end(); ++s) {
200 f->dump_int(type, *s);
201 }
202 f->close_section();
203 }
204 f->close_section();
205 }
206
207
208 // If non-printable characters found then convert bufferlist to
209 // base64 encoded string indicating whether it did.
210 string cleanbin(bufferlist &bl, bool &base64)
211 {
212 bufferlist::iterator it;
213 for (it = bl.begin(); it != bl.end(); ++it) {
214 if (iscntrl(*it))
215 break;
216 }
217 if (it == bl.end()) {
218 base64 = false;
219 string result(bl.c_str(), bl.length());
220 return result;
221 }
222
223 bufferlist b64;
224 bl.encode_base64(b64);
225 string encoded(b64.c_str(), b64.length());
226 base64 = true;
227 return encoded;
228 }
229
230 // If non-printable characters found then convert to "Base64:" followed by
231 // base64 encoding
232 string cleanbin(string &str)
233 {
234 bool base64;
235 bufferlist bl;
236 bl.append(str);
237 string result = cleanbin(bl, base64);
238 if (base64)
239 result = "Base64:" + result;
240 return result;
241 }
242
243 std::string bytes2str(uint64_t count) {
244 static char s[][2] = {"\0", "k", "M", "G", "T", "P", "E", "\0"};
245 int i = 0;
246 while (count >= 1024 && *s[i+1]) {
247 count >>= 10;
248 i++;
249 }
250 char str[128];
251 snprintf(str, sizeof str, "%" PRIu64 "%sB", count, s[i]);
252 return std::string(str);
253 }