1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2012 Inktank Storage, Inc.
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.
15 #include <sys/utsname.h>
16 #include <boost/lexical_cast.hpp>
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"
28 #if defined(DARWIN) || defined(__FreeBSD__)
29 #include <sys/param.h>
30 #include <sys/mount.h>
37 int64_t unit_to_bytesize(string val, ostream *pss)
41 *pss << "value is empty!";
45 char c = val[val.length()-1];
48 if (val.length() < 2) {
50 *pss << "invalid value: " << val;
53 val = val.substr(0,val.length()-1);
78 *pss << "unrecognized modifier '" << c << "'" << std::endl;
83 if (val[0] == '+' || val[0] == '-') {
85 *pss << "expected numerical value, got: " << val;
90 int64_t r = strict_strtoll(val.c_str(), 10, &err);
91 if ((r == 0) && !err.empty()) {
98 *pss << "unable to parse positive integer '" << val << "'";
101 return (r * (1LL << modifier));
104 int get_fs_stats(ceph_data_stats_t &stats, const char *path)
110 int err = ::statfs(path, &stbuf);
115 stats.byte_total = stbuf.f_blocks * stbuf.f_bsize;
116 stats.byte_used = (stbuf.f_blocks - stbuf.f_bfree) * stbuf.f_bsize;
117 stats.byte_avail = stbuf.f_bavail * stbuf.f_bsize;
118 stats.avail_percent = (((float)stats.byte_avail/stats.byte_total)*100);
122 static char* value_sanitize(char *value)
124 while (isspace(*value) || *value == '"')
127 char* end = value + strlen(value) - 1;
128 while (end > value && (isspace(*end) || *end == '"'))
136 static bool value_set(char *buf, const char *prefix,
137 map<string, string> *pm, const char *key)
139 if (strncmp(buf, prefix, strlen(prefix))) {
143 (*pm)[key] = value_sanitize(buf + strlen(prefix));
147 static void file_values_parse(const map<string, string>& kvm, FILE *fp, map<string, string> *m, CephContext *cct) {
149 while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
150 for (auto& kv : kvm) {
151 if (value_set(buf, kv.second.c_str(), m, kv.first.c_str()))
157 static bool os_release_parse(map<string, string> *m, CephContext *cct)
159 static const map<string, string> kvm = {
161 { "distro_description", "PRETTY_NAME=" },
162 { "distro_version", "VERSION_ID=" }
165 FILE *fp = fopen("/etc/os-release", "r");
168 lderr(cct) << "os_release_parse - failed to open /etc/os-release: " << cpp_strerror(ret) << dendl;
172 file_values_parse(kvm, fp, m, cct);
179 static void distro_detect(map<string, string> *m, CephContext *cct)
181 if (!os_release_parse(m, cct)) {
182 lderr(cct) << "distro_detect - /etc/os-release is required" << dendl;
185 for (const char* rk: {"distro", "distro_version"}) {
186 if (m->find(rk) == m->end())
187 lderr(cct) << "distro_detect - can't detect " << rk << dendl;
191 void collect_sys_info(map<string, string> *m, CephContext *cct)
194 (*m)["ceph_version"] = pretty_version_to_str();
200 (*m)["os"] = u.sysname;
201 (*m)["kernel_version"] = u.release;
202 (*m)["kernel_description"] = u.version;
203 (*m)["hostname"] = u.nodename;
204 (*m)["arch"] = u.machine;
208 FILE *f = fopen(PROCPREFIX "/proc/meminfo", "r");
212 char *line = fgets(buf, sizeof(buf), f);
217 int r = sscanf(line, "%s %lld", key, &value);
219 if (strcmp(key, "MemTotal:") == 0)
220 (*m)["mem_total_kb"] = boost::lexical_cast<string>(value);
221 else if (strcmp(key, "SwapTotal:") == 0)
222 (*m)["mem_swap_kb"] = boost::lexical_cast<string>(value);
229 f = fopen(PROCPREFIX "/proc/cpuinfo", "r");
233 char *line = fgets(buf, sizeof(buf), f);
236 if (strncmp(line, "model name", 10) == 0) {
237 char *c = strchr(buf, ':');
253 distro_detect(m, cct);
256 void dump_services(Formatter* f, const map<string, list<int> >& services, const char* type)
260 f->open_object_section(type);
261 for (map<string, list<int> >::const_iterator host = services.begin();
262 host != services.end(); ++host) {
263 f->open_array_section(host->first.c_str());
264 const list<int>& hosted = host->second;
265 for (list<int>::const_iterator s = hosted.begin();
266 s != hosted.end(); ++s) {
267 f->dump_int(type, *s);
275 // If non-printable characters found then convert bufferlist to
276 // base64 encoded string indicating whether it did.
277 string cleanbin(bufferlist &bl, bool &base64)
279 bufferlist::iterator it;
280 for (it = bl.begin(); it != bl.end(); ++it) {
284 if (it == bl.end()) {
286 string result(bl.c_str(), bl.length());
291 bl.encode_base64(b64);
292 string encoded(b64.c_str(), b64.length());
297 // If non-printable characters found then convert to "Base64:" followed by
299 string cleanbin(string &str)
304 string result = cleanbin(bl, base64);
306 result = "Base64:" + result;
310 std::string bytes2str(uint64_t count) {
311 static char s[][2] = {"\0", "k", "M", "G", "T", "P", "E", "\0"};
313 while (count >= 1024 && *s[i+1]) {
318 snprintf(str, sizeof str, "%" PRIu64 "%sB", count, s[i]);
319 return std::string(str);