mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-28 16:01:20 +02:00
425 lines
11 KiB
C++
425 lines
11 KiB
C++
/*
|
|
Based up Neutrino-GUI - Tuxbox-Project
|
|
Copyright (C) 2001 by Steffen Hehn 'McClean'
|
|
|
|
OPKG-Manager Class for Neutrino-GUI
|
|
|
|
Implementation:
|
|
Copyright (C) 2012 T. Graf 'dbt'
|
|
www.dbox2-tuning.net
|
|
|
|
Adaptions:
|
|
Copyright (C) 2013 martii
|
|
gitorious.org/neutrino-mp/martiis-neutrino-mp
|
|
Copyright (C) 2015 Stefan Seyfried
|
|
|
|
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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <gui/opkg_manager.h>
|
|
|
|
#include <global.h>
|
|
#include <neutrino.h>
|
|
#include <neutrino_menue.h>
|
|
|
|
#include <gui/widget/icons.h>
|
|
#include <gui/widget/messagebox.h>
|
|
#include <gui/widget/shellwindow.h>
|
|
#include <driver/screen_max.h>
|
|
|
|
#include <system/debug.h>
|
|
#include <system/helpers.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <poll.h>
|
|
#include <fcntl.h>
|
|
#include <alloca.h>
|
|
|
|
/* later this can be changed to just "opkg" */
|
|
#define OPKG_CL "opkg-cl"
|
|
|
|
enum
|
|
{
|
|
OM_LIST,
|
|
OM_LIST_INSTALLED,
|
|
OM_LIST_UPGRADEABLE,
|
|
OM_UPDATE,
|
|
OM_UPGRADE,
|
|
OM_REMOVE,
|
|
OM_INFO,
|
|
OM_INSTALL,
|
|
OM_MAX
|
|
};
|
|
|
|
static const std::string pkg_types[OM_MAX] =
|
|
{
|
|
OPKG_CL " list",
|
|
OPKG_CL " list-installed",
|
|
OPKG_CL " list-upgradable",
|
|
OPKG_CL " update",
|
|
OPKG_CL " upgrade ",
|
|
OPKG_CL " remove ",
|
|
OPKG_CL " info ",
|
|
OPKG_CL " install "
|
|
};
|
|
|
|
COPKGManager::COPKGManager()
|
|
{
|
|
width = 80;
|
|
pkg_map.clear();
|
|
list_installed_done = false;
|
|
list_upgradeable_done = false;
|
|
expert_mode = false;
|
|
}
|
|
|
|
COPKGManager::~COPKGManager()
|
|
{
|
|
}
|
|
|
|
int COPKGManager::exec(CMenuTarget* parent, const std::string &actionKey)
|
|
{
|
|
int res = menu_return::RETURN_REPAINT;
|
|
|
|
if (actionKey.empty()) {
|
|
if (parent)
|
|
parent->hide();
|
|
return showMenu();
|
|
}
|
|
int selected = menu->getSelected() - menu_offset;
|
|
|
|
if (expert_mode && actionKey == "rc_blue") {
|
|
if (selected < 0 || selected >= (int) pkg_vec.size() || !pkg_vec[selected]->installed)
|
|
return menu_return::RETURN_NONE;
|
|
|
|
char loc[200];
|
|
snprintf(loc, sizeof(loc), g_Locale->getText(LOCALE_OPKG_MESSAGEBOX_REMOVE), pkg_vec[selected]->name.c_str());
|
|
if (ShowMsg(LOCALE_OPKG_TITLE, loc, CMessageBox::mbrCancel, CMessageBox::mbYes | CMessageBox::mbCancel) != CMessageBox::mbrCancel) {
|
|
if (parent)
|
|
parent->hide();
|
|
execCmd(pkg_types[OM_REMOVE] + pkg_vec[selected]->name, true, true);
|
|
refreshMenu();
|
|
}
|
|
return res;
|
|
}
|
|
if (actionKey == "rc_info") {
|
|
if (selected < 0 || selected >= (int) pkg_vec.size())
|
|
return menu_return::RETURN_NONE;
|
|
if (parent)
|
|
parent->hide();
|
|
execCmd(pkg_types[OM_INFO] + pkg_vec[selected]->name, true, true);
|
|
return res;
|
|
}
|
|
if (actionKey == "rc_red") {
|
|
expert_mode = !expert_mode;
|
|
updateMenu();
|
|
return res;
|
|
}
|
|
if(actionKey == pkg_types[OM_UPGRADE]) {
|
|
if (parent)
|
|
parent->hide();
|
|
int r = execCmd(actionKey, true, true);
|
|
if (r) {
|
|
std::string loc = g_Locale->getText(LOCALE_OPKG_FAILURE_UPGRADE);
|
|
char rs[strlen(loc.c_str()) + 20];
|
|
snprintf(rs, sizeof(rs), loc.c_str(), r);
|
|
DisplayInfoMessage(rs);
|
|
} else
|
|
installed = true;
|
|
refreshMenu();
|
|
g_RCInput->postMsg((neutrino_msg_t) CRCInput::RC_up, 0);
|
|
return res;
|
|
}
|
|
|
|
std::map<string, struct pkg>::iterator it = pkg_map.find(actionKey);
|
|
if (it != pkg_map.end()) {
|
|
if (parent)
|
|
parent->hide();
|
|
std::string force = "";
|
|
if (it->second.installed && !it->second.upgradable) {
|
|
char l[200];
|
|
snprintf(l, sizeof(l), g_Locale->getText(LOCALE_OPKG_MESSAGEBOX_REINSTALL), actionKey.c_str());
|
|
l[sizeof(l) - 1] = 0;
|
|
if (ShowMsg(LOCALE_OPKG_TITLE, l, CMessageBox::mbrCancel, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel)
|
|
return res;
|
|
force = "--force-reinstall ";
|
|
}
|
|
int r = execCmd(pkg_types[OM_INSTALL] + force + actionKey, true, true);
|
|
if (r) {
|
|
std::string err = g_Locale->getText(LOCALE_OPKG_FAILURE_INSTALL);
|
|
char rs[strlen(err.c_str()) + 20];
|
|
snprintf(rs, sizeof(rs), err.c_str(), r);
|
|
DisplayInfoMessage(rs);
|
|
} else
|
|
installed = true;
|
|
refreshMenu();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
#define COPKGManagerFooterButtonCount 3
|
|
static const struct button_label COPKGManagerFooterButtons[COPKGManagerFooterButtonCount] = {
|
|
{ NEUTRINO_ICON_BUTTON_RED, LOCALE_OPKG_BUTTON_EXPERT_ON },
|
|
{ NEUTRINO_ICON_BUTTON_INFO_SMALL, LOCALE_OPKG_BUTTON_INFO },
|
|
{ NEUTRINO_ICON_BUTTON_OKAY, LOCALE_OPKG_BUTTON_INSTALL }
|
|
};
|
|
#define COPKGManagerFooterButtonCountExpert 4
|
|
static const struct button_label COPKGManagerFooterButtonsExpert[COPKGManagerFooterButtonCountExpert] = {
|
|
{ NEUTRINO_ICON_BUTTON_RED, LOCALE_OPKG_BUTTON_EXPERT_OFF },
|
|
{ NEUTRINO_ICON_BUTTON_INFO_SMALL, LOCALE_OPKG_BUTTON_INFO },
|
|
{ NEUTRINO_ICON_BUTTON_OKAY, LOCALE_OPKG_BUTTON_INSTALL },
|
|
{ NEUTRINO_ICON_BUTTON_BLUE, LOCALE_OPKG_BUTTON_UNINSTALL }
|
|
};
|
|
|
|
/* TODO: this should go into a config file... */
|
|
static std::string bad_pattern[] = {
|
|
"-dev$",
|
|
"-doc$",
|
|
"-dbg$",
|
|
"-ptest$",
|
|
"-staticdev$",
|
|
"-locale-",
|
|
"-charmap-",
|
|
"-gconv-",
|
|
"-localedata-",
|
|
"^locale-base-",
|
|
"^perl-module-",
|
|
""
|
|
};
|
|
|
|
bool COPKGManager::badpackage(std::string &s)
|
|
{
|
|
int i;
|
|
for (i = 0; !bad_pattern[i].empty(); i++)
|
|
{
|
|
std::string p = bad_pattern[i];
|
|
size_t patlen = p.length() - 1;
|
|
/* poor man's regex :-) only supported are "^" and "$" */
|
|
if (p.substr(patlen, 1) == "$") { /* match at end */
|
|
if (s.rfind(p.substr(0, patlen)) == (s.length() - patlen))
|
|
return true;
|
|
} else if (p.substr(0, 1) == "^") { /* match at beginning */
|
|
if (s.find(p.substr(1)) == 0)
|
|
return true;
|
|
} else { /* match everywhere */
|
|
if (s.find(p) != std::string::npos)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void COPKGManager::updateMenu()
|
|
{
|
|
bool upgradesAvailable = false;
|
|
getPkgData(OM_LIST_INSTALLED);
|
|
getPkgData(OM_LIST_UPGRADEABLE);
|
|
for (std::map<string, struct pkg>::iterator it = pkg_map.begin(); it != pkg_map.end(); it++) {
|
|
if (badpackage(it->second.name))
|
|
continue;
|
|
it->second.forwarder->iconName_Info_right = "";
|
|
it->second.forwarder->setActive(true);
|
|
if (it->second.upgradable) {
|
|
it->second.forwarder->iconName_Info_right = NEUTRINO_ICON_WARNING;
|
|
upgradesAvailable = true;
|
|
} else if (it->second.installed) {
|
|
it->second.forwarder->iconName_Info_right = NEUTRINO_ICON_CHECKMARK;
|
|
it->second.forwarder->setActive(expert_mode);
|
|
}
|
|
}
|
|
|
|
upgrade_forwarder->setActive(upgradesAvailable);
|
|
|
|
if (expert_mode)
|
|
menu->setFooter(COPKGManagerFooterButtonsExpert, COPKGManagerFooterButtonCountExpert);
|
|
else
|
|
menu->setFooter(COPKGManagerFooterButtons, COPKGManagerFooterButtonCount);
|
|
}
|
|
|
|
void COPKGManager::refreshMenu() {
|
|
list_installed_done = false,
|
|
list_upgradeable_done = false;
|
|
updateMenu();
|
|
}
|
|
|
|
int COPKGManager::showMenu()
|
|
{
|
|
installed = false;
|
|
|
|
int r = execCmd(pkg_types[OM_UPDATE]);
|
|
if (r) {
|
|
std::string loc = g_Locale->getText(LOCALE_OPKG_FAILURE_UPDATE);
|
|
char rs[strlen(loc.c_str()) + 20];
|
|
snprintf(rs, sizeof(rs), loc.c_str(), r);
|
|
DisplayInfoMessage(rs);
|
|
}
|
|
|
|
getPkgData(OM_LIST);
|
|
getPkgData(OM_LIST_UPGRADEABLE);
|
|
|
|
menu = new CMenuWidget(g_Locale->getText(LOCALE_SERVICEMENU_UPDATE), NEUTRINO_ICON_UPDATE, width, MN_WIDGET_ID_SOFTWAREUPDATE);
|
|
menu->addIntroItems(LOCALE_OPKG_TITLE, NONEXISTANT_LOCALE, CMenuWidget::BTN_TYPE_BACK, CMenuWidget::BRIEF_HINT_YES);
|
|
|
|
upgrade_forwarder = new CMenuForwarder(LOCALE_OPKG_UPGRADE, true, NULL , this, pkg_types[OM_UPGRADE].c_str(), CRCInput::RC_red);
|
|
upgrade_forwarder->setHint(NEUTRINO_ICON_HINT_SW_UPDATE, LOCALE_MENU_HINT_OPKG_UPGRADE);
|
|
menu->addItem(upgrade_forwarder);
|
|
menu->addItem(GenericMenuSeparatorLine);
|
|
|
|
menu_offset = menu->getItemsCount();
|
|
|
|
menu->addKey(CRCInput::RC_info, this, "rc_info");
|
|
menu->addKey(CRCInput::RC_blue, this, "rc_blue");
|
|
menu->addKey(CRCInput::RC_red, this, "rc_red");
|
|
|
|
pkg_vec.clear();
|
|
for (std::map<string, struct pkg>::iterator it = pkg_map.begin(); it != pkg_map.end(); it++) {
|
|
if (badpackage(it->second.name))
|
|
continue;
|
|
it->second.forwarder = new CMenuForwarder(it->second.desc, true, NULL , this, it->second.name.c_str());
|
|
it->second.forwarder->setHint("", it->second.desc);
|
|
menu->addItem(it->second.forwarder);
|
|
pkg_vec.push_back(&it->second);
|
|
}
|
|
|
|
updateMenu();
|
|
|
|
int res = menu->exec(NULL, "");
|
|
|
|
menu->hide ();
|
|
|
|
if (installed)
|
|
DisplayInfoMessage(g_Locale->getText(LOCALE_OPKG_SUCCESS_INSTALL));
|
|
delete menu;
|
|
return res;
|
|
}
|
|
|
|
bool COPKGManager::hasOpkgSupport()
|
|
{
|
|
string deps[] = {"/etc/opkg/opkg.conf", "/var/lib/opkg", ""};
|
|
|
|
if (find_executable(OPKG_CL).empty()) {
|
|
dprintf(DEBUG_INFO, "[neutrino opkg] did not find " OPKG_CL " executable\n");
|
|
return false;
|
|
}
|
|
for (size_t i = 0; !deps[i].empty(); i++) {
|
|
dprintf(DEBUG_INFO, "[neutrino opkg] check if %s is available...\n", deps[i].c_str());
|
|
if(access(deps[i].c_str(), R_OK) !=0) {
|
|
dprintf(DEBUG_INFO, "[neutrino opkg] %s not found\n", deps[i].c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void COPKGManager::getPkgData(const int pkg_content_id)
|
|
{
|
|
dprintf(DEBUG_INFO, "COPKGManager: executing %s\n", pkg_types[pkg_content_id].c_str());
|
|
|
|
switch (pkg_content_id) {
|
|
case OM_LIST:
|
|
pkg_map.clear();
|
|
list_installed_done = false;
|
|
list_upgradeable_done = false;
|
|
break;
|
|
case OM_LIST_INSTALLED:
|
|
if (list_installed_done)
|
|
return;
|
|
list_installed_done = true;
|
|
for (std::map<string, struct pkg>::iterator it = pkg_map.begin(); it != pkg_map.end(); it++)
|
|
it->second.installed = false;
|
|
break;
|
|
case OM_LIST_UPGRADEABLE:
|
|
if (list_upgradeable_done)
|
|
return;
|
|
list_upgradeable_done = true;
|
|
for (std::map<string, struct pkg>::iterator it = pkg_map.begin(); it != pkg_map.end(); it++)
|
|
it->second.upgradable = false;
|
|
break;
|
|
}
|
|
|
|
FILE *f = popen(pkg_types[pkg_content_id].c_str(), "r");
|
|
if (!f) {
|
|
DisplayInfoMessage("Command failed");
|
|
return;
|
|
}
|
|
|
|
char buf[256];
|
|
|
|
while (fgets(buf, sizeof(buf), f))
|
|
{
|
|
if (buf[0] == ' ')
|
|
continue; /* second, third, ... line of description will not be shown anyway */
|
|
std::string line(buf);
|
|
trim(line);
|
|
|
|
std::string name = getBlankPkgName(line);
|
|
|
|
switch (pkg_content_id) {
|
|
case OM_LIST: {
|
|
pkg_map[name] = pkg(name, line);
|
|
break;
|
|
}
|
|
case OM_LIST_INSTALLED: {
|
|
std::map<string, struct pkg>::iterator it = pkg_map.find(name);
|
|
if (it != pkg_map.end())
|
|
it->second.installed = true;
|
|
break;
|
|
}
|
|
case OM_LIST_UPGRADEABLE: {
|
|
std::map<string, struct pkg>::iterator it = pkg_map.find(name);
|
|
if (it != pkg_map.end())
|
|
it->second.upgradable = true;
|
|
break;
|
|
}
|
|
default:
|
|
fprintf(stderr, "%s %s %d: unrecognized content id %d\n", __FILE__, __func__, __LINE__, pkg_content_id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pclose(f);
|
|
}
|
|
|
|
std::string COPKGManager::getBlankPkgName(const std::string& line)
|
|
{
|
|
size_t l_pos = line.find(" ");
|
|
if (l_pos != string::npos)
|
|
return line.substr(0, l_pos);
|
|
return line;
|
|
}
|
|
|
|
int COPKGManager::execCmd(const char *cmdstr, bool verbose, bool acknowledge)
|
|
{
|
|
fprintf(stderr, "execCmd(%s)\n", cmdstr);
|
|
std::string cmd(cmdstr);
|
|
if (verbose) {
|
|
cmd += " 2>&1";
|
|
int res;
|
|
CShellWindow(cmd, (verbose ? CShellWindow::VERBOSE : 0) | (acknowledge ? CShellWindow::ACKNOWLEDGE : 0), &res);
|
|
return res;
|
|
} else {
|
|
cmd += " 2>/dev/null >&2";
|
|
int r = my_system(3, "/bin/sh", "-c", cmd.c_str());
|
|
if (r == -1)
|
|
return r;
|
|
return WEXITSTATUS(r);
|
|
}
|
|
}
|