/* hdd_info (C) 2009-2016 NG-Team (C) 2016 NI-Team License: GPL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int my_filter(const struct dirent *dent) { if (dent->d_name[0] == 's' && dent->d_name[1] == 'd') return 1; return 0; } static char *trim(char *txt) { register int l; register char *p1, *p2; if (*txt == ' ') { for (p1 = p2 = txt; (*p1 == ' ') || (*p1 == '\t') || (*p1 == '\n') || (*p1 == '\r'); p1++) {}; while (*p1) *p2++ = *p1++; *p2 = '\0'; } if ((l = strlen(txt)) > 0) for (p1 = txt + l - 1; (*p1 == ' ') || (*p1 == '\t') || (*p1 == '\n') || (*p1 == '\r'); *p1-- = '\0') {}; return (txt); } CHDDInfoMenu::CHDDInfoMenu() { width = 35; } CHDDInfoMenu::~CHDDInfoMenu() { } int CHDDInfoMenu::exec(CMenuTarget *parent, const std::string &actionKey) { printf("[HDDInfo] exec ationKey %s\n", actionKey.c_str()); int res = menu_return::RETURN_REPAINT; if (parent) parent->hide(); if (actionKey != "") { COSDFader fader(g_settings.theme.menu_Content_alpha); fader.StartFadeIn(); CHDDInfoWidget::paint(actionKey); //int res = g_RCInput->messageLoop(); neutrino_msg_t msg; neutrino_msg_data_t data; bool doLoop = true; int timeout = g_settings.timing[SNeutrinoSettings::TIMING_MENU]; uint64_t timeoutEnd = CRCInput::calcTimeoutEnd(timeout); while (doLoop) { g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); if ((msg == NeutrinoMessages::EVT_TIMER) && (data == fader.GetFadeTimer())) { if (fader.FadeDone()) { doLoop = false; } } else if ((msg == CRCInput::RC_timeout) || (msg == CRCInput::RC_home) || (msg == CRCInput::RC_ok)) { if (fader.StartFadeOut()) { timeoutEnd = CRCInput::calcTimeoutEnd(1); msg = 0; } else doLoop = false; } else if (CNeutrinoApp::getInstance()->listModeKey(msg)) { // do nothing } else { int mr = CNeutrinoApp::getInstance()->handleMsg(msg, data); if (mr & messages_return::cancel_all) { res = menu_return::RETURN_EXIT_ALL; doLoop = false; } else if (mr & messages_return::unhandled) { if ((msg <= CRCInput::RC_MaxRC) && (data == 0)) /* <- button pressed */ { timeoutEnd = CRCInput::calcTimeoutEnd(timeout); } } } } CHDDInfoWidget::hide(); fader.StopFade(); return res; } res = show(); return res; } int CHDDInfoMenu::show() { FILE *f; struct dirent **namelist; bool hdd_found = 0; int n = scandir("/sys/block", &namelist, my_filter, alphasort); std::ostringstream buf; //menue init CMenuWidget *HDDInfo = new CMenuWidget(LOCALE_HDD_INFO_HEAD, NEUTRINO_ICON_SETTINGS, width, MN_WIDGET_ID_HDD_INFO); HDDInfo->addIntroItems(); for (int i = 0; i < n; i++) { char model[128] = "unbekannt"; buf.str(""); buf << "/sys/block/" << namelist[i]->d_name << "/device/model"; f = fopen(buf.str().c_str(), "r"); if (f) { fscanf(f, "%127[^\n]", (char *) &model); fclose(f); } else printf("Cant open %s\n", buf.str().c_str()); buf.str(""); buf << trim(model) << " (" << namelist[i]->d_name << ")"; HDDInfo->addItem(new CMenuForwarder(buf.str().c_str(), true, NULL, this, namelist[i]->d_name)); hdd_found = 1; free(namelist[i]); } if (n >= 0) free(namelist); if (!hdd_found) HDDInfo->addItem(new CMenuForwarder(LOCALE_HDD_NOT_FOUND, false)); int res = HDDInfo->exec(NULL, ""); HDDInfo->hide(); delete HDDInfo; return res; } // ---------------------------------------------------------------------------- CHDDInfoWidget::CHDDInfoWidget() { } CHDDInfoWidget::~CHDDInfoWidget() { } typedef struct items_data_t { neutrino_locale_t locale; char value[128]; } items_data_struct; items_data_t items_data[] = { { LOCALE_HDD_INFO_MODEL_FAMILY , "" }, // 0 { LOCALE_HDD_INFO_MODEL , "" }, // 1 { LOCALE_HDD_INFO_SERIAL , "" }, // 2 { LOCALE_HDD_INFO_FIRMWARE , "" }, // 3 { LOCALE_HDD_INFO_CAPACITY , "" }, // 4 { LOCALE_HDD_INFO_SECTOR_SIZE , "" }, // 5 { LOCALE_HDD_INFO_ROTATION_RATE , "" }, // 6 { LOCALE_HDD_INFO_SATA_VERSION , "" }, // 7 { LOCALE_HDD_INFO_TEMPERATURE , "" } // 8 }; #define items_count (sizeof(items_data)/sizeof(struct items_data_t)) void CHDDInfoWidget::paint(const std::string &Key) { frameBuffer = CFrameBuffer::getInstance(); CComponentsHeader header; CComponentsFooter footer; Font *item_font = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]; int header_height = header.getHeight(); int item_height = item_font->getHeight(); int body_height = items_count * item_height + 2 * OFFSET_INNER_SMALL; int footer_height = header.getHeight(); width = frameBuffer->getScreenWidth() / 2; height = header_height + body_height + footer_height; x = getScreenStartX(width); y = getScreenStartY(height); FILE *pipe_reader; char *buffer; ssize_t read; size_t len; char *found; std::string str_capacity; unsigned long long mb; std::ostringstream buf; buf << "smartctl --all /dev/" << Key; buffer = NULL; if ((pipe_reader = popen(buf.str().c_str(), "r"))) { while ((read = getline(&buffer, &len, pipe_reader)) != -1) { if ((found = strstr(buffer, "Model Family:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[0].value); else if ((found = strstr(buffer, "Device Model:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[1].value); else if ((found = strstr(buffer, "Serial Number:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[2].value); else if ((found = strstr(buffer, "Firmware Version:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[3].value); else if ((found = strstr(buffer, "User Capacity:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[4].value); else if ((found = strstr(buffer, "Sector Size:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[5].value); else if ((found = strstr(buffer, "Rotation Rate:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[6].value); else if ((found = strstr(buffer, "SATA Version is:"))) sscanf(found + 18, "%127[^\n]", (char *) &items_data[7].value); else if ((found = strstr(buffer, "Temperature_Celsius"))) sscanf(found + 83, "%3[^\n]", (char *) &items_data[8].value); } pclose(pipe_reader); } else printf("[read_smartctl] popen error\n"); if (buffer) free(buffer); // manipulating capacity str_capacity = items_data[4].value; str_capacity.erase(std::remove(str_capacity.begin(), str_capacity.end(), ','), str_capacity.end()); mb = strtoull(str_capacity.c_str(), NULL, 0) / 1000000; buf.str(""); if (mb != 0) { if (mb < 1000) buf << mb << " MB"; else buf << mb / 1000 << " GB"; } snprintf(items_data[4].value, sizeof(items_data[4].value), "%s", buf.str().c_str()); // manipulating temperature buf.str(""); if (strcmp(items_data[8].value, "") != 0) { buf << trim(items_data[8].value) << " Grad Celsius"; snprintf(items_data[8].value, sizeof(items_data[8].value), "%s", buf.str().c_str()); } // calculate max width of locales int w_loc = 0, w_tmp = 0; for (unsigned int i = 0; i < items_count; i++) { w_tmp = item_font->getRenderWidth(g_Locale->getText(items_data[i].locale)); w_loc = std::max(w_loc, w_tmp); } // calculate width of separator std::string separator = ":"; int w_sep = item_font->getRenderWidth(separator); // calculate max width of values int w_val = 0; for (unsigned int i = 0; i < items_count; i++) { if (strcmp(items_data[i].value, "") == 0) snprintf(items_data[i].value, sizeof(items_data[i].value), "%s", g_Locale->getText(LOCALE_HDD_INFO_UNKNOWN)); w_tmp = item_font->getRenderWidth(trim(items_data[i].value)); w_val = std::max(w_val, w_tmp); } // recalculate width and xpos width = std::max(width, w_loc + w_sep + w_val + 4 * OFFSET_INNER_MID); if (width > (int) frameBuffer->getScreenWidth()) { // should only happen with very big fonts width = frameBuffer->getScreenWidth(); w_val = width - w_loc - w_sep - 4 * OFFSET_INNER_MID; } x = getScreenStartX(width); // header buf.str(""); buf << g_Locale->getText(LOCALE_HDD_INFO_HEAD) << " (" << Key << ")"; header.setCaption(buf.str()); header.setIcon(NEUTRINO_ICON_SETTINGS); header.setDimensionsAll(x, y, width, header_height); header.addContextButton(CComponentsHeader::CC_BTN_EXIT); header.enableShadow(CC_SHADOW_RIGHT | CC_SHADOW_CORNER_TOP_RIGHT | CC_SHADOW_CORNER_BOTTOM_RIGHT, -1, true); header.paint(CC_SAVE_SCREEN_NO); // body PaintBoxRel(x, y + header_height, width, body_height, COL_MENUCONTENT_PLUS_0, RADIUS_NONE, CORNER_NONE, CC_SHADOW_ON); // footer const struct button_label buttons[] = { { "", LOCALE_HDD_INFO_INFO } }; footer.enableShadow(CC_SHADOW_ON, -1, true); footer.paintButtons(x, y + header_height + body_height, width, footer_height, 1, buttons); // paint items int x_loc = x + OFFSET_INNER_MID; int x_sep = x_loc + w_loc + OFFSET_INNER_MID; int x_val = x_sep + w_sep + OFFSET_INNER_MID; int y_item = y + header_height + OFFSET_INNER_SMALL; for (unsigned int i = 0; i < items_count; i++) { y_item += item_height; item_font->RenderString(x_loc, y_item, w_loc, g_Locale->getText(items_data[i].locale), COL_MENUCONTENTINACTIVE_TEXT); item_font->RenderString(x_sep, y_item, w_sep, separator, COL_MENUCONTENTINACTIVE_TEXT); item_font->RenderString(x_val, y_item, w_val, items_data[i].value, COL_MENUCONTENT_TEXT); } } void CHDDInfoWidget::hide() { frameBuffer->paintBackgroundBoxRel(x, y, width + OFFSET_SHADOW, height + OFFSET_SHADOW); }