is read from <current-rootdir>/etc/products.d/baseproduct and the architecture
is determined from uname and CPU flags.
+.TP
+.B licenses
+Prints a report about \fBlicenses\fR and \fBEULA\fRs of installed packages
+to standard output.
+
+First, a list of all packages and their licenses and/or EULAs is shown.
+This is followed by a summary, including the total number of installed
+packages, the number of installed
+packages with EULAs that required a confirmation from the user. Since the
+EULAs are not stored on the system and can only be read from repository
+metadata, the summary includes also the number of installed packages
+that have their counterpart in repositories. The report ends with a list
+of all licenses uses by the installed packages.
+
+This command can be useful for companies redistributiong a custom
+distribution (like appliances) to figure out what licenses they are bound by.
+
.SH "GLOBAL OPTIONS"
const ZypperCommand ZypperCommand::TARGET_OS(ZypperCommand::TARGET_OS_e);
const ZypperCommand ZypperCommand::VERSION_CMP(ZypperCommand::VERSION_CMP_e);
+const ZypperCommand ZypperCommand::LICENSES(ZypperCommand::LICENSES_e);
const ZypperCommand ZypperCommand::HELP(ZypperCommand::HELP_e);
const ZypperCommand ZypperCommand::SHELL(ZypperCommand::SHELL_e);
_table["targetos"] = _table["tos"] = ZypperCommand::TARGET_OS_e;
_table["versioncmp"] = _table["vcmp"] = ZypperCommand::VERSION_CMP_e;
+ _table["licenses"] = ZypperCommand::LICENSES_e;
_table["help"] = _table["?"] = ZypperCommand::HELP_e;
_table["shell"] = _table["sh"] = ZypperCommand::SHELL_e;
// utils/others
static const ZypperCommand TARGET_OS;
static const ZypperCommand VERSION_CMP;
+ static const ZypperCommand LICENSES;
static const ZypperCommand HELP;
static const ZypperCommand SHELL;
TARGET_OS_e,
VERSION_CMP_e,
+ LICENSES_e,
HELP_e,
SHELL_e,
static string help_other_commands = _("\tOther Commands:\n"
"\tversioncmp, vcmp\tCompare two version strings.\n"
"\ttargetos, tos\t\tPrint the target operating system ID string.\n"
+ "\tlicenses\t\tPrint report about licenses and EULAs of installed packages.\n"
);
static string help_usage = _(
break;
}
+ case ZypperCommand::LICENSES_e:
+ {
+ static struct option options[] =
+ {
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+ specific_options = options;
+ _command_help = _(
+ "licenses\n"
+ "\n"
+ "Report Licenses and EULA of currently installed software packages.\n"
+ "\n"
+ "This command has no additional options.\n"
+ );
+ break;
+ }
+
case ZypperCommand::SHELL_QUIT_e:
{
static struct option quit_options[] = {
if (command() == ZypperCommand::RUG_PATCH_SEARCH)
_gopts.is_rug_compatible = true;
- zypp::PoolQuery query;
-
if (runningHelp()) { out().info(_command_help, Out::QUIET); return; }
+ zypp::PoolQuery query;
+
TriBool inst_notinst = indeterminate;
if (globalOpts().disable_system_resolvables || copts.count("uninstalled-only"))
{
break;
}
+ case ZypperCommand::LICENSES_e:
+ {
+ if (runningHelp()) { out().info(_command_help, Out::QUIET); return; }
+
+ if (!_arguments.empty())
+ {
+ report_too_many_arguments(_command_help);
+ setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
+ return;
+ }
+
+ init_repos(*this);
+ if (exitCode() != ZYPPER_EXIT_OK)
+ return;
+ init_target(*this);
+ // now load resolvables:
+ load_resolvables(*this);
+ // needed to compute status of PPP
+ resolve(*this);
+
+ report_licenses(*this);
+
+ break;
+ }
+
// -----------------------------( shell )------------------------------------
case ZypperCommand::SHELL_QUIT_e:
|__/|_| |_|
\*---------------------------------------------------------------------------*/
+#include <iostream>
#include <sstream>
#include <boost/format.hpp>
#include "zypp/base/Logger.h"
#include "zypp/SrcPackage.h"
+#include "zypp/Package.h"
#include "zypp/Capabilities.h"
+
#include "zypp/RepoInfo.h"
+#include "zypp/PoolQuery.h"
+
#include "main.h"
#include "utils/misc.h"
#include "utils/pager.h"
return confirmed;
}
+// ----------------------------------------------------------------------------
+
+void report_licenses(Zypper & zypper)
+{
+ PoolQuery q;
+
+ ui::Selectable::constPtr s;
+ PoolItem inst;
+ PoolItem inst_with_repo;
+
+ unsigned count_installed = 0, count_installed_repo = 0, count_installed_eula = 0;
+ set<string> unique_licenses;
+
+ for_(pit, q.selectableBegin(), q.selectableEnd())
+ {
+ s = *pit;
+ if (!s) // FIXME this must not be necessary!
+ continue;
+
+ for_(iit, s->installedBegin(), s->installedEnd())
+ {
+ inst = *iit;
+ ++count_installed;
+
+ cout
+ << s->name() << "-" << inst.resolvable()->edition()
+ << " (" << kind_to_string_localized(s->kind(), 1) << ")"
+ << endl;
+
+ if (s->kind() == ResKind::package)
+ {
+ cout
+ << _("License") << ": "
+ << asKind<Package>(inst.resolvable())->license()
+ << endl;
+ unique_licenses.insert(asKind<Package>(inst.resolvable())->license());
+ }
+
+ for_(it, s->availableBegin(), s->availableEnd())
+ {
+ if (equalNVRA(*it->resolvable(), *inst.resolvable()))
+ {
+ inst_with_repo = *it;
+ ++count_installed_repo;
+ break;
+ }
+ }
+
+ if (inst_with_repo && !inst_with_repo.resolvable()->licenseToConfirm().empty())
+ {
+ cout << _("EULA") << ":" << endl;
+
+ const string & licenseText =
+ inst_with_repo.resolvable()->licenseToConfirm();
+ if (licenseText.find("DT:Rich")==licenseText.npos)
+ cout << licenseText;
+ else
+ cout << processRichText(licenseText);
+ cout << endl;
+
+ ++count_installed_eula;
+ }
+ else if (!inst.resolvable()->licenseToConfirm().empty())
+ cout << "look! got an installed-only item and it has EULA! he?" << inst << endl;
+ cout << "-" << endl;
+ }
+ }
+
+ cout << endl << _("SUMMARY") << endl << endl;
+ cout << _("Installed packages: ") << count_installed << endl;
+ cout << _("Installed packages with counterparts in repositories: ") << count_installed_repo << endl;
+ cout << _("Installed packages with EULAs: ") << count_installed_eula << endl;
+
+ cout << str::form("Package licenses (%u):", (unsigned int) unique_licenses.size()) << endl;
+ for_(it, unique_licenses.begin(), unique_licenses.end())
+ cout << "* " << *it << endl;
+}
+
+// ----------------------------------------------------------------------------
+
static SrcPackage::constPtr source_find( const string & arg )
{
/*
*/
bool confirm_licenses(Zypper & zypper);
+/**
+ * Prints a report about licenses and EULAs of installed packages to stdout.
+ */
+void report_licenses(Zypper & zypper);
+
zypp::ResKind string_to_kind (const std::string & skind);
/**