diff options
author | Roger Leigh <rleigh@debian.org> | 2013-05-04 23:22:29 +0100 |
---|---|---|
committer | Roger Leigh <rleigh@debian.org> | 2013-05-04 23:22:29 +0100 |
commit | ef61a2aa84a4913ff5a9d4478767a1e3e6224e7c (patch) | |
tree | eb1a8eaa5c0e7565edd465e5370692503e9175a2 /lib | |
parent | 4ec183f4fa454c8ddbe41e306ab9ba12e098e098 (diff) | |
download | schroot-ef61a2aa84a4913ff5a9d4478767a1e3e6224e7c.tar.gz |
lib: Sources use namespace scoping
Enclose in namespace as for all other sources.
Diffstat (limited to 'lib')
52 files changed, 4952 insertions, 4920 deletions
diff --git a/lib/bin-common/main.cc b/lib/bin-common/main.cc index 17ae2ef7..1e2df2ab 100644 --- a/lib/bin-common/main.cc +++ b/lib/bin-common/main.cc @@ -36,100 +36,104 @@ using std::endl; using boost::format; using sbuild::_; -using namespace bin_common; - -main::main (std::string const& program_name, - std::string const& program_usage, - options::ptr const& program_options, - bool use_syslog): - program_name(program_name), - program_usage(program_usage), - program_options(program_options), - use_syslog(use_syslog) -{ -} - -main::~main () -{ -} - -void -main::action_version (std::ostream& stream) -{ - // TRANSLATORS: %1% = program name - // TRANSLATORS: %2% = program version - // TRANSLATORS: %3% = release date - format fmtr(_("%1% (Debian sbuild) %2% (%3%)")); - fmtr % this->program_name % VERSION % sbuild::gmdate(RELEASE_DATE); - - // TRANSLATORS: %1% = copyright year (start) - // TRANSLATORS: %2% = copyright year (end) - format fmtc(_("Copyright © %1%–%2% Roger Leigh")); - fmtc % "2004" % "2012"; - - stream << fmtr << '\n' - << _("Written by Roger Leigh") << '\n' << '\n' - << fmtc << '\n' - << _("This is free software; see the source for copying conditions. There is NO\n" - "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n") - << '\n' - << _("Configured features:") << '\n'; - sbuild::feature::print_features(stream); - stream << std::flush; -} -void -main::action_help (std::ostream& stream) +namespace bin_common { - stream - << _("Usage:") << '\n' - << " " << this->program_name << " " - << this->program_usage << std::endl; - - stream << this->program_options->get_visible_options() << std::flush; -} -int -main::run (int argc, - char *argv[]) -{ - try - { - this->program_options->parse(argc, argv); + main::main (std::string const& program_name, + std::string const& program_usage, + options::ptr const& program_options, + bool use_syslog): + program_name(program_name), + program_usage(program_usage), + program_options(program_options), + use_syslog(use_syslog) + { + } + + main::~main () + { + } + + void + main::action_version (std::ostream& stream) + { + // TRANSLATORS: %1% = program name + // TRANSLATORS: %2% = program version + // TRANSLATORS: %3% = release date + format fmtr(_("%1% (Debian sbuild) %2% (%3%)")); + fmtr % this->program_name % VERSION % sbuild::gmdate(RELEASE_DATE); + + // TRANSLATORS: %1% = copyright year (start) + // TRANSLATORS: %2% = copyright year (end) + format fmtc(_("Copyright © %1%–%2% Roger Leigh")); + fmtc % "2004" % "2012"; + + stream << fmtr << '\n' + << _("Written by Roger Leigh") << '\n' << '\n' + << fmtc << '\n' + << _("This is free software; see the source for copying conditions. There is NO\n" + "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n") + << '\n' + << _("Configured features:") << '\n'; + sbuild::feature::print_features(stream); + stream << std::flush; + } + + void + main::action_help (std::ostream& stream) + { + stream + << _("Usage:") << '\n' + << " " << this->program_name << " " + << this->program_usage << std::endl; + + stream << this->program_options->get_visible_options() << std::flush; + } + + int + main::run (int argc, + char *argv[]) + { + try + { + this->program_options->parse(argc, argv); #ifdef SBUILD_DEBUG - sbuild::debug_log_level = sbuild::DEBUG_CRITICAL; + sbuild::debug_log_level = sbuild::DEBUG_CRITICAL; #endif - if (this->use_syslog) - openlog(this->program_name.c_str(), LOG_PID|LOG_NDELAY, LOG_AUTHPRIV); - - int status = run_impl(); - - closelog(); - - return status; - } - catch (std::exception const& e) - { - sbuild::log_exception_error(e); - - try - { - dynamic_cast<bin_common::options::error const&>(e); - sbuild::log_info() - // TRANSLATORS: %1% = program name - << format(_("Run “%1% --help” to list usage example and all available options")) - % argv[0] - << endl; - } - catch (std::bad_cast const& discard) - { - } - - if (this->use_syslog) + if (this->use_syslog) + openlog(this->program_name.c_str(), LOG_PID|LOG_NDELAY, LOG_AUTHPRIV); + + int status = run_impl(); + closelog(); - return EXIT_FAILURE; - } + return status; + } + catch (std::exception const& e) + { + sbuild::log_exception_error(e); + + try + { + dynamic_cast<bin_common::options::error const&>(e); + sbuild::log_info() + // TRANSLATORS: %1% = program name + << format(_("Run “%1% --help” to list usage example and all available options")) + % argv[0] + << endl; + } + catch (std::bad_cast const& discard) + { + } + + if (this->use_syslog) + closelog(); + + return EXIT_FAILURE; + } + } + } diff --git a/lib/bin-common/option-action.cc b/lib/bin-common/option-action.cc index 65dbd46e..06107599 100644 --- a/lib/bin-common/option-action.cc +++ b/lib/bin-common/option-action.cc @@ -32,67 +32,70 @@ using std::endl; using boost::format; using sbuild::_; namespace opt = boost::program_options; -using namespace bin_common; -option_action::option_action (): - default_action(), - current_action(), - actions() +namespace bin_common { -} -option_action::~option_action () -{ -} - -void -option_action::add (action_type const& action) -{ - this->actions.insert(action); -} + option_action::option_action (): + default_action(), + current_action(), + actions() + { + } -option_action::action_type const& -option_action::get_default () -{ - return this->default_action; -} + option_action::~option_action () + { + } -void -option_action::set_default (action_type const& action) -{ - if (valid(action)) - this->default_action = action; - else - throw bin_common::options::error((format(_("%1%: invalid action")) % action).str()); -} + void + option_action::add (action_type const& action) + { + this->actions.insert(action); + } -option_action::action_type const& -option_action::get () -{ - if (this->current_action != "") - return this->current_action; - else + option_action::action_type const& + option_action::get_default () + { return this->default_action; -} + } -void -option_action::set (action_type const& action) -{ - if (valid(action)) - { - if (this->current_action == "") - this->current_action = action; - else - throw bin_common::options::error - (_("Only one action may be specified")); - } - else - throw bin_common::options::error((format(_("%1%: invalid action")) % action).str()); -} + void + option_action::set_default (action_type const& action) + { + if (valid(action)) + this->default_action = action; + else + throw bin_common::options::error((format(_("%1%: invalid action")) % action).str()); + } -bool -option_action::valid (action_type const& action) -{ - return this->actions.find(action) != this->actions.end(); -} + option_action::action_type const& + option_action::get () + { + if (this->current_action != "") + return this->current_action; + else + return this->default_action; + } + + void + option_action::set (action_type const& action) + { + if (valid(action)) + { + if (this->current_action == "") + this->current_action = action; + else + throw bin_common::options::error + (_("Only one action may be specified")); + } + else + throw bin_common::options::error((format(_("%1%: invalid action")) % action).str()); + } + bool + option_action::valid (action_type const& action) + { + return this->actions.find(action) != this->actions.end(); + } + +} diff --git a/lib/bin-common/options.cc b/lib/bin-common/options.cc index 26af2662..6c5e3977 100644 --- a/lib/bin-common/options.cc +++ b/lib/bin-common/options.cc @@ -33,138 +33,142 @@ using std::endl; using boost::format; using sbuild::_; namespace opt = boost::program_options; -using namespace bin_common; - -/// Display program help. -const options::action_type options::ACTION_HELP ("help"); -/// Display program version. -const options::action_type options::ACTION_VERSION ("version"); - -options::options (): - action(), - quiet(false), - verbose(false), - actions(_("Actions")), - general(_("General options")), - hidden(_("Hidden options")), - positional(), - visible(), - global(), - vm() -{ -} - -options::~options () -{ -} - -boost::program_options::options_description const& -options::get_visible_options() const -{ - return this->visible; -} -void -options::parse (int argc, - char *argv[]) +namespace bin_common { - add_options(); - add_option_groups(); - opt::store(opt::command_line_parser(argc, argv). - options(global).positional(positional).run(), vm); - opt::notify(vm); - - check_options(); - check_actions(); -} - -void -options::add_options () -{ - this->action.add(ACTION_HELP); - this->action.add(ACTION_VERSION); - - actions.add_options() - ("help,h", - _("Show help options")) - ("version,V", - _("Print version information")); - - general.add_options() - ("quiet,q", - _("Show less output")) - ("verbose,v", - _("Show more output")); - - hidden.add_options() - ("debug", opt::value<std::string>(&this->debug_level), - _("Enable debugging messages")); -} - -void -options::add_option_groups () -{ + /// Display program help. + const options::action_type options::ACTION_HELP ("help"); + /// Display program version. + const options::action_type options::ACTION_VERSION ("version"); + + options::options (): + action(), + quiet(false), + verbose(false), + actions(_("Actions")), + general(_("General options")), + hidden(_("Hidden options")), + positional(), + visible(), + global(), + vm() + { + } + + options::~options () + { + } + + boost::program_options::options_description const& + options::get_visible_options() const + { + return this->visible; + } + + void + options::parse (int argc, + char *argv[]) + { + add_options(); + add_option_groups(); + + opt::store(opt::command_line_parser(argc, argv). + options(global).positional(positional).run(), vm); + opt::notify(vm); + + check_options(); + check_actions(); + } + + void + options::add_options () + { + this->action.add(ACTION_HELP); + this->action.add(ACTION_VERSION); + + actions.add_options() + ("help,h", + _("Show help options")) + ("version,V", + _("Print version information")); + + general.add_options() + ("quiet,q", + _("Show less output")) + ("verbose,v", + _("Show more output")); + + hidden.add_options() + ("debug", opt::value<std::string>(&this->debug_level), + _("Enable debugging messages")); + } + + void + options::add_option_groups () + { #ifndef BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD - if (!actions.options().empty()) + if (!actions.options().empty()) #else - if (!actions.primary_keys().empty()) + if (!actions.primary_keys().empty()) #endif - { - visible.add(actions); - global.add(actions); - } + { + visible.add(actions); + global.add(actions); + } #ifndef BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD - if (!general.options().empty()) + if (!general.options().empty()) #else - if (!general.primary_keys().empty()) + if (!general.primary_keys().empty()) #endif - { - visible.add(general); - global.add(general); - } + { + visible.add(general); + global.add(general); + } #ifndef BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD - if (!hidden.options().empty()) + if (!hidden.options().empty()) #else - if (!hidden.primary_keys().empty()) + if (!hidden.primary_keys().empty()) #endif - global.add(hidden); -} + global.add(hidden); + } -void -options::check_options () -{ - if (vm.count("help")) - this->action = ACTION_HELP; - - if (vm.count("version")) - this->action = ACTION_VERSION; - - if (vm.count("quiet")) - this->quiet = true; - if (vm.count("verbose")) - this->verbose = true; - - if (vm.count("debug")) - { - if (this->debug_level == "none") - sbuild::debug_log_level = sbuild::DEBUG_NONE; - else if (this->debug_level == "notice") - sbuild::debug_log_level = sbuild::DEBUG_NOTICE; - else if (this->debug_level == "info") - sbuild::debug_log_level = sbuild::DEBUG_INFO; - else if (this->debug_level == "warning") - sbuild::debug_log_level = sbuild::DEBUG_WARNING; - else if (this->debug_level == "critical") - sbuild::debug_log_level = sbuild::DEBUG_CRITICAL; - else - throw error(_("Invalid debug level")); - } - else - sbuild::debug_log_level = sbuild::DEBUG_NONE; -} + void + options::check_options () + { + if (vm.count("help")) + this->action = ACTION_HELP; + + if (vm.count("version")) + this->action = ACTION_VERSION; + + if (vm.count("quiet")) + this->quiet = true; + if (vm.count("verbose")) + this->verbose = true; + + if (vm.count("debug")) + { + if (this->debug_level == "none") + sbuild::debug_log_level = sbuild::DEBUG_NONE; + else if (this->debug_level == "notice") + sbuild::debug_log_level = sbuild::DEBUG_NOTICE; + else if (this->debug_level == "info") + sbuild::debug_log_level = sbuild::DEBUG_INFO; + else if (this->debug_level == "warning") + sbuild::debug_log_level = sbuild::DEBUG_WARNING; + else if (this->debug_level == "critical") + sbuild::debug_log_level = sbuild::DEBUG_CRITICAL; + else + throw error(_("Invalid debug level")); + } + else + sbuild::debug_log_level = sbuild::DEBUG_NONE; + } + + void + options::check_actions () + { + } -void -options::check_actions () -{ } diff --git a/lib/dchroot-common/main.cc b/lib/dchroot-common/main.cc index cc789cd1..a0e3e856 100644 --- a/lib/dchroot-common/main.cc +++ b/lib/dchroot-common/main.cc @@ -36,21 +36,25 @@ using std::endl; using boost::format; using sbuild::_; -using namespace dchroot_common; -main::main (std::string const& program_name, - std::string const& program_usage, - schroot_common::options::ptr& options): - schroot_common::main(program_name, program_usage, options, true) +namespace dchroot_common { -} -main::~main () -{ -} + main::main (std::string const& program_name, + std::string const& program_usage, + schroot_common::options::ptr& options): + schroot_common::main(program_name, program_usage, options, true) + { + } + + main::~main () + { + } + + void + main::action_list () + { + this->config->print_chroot_list_simple(std::cout); + } -void -main::action_list () -{ - this->config->print_chroot_list_simple(std::cout); } diff --git a/lib/dchroot-common/session.cc b/lib/dchroot-common/session.cc index adbfdb7d..992d0a4c 100644 --- a/lib/dchroot-common/session.cc +++ b/lib/dchroot-common/session.cc @@ -37,34 +37,38 @@ using std::cout; using std::endl; using sbuild::_; using boost::format; -using namespace dchroot_common; -session::session (std::string const& service, - operation operation, - sbuild::session::chroot_list const& chroots): - sbuild::session(service, operation, chroots) +namespace dchroot_common { -} -session::~session () -{ -} + session::session (std::string const& service, + operation operation, + sbuild::session::chroot_list const& chroots): + sbuild::session(service, operation, chroots) + { + } -void -session::run_impl () -{ - if (get_auth()->get_ruid() != get_auth()->get_uid()) - throw error(get_auth()->get_ruser(), get_auth()->get_user(), USER_SWITCH, - _("dchroot session restriction")); + session::~session () + { + } - sbuild::session::run_impl(); -} + void + session::run_impl () + { + if (get_auth()->get_ruid() != get_auth()->get_uid()) + throw error(get_auth()->get_ruser(), get_auth()->get_user(), USER_SWITCH, + _("dchroot session restriction")); + + sbuild::session::run_impl(); + } + + sbuild::string_list + session::get_command_directories (sbuild::chroot::chroot::ptr& session_chroot, + sbuild::environment const& env) const + { + // dchroot does not treat logins differently from commands with + // respect to the cwd inside the chroot. + return get_login_directories(session_chroot, env); + } -sbuild::string_list -session::get_command_directories (sbuild::chroot::chroot::ptr& session_chroot, - sbuild::environment const& env) const -{ - // dchroot does not treat logins differently from commands with - // respect to the cwd inside the chroot. - return get_login_directories(session_chroot, env); } diff --git a/lib/sbuild/auth/auth.cc b/lib/sbuild/auth/auth.cc index 2083d019..46911310 100644 --- a/lib/sbuild/auth/auth.cc +++ b/lib/sbuild/auth/auth.cc @@ -36,7 +36,6 @@ using std::cerr; using std::endl; using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/auth/deny.cc b/lib/sbuild/auth/deny.cc index e7e81d30..6eae07fd 100644 --- a/lib/sbuild/auth/deny.cc +++ b/lib/sbuild/auth/deny.cc @@ -34,7 +34,6 @@ using std::cerr; using std::endl; using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/auth/pam-conv-tty.cc b/lib/sbuild/auth/pam-conv-tty.cc index a139cbbb..614462da 100644 --- a/lib/sbuild/auth/pam-conv-tty.cc +++ b/lib/sbuild/auth/pam-conv-tty.cc @@ -32,7 +32,6 @@ using std::endl; using boost::format; -using namespace sbuild; namespace { diff --git a/lib/sbuild/auth/pam-conv.cc b/lib/sbuild/auth/pam-conv.cc index d085b892..019aa29c 100644 --- a/lib/sbuild/auth/pam-conv.cc +++ b/lib/sbuild/auth/pam-conv.cc @@ -20,8 +20,6 @@ #include <sbuild/auth/pam-conv.h> -using namespace sbuild; - namespace sbuild { namespace auth diff --git a/lib/sbuild/auth/pam-message.cc b/lib/sbuild/auth/pam-message.cc index d9278ba5..d88e5deb 100644 --- a/lib/sbuild/auth/pam-message.cc +++ b/lib/sbuild/auth/pam-message.cc @@ -20,8 +20,6 @@ #include <sbuild/auth/pam-message.h> -using namespace sbuild; - namespace sbuild { namespace auth diff --git a/lib/sbuild/auth/pam.cc b/lib/sbuild/auth/pam.cc index 9a7665c4..6fcc0aa0 100644 --- a/lib/sbuild/auth/pam.cc +++ b/lib/sbuild/auth/pam.cc @@ -36,7 +36,6 @@ using std::cerr; using std::endl; using boost::format; -using namespace sbuild; #if defined(__LINUX_PAM__) #define PAM_TEXT_DOMAIN "Linux-PAM" @@ -44,99 +43,99 @@ using namespace sbuild; #define PAM_TEXT_DOMAIN "SUNW_OST_SYSOSPAM" #endif -namespace +namespace sbuild { - - /* This is the glue to link PAM user interaction with pam_conv. */ - int - pam_conv_hook (int num_msg, - const struct pam_message **msgm, - struct pam_response **response, - void *appdata_ptr) + namespace auth { - log_debug(DEBUG_NOTICE) << "PAM conversation hook started" << endl; - - try - { - if (appdata_ptr == 0) - return PAM_CONV_ERR; - auth::pam_conv *conv = static_cast<auth::pam_conv *>(appdata_ptr); - assert (conv != 0); + namespace + { - log_debug(DEBUG_INFO) << "Found PAM conversation handler" << endl; + /* This is the glue to link PAM user interaction with pam_conv. */ + int + pam_conv_hook (int num_msg, + const struct ::pam_message **msgm, + struct ::pam_response **response, + void *appdata_ptr) + { + log_debug(DEBUG_NOTICE) << "PAM conversation hook started" << endl; - /* Construct a message vector */ - auth::pam_conv::message_list messages; - for (int i = 0; i < num_msg; ++i) + try { - const struct ::pam_message *source = msgm[i]; + if (appdata_ptr == 0) + return PAM_CONV_ERR; + + pam_conv *conv = static_cast<pam_conv *>(appdata_ptr); + assert (conv != 0); - auth::pam_message - message(static_cast<auth::pam_message::message_type>(source->msg_style), - source->msg); + log_debug(DEBUG_INFO) << "Found PAM conversation handler" << endl; - /* Replace PAM prompt */ - if (message.message == dgettext(PAM_TEXT_DOMAIN, "Password: ") || - message.message == dgettext(PAM_TEXT_DOMAIN, "Password:")) + /* Construct a message vector */ + pam_conv::message_list messages; + for (int i = 0; i < num_msg; ++i) { - std::string user = "unknown"; // Set in case auth is void - std::shared_ptr<auth::pam> auth = conv->get_auth(); - assert(auth && auth.get() != 0); // Check auth is not void - if (auth && auth.get() != 0) - user = auth->get_user(); - format fmt(_("[schroot] password for %1%: ")); - fmt % user; - message.message = fmt.str(); + const struct ::pam_message *source = msgm[i]; + + pam_message + message(static_cast<pam_message::message_type>(source->msg_style), + source->msg); + + /* Replace PAM prompt */ + if (message.message == dgettext(PAM_TEXT_DOMAIN, "Password: ") || + message.message == dgettext(PAM_TEXT_DOMAIN, "Password:")) + { + std::string user = "unknown"; // Set in case auth is void + std::shared_ptr<pam> auth = conv->get_auth(); + assert(auth && auth.get() != 0); // Check auth is not void + if (auth && auth.get() != 0) + user = auth->get_user(); + format fmt(_("[schroot] password for %1%: ")); + fmt % user; + message.message = fmt.str(); + } + + messages.push_back(message); } - messages.push_back(message); - } + log_debug(DEBUG_INFO) << "Set PAM conversation message vector" << endl; - log_debug(DEBUG_INFO) << "Set PAM conversation message vector" << endl; + /* Do the conversation; an exception will be thrown on failure */ + conv->conversation(messages); - /* Do the conversation; an exception will be thrown on failure */ - conv->conversation(messages); + log_debug(DEBUG_INFO) << "Run PAM conversation" << endl; - log_debug(DEBUG_INFO) << "Run PAM conversation" << endl; + /* Copy response into **reponse */ + struct pam_response *reply = + static_cast<struct pam_response *> + (malloc(sizeof(struct pam_response) * num_msg)); - /* Copy response into **reponse */ - struct pam_response *reply = - static_cast<struct pam_response *> - (malloc(sizeof(struct pam_response) * num_msg)); + for (int i = 0; i < num_msg; ++i) + { + reply[i].resp_retcode = 0; + reply[i].resp = strdup(messages[i].response.c_str()); + } - for (int i = 0; i < num_msg; ++i) - { - reply[i].resp_retcode = 0; - reply[i].resp = strdup(messages[i].response.c_str()); - } + *response = reply; + reply = 0; - *response = reply; - reply = 0; + log_debug(DEBUG_INFO) << "Set PAM conversation reply" << endl; - log_debug(DEBUG_INFO) << "Set PAM conversation reply" << endl; + return PAM_SUCCESS; + } + catch (std::exception const& e) + { + log_exception_error(e); + } + catch (...) + { + log_error() << _("An unknown exception occurred") << endl; + } - return PAM_SUCCESS; - } - catch (std::exception const& e) - { - log_exception_error(e); + return PAM_CONV_ERR; } - catch (...) - { - log_error() << _("An unknown exception occurred") << endl; - } - - return PAM_CONV_ERR; - } - sbuild::feature feature_pam("PAM", N_("Pluggable Authentication Modules")); -} - -namespace sbuild -{ - namespace auth - { + sbuild::feature feature_pam("PAM", N_("Pluggable Authentication Modules")); + } pam::pam (std::string const& service_name): auth(service_name), diff --git a/lib/sbuild/chroot/config.cc b/lib/sbuild/chroot/config.cc index 1020bbe6..1bccaf65 100644 --- a/lib/sbuild/chroot/config.cc +++ b/lib/sbuild/chroot/config.cc @@ -42,25 +42,24 @@ using std::endl; using boost::format; -using namespace sbuild; - -namespace -{ - - bool - chroot_alphasort (chroot::chroot::ptr const& c1, - chroot::chroot::ptr const& c2) - { - return c1->get_name() < c2->get_name(); - } - -} namespace sbuild { namespace chroot { + namespace + { + + bool + chroot_alphasort (chroot::chroot::ptr const& c1, + chroot::chroot::ptr const& c2) + { + return c1->get_name() < c2->get_name(); + } + + } + template<> error<config::error_code>::map_type error<config::error_code>::error_strings = diff --git a/lib/sbuild/chroot/facet/block-device-base.cc b/lib/sbuild/chroot/facet/block-device-base.cc index d3ca94b2..a0388717 100644 --- a/lib/sbuild/chroot/facet/block-device-base.cc +++ b/lib/sbuild/chroot/facet/block-device-base.cc @@ -28,8 +28,6 @@ #include <cstring> #include <iostream> -using namespace sbuild; - namespace sbuild { namespace chroot diff --git a/lib/sbuild/chroot/facet/block-device.cc b/lib/sbuild/chroot/facet/block-device.cc index f3427280..166e33d0 100644 --- a/lib/sbuild/chroot/facet/block-device.cc +++ b/lib/sbuild/chroot/facet/block-device.cc @@ -37,7 +37,6 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/btrfs-snapshot.cc b/lib/sbuild/chroot/facet/btrfs-snapshot.cc index afa3fbb7..170da0ca 100644 --- a/lib/sbuild/chroot/facet/btrfs-snapshot.cc +++ b/lib/sbuild/chroot/facet/btrfs-snapshot.cc @@ -34,7 +34,6 @@ using std::endl; using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/custom.cc b/lib/sbuild/chroot/facet/custom.cc index 97f81529..9bccd220 100644 --- a/lib/sbuild/chroot/facet/custom.cc +++ b/lib/sbuild/chroot/facet/custom.cc @@ -33,7 +33,6 @@ using std::endl; using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/directory-base.cc b/lib/sbuild/chroot/facet/directory-base.cc index 2240550e..11a44080 100644 --- a/lib/sbuild/chroot/facet/directory-base.cc +++ b/lib/sbuild/chroot/facet/directory-base.cc @@ -27,8 +27,6 @@ #include <cstring> #include <iostream> -using namespace sbuild; - namespace sbuild { namespace chroot diff --git a/lib/sbuild/chroot/facet/directory.cc b/lib/sbuild/chroot/facet/directory.cc index 5f87a8ef..90bd5b66 100644 --- a/lib/sbuild/chroot/facet/directory.cc +++ b/lib/sbuild/chroot/facet/directory.cc @@ -33,7 +33,6 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/facet.cc b/lib/sbuild/chroot/facet/facet.cc index b905dbfc..4c94feab 100644 --- a/lib/sbuild/chroot/facet/facet.cc +++ b/lib/sbuild/chroot/facet/facet.cc @@ -24,7 +24,6 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/file.cc b/lib/sbuild/chroot/facet/file.cc index 4999415d..3f45746c 100644 --- a/lib/sbuild/chroot/facet/file.cc +++ b/lib/sbuild/chroot/facet/file.cc @@ -33,7 +33,6 @@ using std::endl; using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/fsunion.cc b/lib/sbuild/chroot/facet/fsunion.cc index bb154a5e..3db40e5b 100644 --- a/lib/sbuild/chroot/facet/fsunion.cc +++ b/lib/sbuild/chroot/facet/fsunion.cc @@ -30,14 +30,6 @@ using boost::format; using std::endl; -using namespace sbuild; - -namespace -{ - - sbuild::feature feature_union("UNION", N_("Support for filesystem unioning")); - -} namespace sbuild { @@ -49,6 +41,8 @@ namespace sbuild namespace { + feature feature_union("UNION", N_("Support for filesystem unioning")); + factory::facet_info fsunion_info = { "union", diff --git a/lib/sbuild/chroot/facet/loopback.cc b/lib/sbuild/chroot/facet/loopback.cc index fb23e278..73a7a96d 100644 --- a/lib/sbuild/chroot/facet/loopback.cc +++ b/lib/sbuild/chroot/facet/loopback.cc @@ -33,7 +33,6 @@ using std::endl; using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/lvm-snapshot.cc b/lib/sbuild/chroot/facet/lvm-snapshot.cc index c138a869..113f3d69 100644 --- a/lib/sbuild/chroot/facet/lvm-snapshot.cc +++ b/lib/sbuild/chroot/facet/lvm-snapshot.cc @@ -34,7 +34,6 @@ using std::endl; using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/mountable.cc b/lib/sbuild/chroot/facet/mountable.cc index 5ef62a78..fce24281 100644 --- a/lib/sbuild/chroot/facet/mountable.cc +++ b/lib/sbuild/chroot/facet/mountable.cc @@ -29,7 +29,6 @@ using boost::format; using std::endl; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/personality.cc b/lib/sbuild/chroot/facet/personality.cc index 7ba38c75..0936ad34 100644 --- a/lib/sbuild/chroot/facet/personality.cc +++ b/lib/sbuild/chroot/facet/personality.cc @@ -25,7 +25,6 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/plain.cc b/lib/sbuild/chroot/facet/plain.cc index ff452b56..b8cc9eae 100644 --- a/lib/sbuild/chroot/facet/plain.cc +++ b/lib/sbuild/chroot/facet/plain.cc @@ -31,7 +31,6 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/session-clonable.cc b/lib/sbuild/chroot/facet/session-clonable.cc index cb6b97e1..35924385 100644 --- a/lib/sbuild/chroot/facet/session-clonable.cc +++ b/lib/sbuild/chroot/facet/session-clonable.cc @@ -33,7 +33,6 @@ using boost::format; using std::endl; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/session.cc b/lib/sbuild/chroot/facet/session.cc index 0e13ff29..e45dbf39 100644 --- a/lib/sbuild/chroot/facet/session.cc +++ b/lib/sbuild/chroot/facet/session.cc @@ -37,7 +37,6 @@ using boost::format; using std::endl; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/source-clonable.cc b/lib/sbuild/chroot/facet/source-clonable.cc index ff70e9b5..7f3f5716 100644 --- a/lib/sbuild/chroot/facet/source-clonable.cc +++ b/lib/sbuild/chroot/facet/source-clonable.cc @@ -31,7 +31,6 @@ using boost::format; using std::endl; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/source.cc b/lib/sbuild/chroot/facet/source.cc index 638f3d0f..e5ade412 100644 --- a/lib/sbuild/chroot/facet/source.cc +++ b/lib/sbuild/chroot/facet/source.cc @@ -26,7 +26,6 @@ using boost::format; using std::endl; -using namespace sbuild; namespace sbuild { diff --git a/lib/sbuild/chroot/facet/storage.cc b/lib/sbuild/chroot/facet/storage.cc index a54167e7..e47d513e 100644 --- a/lib/sbuild/chroot/facet/storage.cc +++ b/lib/sbuild/chroot/facet/storage.cc @@ -20,8 +20,6 @@ #include <sbuild/chroot/facet/storage.h> -using namespace sbuild; - namespace sbuild { namespace chroot diff --git a/lib/sbuild/chroot/facet/unshare.cc b/lib/sbuild/chroot/facet/unshare.cc index 9d421a51..bd6184b3 100644 --- a/lib/sbuild/chroot/facet/unshare.cc +++ b/lib/sbuild/chroot/facet/unshare.cc @@ -30,18 +30,7 @@ #endif // SBUILD_FEATURE_UNSHARE using boost::format; -using namespace sbuild; -namespace -{ - -#ifdef SBUILD_FEATURE_UNSHARE - sbuild::feature feature_unshare - ("UNSHARE", - N_("Linux dissassociation of shared execution context")); -#endif - -} namespace sbuild { @@ -50,9 +39,16 @@ namespace sbuild namespace facet { + namespace { +#ifdef SBUILD_FEATURE_UNSHARE + feature feature_unshare + ("UNSHARE", + N_("Linux dissassociation of shared execution context")); +#endif + factory::facet_info unshare_info = { "unshare", diff --git a/lib/sbuild/chroot/facet/userdata.cc b/lib/sbuild/chroot/facet/userdata.cc index b1c30a04..95182ecd 100644 --- a/lib/sbuild/chroot/facet/userdata.cc +++ b/lib/sbuild/chroot/facet/userdata.cc @@ -28,46 +28,6 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; - -namespace -{ - - bool - validate_keyname(std::string const& key) - { - // Valid names consist of one (or more) namespaces which consist - // of [a-z][a-z0-9] followed by a . (namespace separator). The - // key name following the separator is [a-z][a-z0-9-]. When - // converted to an environment variable, all alphabet characters - // are uppercased, and all periods and hyphens converted to - // underscores. - static sbuild::regex permitted("^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]*$"); - - // These would permit clashes with existing setup environment - // variables, and potentially security issues if they were - // user-settable. - static sbuild::regex reserved("^(((auth|chroot|host|libexec|mount|session|status|sysconf)\\..*)|setup.data.dir)$"); - - return regex_search(key, permitted) && !regex_search(key, reserved); - } - - std::string - envname(std::string const& key) - { - std::string ret(key); - - static const std::ctype<char>& ct = std::use_facet<std::ctype<char> >(std::locale::classic()); - for (auto& chr : ret) - { - chr = ct.toupper(chr); - if (chr == '-' || chr == '.') - chr = '_'; - } - return ret; - } - -} namespace sbuild { @@ -79,6 +39,40 @@ namespace sbuild namespace { + bool + validate_keyname(std::string const& key) + { + // Valid names consist of one (or more) namespaces which consist + // of [a-z][a-z0-9] followed by a . (namespace separator). The + // key name following the separator is [a-z][a-z0-9-]. When + // converted to an environment variable, all alphabet characters + // are uppercased, and all periods and hyphens converted to + // underscores. + static sbuild::regex permitted("^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]*$"); + + // These would permit clashes with existing setup environment + // variables, and potentially security issues if they were + // user-settable. + static sbuild::regex reserved("^(((auth|chroot|host|libexec|mount|session|status|sysconf)\\..*)|setup.data.dir)$"); + + return regex_search(key, permitted) && !regex_search(key, reserved); + } + + std::string + envname(std::string const& key) + { + std::string ret(key); + + static const std::ctype<char>& ct = std::use_facet<std::ctype<char> >(std::locale::classic()); + for (auto& chr : ret) + { + chr = ct.toupper(chr); + if (chr == '-' || chr == '.') + chr = '_'; + } + return ret; + } + factory::facet_info userdata_info = { "userdata", diff --git a/lib/sbuild/ctty.cc b/lib/sbuild/ctty.cc index e707b1b1..b7c12a45 100644 --- a/lib/sbuild/ctty.cc +++ b/lib/sbuild/ctty.cc @@ -28,93 +28,96 @@ #include <fcntl.h> #include <unistd.h> -using namespace sbuild; - -namespace +namespace sbuild { - /** - * Set close-on-exec flag. An error will be thrown on failure. - * - * @param fd the file descriptor to set. - */ - void - set_cloexec (int fd) + namespace { - int flags = fcntl(fd, F_GETFD); - flags |= FD_CLOEXEC; - if (fcntl(fd, F_SETFD, flags) < 0) - throw ctty_error(CTTY_CLOEXEC, strerror(errno)); - } - /** - * Open the controlling terminal and return its file descriptor. - * - * @returns the CTTY fd, or -1 on failure. - */ - int - open_ctty () - { - int ctty = open("/dev/tty", O_RDWR|O_NOCTTY); - if (ctty >= 0) - { - set_cloexec(ctty); - } - else - { - ctty = -1; - } - - return ctty; + /** + * Set close-on-exec flag. An error will be thrown on failure. + * + * @param fd the file descriptor to set. + */ + void + set_cloexec (int fd) + { + int flags = fcntl(fd, F_GETFD); + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) < 0) + throw ctty_error(CTTY_CLOEXEC, strerror(errno)); + } + + /** + * Open the controlling terminal and return its file descriptor. + * + * @returns the CTTY fd, or -1 on failure. + */ + int + open_ctty () + { + int ctty = open("/dev/tty", O_RDWR|O_NOCTTY); + if (ctty >= 0) + { + set_cloexec(ctty); + } + else + { + ctty = -1; + } + + return ctty; + } + } -} + template<> + error<ctty_error_code>::map_type + error<ctty_error_code>::error_strings = + { + {sbuild::CTTY_CLOEXEC, N_("The controlling terminal close-on-execute flag could not be set")}, + {sbuild::CTTY_DUP, N_("The controlling terminal file descriptor could not be duplicated")} + }; + + const int CTTY_FILENO(open_ctty()); -template<> -error<ctty_error_code>::map_type -error<ctty_error_code>::error_strings = + namespace { - {CTTY_CLOEXEC, N_("The controlling terminal close-on-execute flag could not be set")}, - {CTTY_DUP, N_("The controlling terminal file descriptor could not be duplicated")} - }; -const int sbuild::CTTY_FILENO(open_ctty()); + /** + * Get the file descriptor for cttybuf. An error will be thrown on + * failure. + * + * @returns the CTTY_FILENO file descriptor if there is a CTTY, or a + * duplicated file descriptor for stdin otherwise. + */ + int + cttybuf_fd () + { + int ctty = CTTY_FILENO; -namespace -{ + if (ctty < 0) + { + ctty = dup(STDIN_FILENO); - /** - * Get the file descriptor for cttybuf. An error will be thrown on - * failure. - * - * @returns the CTTY_FILENO file descriptor if there is a CTTY, or a - * duplicated file descriptor for stdin otherwise. - */ - int - cttybuf_fd () - { - int ctty = CTTY_FILENO; + if (ctty < 0) + throw ctty_error(CTTY_DUP, strerror(errno)); - if (ctty < 0) - { - ctty = dup(STDIN_FILENO); + set_cloexec(ctty); + } - if (ctty < 0) - throw ctty_error(CTTY_DUP, strerror(errno)); + return ctty; + } - set_cloexec(ctty); - } + /// A streambuf for cctty. + // boost::iostreams::file_descriptor cttybuf(cttybuf_fd(), close_handle); - return ctty; } - /// A streambuf for cctty. - // boost::iostreams::file_descriptor cttybuf(cttybuf_fd(), close_handle); - -} - #ifdef BOOST_IOSTREAMS_CLOSE_HANDLE_OLD -fdstream sbuild::cctty(cttybuf_fd(), true); + fdstream cctty(cttybuf_fd(), true); #else -fdstream sbuild::cctty(cttybuf_fd(), boost::iostreams::close_handle); + fdstream cctty(cttybuf_fd(), boost::iostreams::close_handle); #endif + +} diff --git a/lib/sbuild/environment.cc b/lib/sbuild/environment.cc index 8754763d..cd7f5599 100644 --- a/lib/sbuild/environment.cc +++ b/lib/sbuild/environment.cc @@ -23,147 +23,151 @@ #include <cstring> using boost::format; -using namespace sbuild; -environment::environment (): - std::map<std::string,std::string>(), - filter() +namespace sbuild { -} - -environment::environment (char **environment): - std::map<std::string,std::string>() -{ - add(environment); -} - -environment::~environment () -{ -} -void -environment::set_filter (regex const& filter) -{ - this->filter = filter; -} + environment::environment (): + std::map<std::string,std::string>(), + filter() + { + } + + environment::environment (char **environment): + std::map<std::string,std::string>() + { + add(environment); + } + + environment::~environment () + { + } + + void + environment::set_filter (regex const& filter) + { + this->filter = filter; + } + + regex const& + environment::get_filter () const + { + return this->filter; + } + + void + environment::add (char **environment) + { + if (environment) + { + for (char **ev = environment; ev != 0 && *ev != 0; ++ev) + add(std::string(*ev)); + } + } + + void + environment::add (environment const& environment) + { + for (const auto& env : environment) + add(env); + } + + void + environment::add (std::string const& value) + { + std::string::size_type pos = value.find('='); + if (pos != std::string::npos && pos != 0) + { + std::string key = value.substr(0, pos); + std::string val; + if (pos < value.length()) + val = value.substr(pos + 1); + add(std::make_pair(key, val)); + } + else + { + add(std::make_pair(value, std::string())); + } + } + + void + environment::add (value_type const& value) + { + remove(value); + if (!value.first.empty() && !value.second.empty()) + { + if (this->filter.str().empty() || + !regex_search(value.first, this->filter)) + { + insert(value); + log_debug(DEBUG_NOTICE) << "Inserted into environment: " + << value.first << '=' << value.second + << std::endl; + } + else + log_debug(DEBUG_INFO) << "Filtered from environment: " << value.first + << std::endl; + } + } + + void + environment::remove (char **environment) + { + if (environment) + { + for (char **ev = environment; ev != 0 && *ev != 0; ++ev) + remove(std::string(*ev)); + } + } + + void + environment::remove (environment const& environment) + { + for (const auto& env : environment) + remove(env); + } + + void + environment::remove (std::string const& value) + { + std::string::size_type pos = value.find('='); + if (pos != std::string::npos && pos != 0) + { + std::string key = value.substr(0, pos); + std::string val; + if (pos < value.length()) + val = value.substr(pos + 1); + remove(std::make_pair(key, val)); + } + else + { + remove(std::make_pair(value, std::string())); + } + } + + void + environment::remove (value_type const& value) + { + iterator pos = find(value.first); + if (pos != end()) + erase(pos); + } + + char ** + environment::get_strv () const + { + char **ret = new char *[size() + 1]; + + size_type idx = 0; + for (const_iterator pos = begin(); pos != end(); ++pos, ++idx) + { + std::string envitem = pos->first + "=" + pos->second; + ret[idx] = new char[envitem.length() + 1]; + std::strcpy(ret[idx], envitem.c_str()); + } + ret[size()] = 0; + + return ret; + } -regex const& -environment::get_filter () const -{ - return this->filter; -} - -void -environment::add (char **environment) -{ - if (environment) - { - for (char **ev = environment; ev != 0 && *ev != 0; ++ev) - add(std::string(*ev)); - } -} - -void -environment::add (environment const& environment) -{ - for (const auto& env : environment) - add(env); -} - -void -environment::add (std::string const& value) -{ - std::string::size_type pos = value.find('='); - if (pos != std::string::npos && pos != 0) - { - std::string key = value.substr(0, pos); - std::string val; - if (pos < value.length()) - val = value.substr(pos + 1); - add(std::make_pair(key, val)); - } - else - { - add(std::make_pair(value, std::string())); - } -} - -void -environment::add (value_type const& value) -{ - remove(value); - if (!value.first.empty() && !value.second.empty()) - { - if (this->filter.str().empty() || - !regex_search(value.first, this->filter)) - { - insert(value); - log_debug(DEBUG_NOTICE) << "Inserted into environment: " - << value.first << '=' << value.second - << std::endl; - } - else - log_debug(DEBUG_INFO) << "Filtered from environment: " << value.first - << std::endl; - } -} - -void -environment::remove (char **environment) -{ - if (environment) - { - for (char **ev = environment; ev != 0 && *ev != 0; ++ev) - remove(std::string(*ev)); - } -} - -void -environment::remove (environment const& environment) -{ - for (const auto& env : environment) - remove(env); -} - -void -environment::remove (std::string const& value) -{ - std::string::size_type pos = value.find('='); - if (pos != std::string::npos && pos != 0) - { - std::string key = value.substr(0, pos); - std::string val; - if (pos < value.length()) - val = value.substr(pos + 1); - remove(std::make_pair(key, val)); - } - else - { - remove(std::make_pair(value, std::string())); - } -} - -void -environment::remove (value_type const& value) -{ - iterator pos = find(value.first); - if (pos != end()) - erase(pos); -} - -char ** -environment::get_strv () const -{ - char **ret = new char *[size() + 1]; - - size_type idx = 0; - for (const_iterator pos = begin(); pos != end(); ++pos, ++idx) - { - std::string envitem = pos->first + "=" + pos->second; - ret[idx] = new char[envitem.length() + 1]; - std::strcpy(ret[idx], envitem.c_str()); - } - ret[size()] = 0; - - return ret; } diff --git a/lib/sbuild/feature.cc b/lib/sbuild/feature.cc index 13f53036..d1583e8f 100644 --- a/lib/sbuild/feature.cc +++ b/lib/sbuild/feature.cc @@ -23,33 +23,36 @@ #include <sbuild/feature.h> #include <sbuild/i18n.h> -using namespace sbuild; - -feature::feature(std::string const& feature, - std::string const& description) +namespace sbuild { - registered_features().insert(std::make_pair(feature, description)); -} -feature::~feature() -{ -} + feature::feature(std::string const& feature, + std::string const& description) + { + registered_features().insert(std::make_pair(feature, description)); + } -std::ostream& -feature::print_features(std::ostream& stream) -{ - boost::format fmt(" %1$-12s %2%\n"); + feature::~feature() + { + } - std::map<std::string,std::string>& features = registered_features(); - for (const auto& feature : features) - stream << fmt % feature.first % gettext(feature.second); + std::ostream& + feature::print_features(std::ostream& stream) + { + boost::format fmt(" %1$-12s %2%\n"); - return stream; -} + std::map<std::string,std::string>& features = registered_features(); + for (const auto& feature : features) + stream << fmt % feature.first % gettext(feature.second); + + return stream; + } + + std::map<std::string,std::string>& + feature::registered_features () + { + static std::map<std::string,std::string> features; + return features; + } -std::map<std::string,std::string>& -feature::registered_features () -{ - static std::map<std::string,std::string> features; - return features; } diff --git a/lib/sbuild/format-detail.cc b/lib/sbuild/format-detail.cc index d38ecfea..eda875c7 100644 --- a/lib/sbuild/format-detail.cc +++ b/lib/sbuild/format-detail.cc @@ -24,70 +24,73 @@ #include <boost/format.hpp> -using namespace sbuild; - -format_detail::format_detail (std::string const& title, - std::locale locale): - title(title), - locale(locale), - items() +namespace sbuild { -} -format_detail::~format_detail () -{ -} + format_detail::format_detail (std::string const& title, + std::locale locale): + title(title), + locale(locale), + items() + { + } -format_detail& -format_detail::add (std::string const& name, - std::string const& value) -{ - for (const auto& item : this->items) - { - if (item.first == name) - { - log_debug(DEBUG_WARNING) << "format_detail: name \"" - << name << "\" is already added" - << std::endl; - return *this; - } - } + format_detail::~format_detail () + { + } - this->items.push_back(value_type(name, value)); - log_debug(DEBUG_INFO) << "format_detail: added name \"" - << name << "\"" - << std::endl; + format_detail& + format_detail::add (std::string const& name, + std::string const& value) + { + for (const auto& item : this->items) + { + if (item.first == name) + { + log_debug(DEBUG_WARNING) << "format_detail: name \"" + << name << "\" is already added" + << std::endl; + return *this; + } + } - return *this; -} + this->items.push_back(value_type(name, value)); + log_debug(DEBUG_INFO) << "format_detail: added name \"" + << name << "\"" + << std::endl; -format_detail& -format_detail::add (std::string const& name, - bool value) -{ - const char *desc = 0; - if (value) - desc = _("true"); - else - desc = _("false"); + return *this; + } - return add(name, std::string(desc)); -} + format_detail& + format_detail::add (std::string const& name, + bool value) + { + const char *desc = 0; + if (value) + desc = _("true"); + else + desc = _("false"); -format_detail& -format_detail::add (std::string const& name, - string_list const& value) -{ - return add(name, string_list_to_string(value, " ")); -} + return add(name, std::string(desc)); + } -std::string -format_detail::get_title () const -{ - // TRANSLATORS: %1% = title of section - // TRANSLATORS: Please format the --- as a continuous line, e.g. U+2500 - boost::format fmt(_("─── %1% ───")); - fmt %this->title; + format_detail& + format_detail::add (std::string const& name, + string_list const& value) + { + return add(name, string_list_to_string(value, " ")); + } + + std::string + format_detail::get_title () const + { + // TRANSLATORS: %1% = title of section + // TRANSLATORS: Please format the --- as a continuous line, e.g. U+2500 + boost::format fmt(_("─── %1% ───")); + fmt %this->title; + + return fmt.str(); + } - return fmt.str(); } diff --git a/lib/sbuild/keyfile-reader.cc b/lib/sbuild/keyfile-reader.cc index 237d286a..ec62c596 100644 --- a/lib/sbuild/keyfile-reader.cc +++ b/lib/sbuild/keyfile-reader.cc @@ -22,166 +22,169 @@ #include <sbuild/keyfile-reader.h> -using namespace sbuild; - -keyfile_reader::keyfile_reader(keyfile& store): - store(store), - group(), - group_set(false), - key(), - key_set(false), - value(), - value_set(false), - comment(), - comment_set(false), - line_number(0) -{} - -keyfile_reader::keyfile_reader (keyfile& store, - std::string const& file): - keyfile_reader(store) +namespace sbuild { - std::ifstream fs(file.c_str()); - if (fs) - { - fs.imbue(std::locale::classic()); - read_stream(fs); - } - else - { - throw error(file, keyfile::BAD_FILE); - } -} - -keyfile_reader::keyfile_reader (keyfile& store, - std::istream& stream): - keyfile_reader(store) -{ - read_stream(stream); -} - -keyfile_reader::~keyfile_reader() -{} - -void -keyfile_reader::read_stream(std::istream& stream) -{ - keyfile tmp; - std::string line; - - begin(); - - while (std::getline(stream, line)) - { - parse_line(line); - - // Insert group - if (this->group_set) - { - if (tmp.has_group(this->group)) - throw error(this->line_number, keyfile::DUPLICATE_GROUP, this->group); - else - tmp.set_group(this->group, this->comment, this->line_number); - } - - // Insert item - if (this->key_set && this->value_set) - { - if (tmp.has_key(this->group, this->key)) - throw error(this->line_number, this->group, keyfile::DUPLICATE_KEY, this->key); - else - tmp.set_value(this->group, this->key, this->value, this->comment, this->line_number); - } - } - - end(); - - // TODO: do inserts here as well. - - this->store += tmp; -} -void -keyfile_reader::begin() -{ - line_number = 0; -} + keyfile_reader::keyfile_reader(keyfile& store): + store(store), + group(), + group_set(false), + key(), + key_set(false), + value(), + value_set(false), + comment(), + comment_set(false), + line_number(0) + {} + + keyfile_reader::keyfile_reader (keyfile& store, + std::string const& file): + keyfile_reader(store) + { + std::ifstream fs(file.c_str()); + if (fs) + { + fs.imbue(std::locale::classic()); + read_stream(fs); + } + else + { + throw error(file, keyfile::BAD_FILE); + } + } + + keyfile_reader::keyfile_reader (keyfile& store, + std::istream& stream): + keyfile_reader(store) + { + read_stream(stream); + } + + keyfile_reader::~keyfile_reader() + {} + + void + keyfile_reader::read_stream(std::istream& stream) + { + keyfile tmp; + std::string line; + + begin(); + + while (std::getline(stream, line)) + { + parse_line(line); + + // Insert group + if (this->group_set) + { + if (tmp.has_group(this->group)) + throw error(this->line_number, keyfile::DUPLICATE_GROUP, this->group); + else + tmp.set_group(this->group, this->comment, this->line_number); + } + + // Insert item + if (this->key_set && this->value_set) + { + if (tmp.has_key(this->group, this->key)) + throw error(this->line_number, this->group, keyfile::DUPLICATE_KEY, this->key); + else + tmp.set_value(this->group, this->key, this->value, this->comment, this->line_number); + } + } + + end(); + + // TODO: do inserts here as well. + + this->store += tmp; + } + + void + keyfile_reader::begin() + { + line_number = 0; + } + + void + keyfile_reader::parse_line (std::string const& line) + { + if (comment_set == true) + { + comment.clear(); + comment_set = false; + } + if (group_set == true) + { + // The group isn't cleared + group_set = false; + } + if (key_set == true) + { + key.clear(); + key_set = false; + } + if (value_set == true) + { + value.clear(); + value_set = false; + } + + if (line.length() == 0) + { + // Empty line; do nothing. + } + else if (line[0] == '#') // Comment line + { + if (!comment.empty()) + comment += '\n'; + comment += line.substr(1); + } + else if (line[0] == '[') // Group + { + std::string::size_type fpos = line.find_first_of(']'); + std::string::size_type lpos = line.find_last_of(']'); + if (fpos == std::string::npos || lpos == std::string::npos || + fpos != lpos) + throw error(line_number, keyfile::INVALID_GROUP, line); + group = line.substr(1, fpos - 1); + + if (group.length() == 0) + throw error(line_number, keyfile::INVALID_GROUP, line); + + comment_set = true; + group_set = true; + } + else // Item + { + std::string::size_type pos = line.find_first_of('='); + if (pos == std::string::npos) + throw error(line_number, keyfile::INVALID_LINE, line); + if (pos == 0) + throw error(line_number, keyfile::NO_KEY, line); + key = line.substr(0, pos); + if (pos == line.length() - 1) + value = ""; + else + value = line.substr(pos + 1); + + // No group specified + if (group.empty()) + throw error(line_number, keyfile::NO_GROUP, line); + + comment_set = true; + key_set = true; + value_set = true; + } + + ++line_number; + } + + void + keyfile_reader::end() + { + } -void -keyfile_reader::parse_line (std::string const& line) -{ - if (comment_set == true) - { - comment.clear(); - comment_set = false; - } - if (group_set == true) - { - // The group isn't cleared - group_set = false; - } - if (key_set == true) - { - key.clear(); - key_set = false; - } - if (value_set == true) - { - value.clear(); - value_set = false; - } - - if (line.length() == 0) - { - // Empty line; do nothing. - } - else if (line[0] == '#') // Comment line - { - if (!comment.empty()) - comment += '\n'; - comment += line.substr(1); - } - else if (line[0] == '[') // Group - { - std::string::size_type fpos = line.find_first_of(']'); - std::string::size_type lpos = line.find_last_of(']'); - if (fpos == std::string::npos || lpos == std::string::npos || - fpos != lpos) - throw error(line_number, keyfile::INVALID_GROUP, line); - group = line.substr(1, fpos - 1); - - if (group.length() == 0) - throw error(line_number, keyfile::INVALID_GROUP, line); - - comment_set = true; - group_set = true; - } - else // Item - { - std::string::size_type pos = line.find_first_of('='); - if (pos == std::string::npos) - throw error(line_number, keyfile::INVALID_LINE, line); - if (pos == 0) - throw error(line_number, keyfile::NO_KEY, line); - key = line.substr(0, pos); - if (pos == line.length() - 1) - value = ""; - else - value = line.substr(pos + 1); - - // No group specified - if (group.empty()) - throw error(line_number, keyfile::NO_GROUP, line); - - comment_set = true; - key_set = true; - value_set = true; - } - - ++line_number; -} - -void -keyfile_reader::end() -{ } diff --git a/lib/sbuild/keyfile-writer.cc b/lib/sbuild/keyfile-writer.cc index b3a62552..c00ca000 100644 --- a/lib/sbuild/keyfile-writer.cc +++ b/lib/sbuild/keyfile-writer.cc @@ -22,92 +22,94 @@ #include <sbuild/keyfile-writer.h> -using namespace sbuild; - -keyfile_writer::keyfile_writer(keyfile const& store): - store(store) -{} - -keyfile_writer::keyfile_writer (keyfile const& store, - std::string const& file): - keyfile_writer(store) -{ - std::ofstream fs(file.c_str()); - if (fs) - { - fs.imbue(std::locale::classic()); - write_stream(fs); - } - else - { - throw error(file, keyfile::BAD_FILE); - } -} - -keyfile_writer::keyfile_writer (keyfile const& store, - std::ostream& stream): - keyfile_writer(store) -{ - write_stream(stream); -} - -keyfile_writer::~keyfile_writer() -{} - -void -keyfile_writer::write_stream(std::ostream& stream) const +namespace sbuild { - keyfile::size_type group_count = 0; - for (const auto& group : this->store.get_groups()) - { - if (group_count > 0) - stream << '\n'; - ++group_count; + keyfile_writer::keyfile_writer(keyfile const& store): + store(store) + {} + + keyfile_writer::keyfile_writer (keyfile const& store, + std::string const& file): + keyfile_writer(store) + { + std::ofstream fs(file.c_str()); + if (fs) + { + fs.imbue(std::locale::classic()); + write_stream(fs); + } + else + { + throw error(file, keyfile::BAD_FILE); + } + } + + keyfile_writer::keyfile_writer (keyfile const& store, + std::ostream& stream): + keyfile_writer(store) + { + write_stream(stream); + } + + keyfile_writer::~keyfile_writer() + {} + + void + keyfile_writer::write_stream(std::ostream& stream) const + { + keyfile::size_type group_count = 0; + + for (const auto& group : this->store.get_groups()) + { + if (group_count > 0) + stream << '\n'; + ++group_count; + + keyfile::comment_type comment = this->store.get_comment(group); + + if (comment.length() > 0) + print_comment(comment, stream); + + stream << '[' << group << ']' << '\n'; + + for (const auto& key : this->store.get_keys(group)) + { + std::string value; + this->store.get_value(group, key, value); + keyfile::comment_type comment = this->store.get_comment(group, key); + + if (comment.length() > 0) + print_comment(comment, stream); + + stream << key << '=' << value << '\n'; + } + } + } + + void + sbuild::keyfile_writer::print_comment (keyfile::comment_type const& comment, + std::ostream& stream) + { + std::string::size_type last_pos = 0; + std::string::size_type pos = comment.find_first_of('\n', last_pos); + + while (1) + { + if (last_pos == pos) + stream << "#\n"; + else + stream << '#' << comment.substr(last_pos, pos - last_pos) << '\n'; + + // Find next + if (pos < comment.length() - 1) + { + last_pos = pos + 1; + pos = comment.find_first_of('\n', last_pos); + } + else + break; + } + } - keyfile::comment_type comment = this->store.get_comment(group); - - if (comment.length() > 0) - print_comment(comment, stream); - - stream << '[' << group << ']' << '\n'; - - for (const auto& key : this->store.get_keys(group)) - { - std::string value; - this->store.get_value(group, key, value); - keyfile::comment_type comment = this->store.get_comment(group, key); - - if (comment.length() > 0) - print_comment(comment, stream); - - stream << key << '=' << value << '\n'; - } - } } - -void -sbuild::keyfile_writer::print_comment (keyfile::comment_type const& comment, - std::ostream& stream) -{ - std::string::size_type last_pos = 0; - std::string::size_type pos = comment.find_first_of('\n', last_pos); - - while (1) - { - if (last_pos == pos) - stream << "#\n"; - else - stream << '#' << comment.substr(last_pos, pos - last_pos) << '\n'; - - // Find next - if (pos < comment.length() - 1) - { - last_pos = pos + 1; - pos = comment.find_first_of('\n', last_pos); - } - else - break; - } -} - diff --git a/lib/sbuild/keyfile.cc b/lib/sbuild/keyfile.cc index 7d74b2f9..cd648ab7 100644 --- a/lib/sbuild/keyfile.cc +++ b/lib/sbuild/keyfile.cc @@ -27,501 +27,498 @@ using boost::format; -using namespace sbuild; - -template<> -error<keyfile::error_code>::map_type -error<keyfile::error_code>::error_strings = - { - // TRANSLATORS: %1% = file - {keyfile::BAD_FILE, - N_("Can't open file ‘%1%’")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::DEPRECATED_KEY, - N_("line %1% [%2%]: Deprecated key ‘%4%’ used")}, - // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::DEPRECATED_KEY_NL, - N_("[%1%]: Deprecated key ‘%4%’ used")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::DISALLOWED_KEY, - N_("line %1% [%2%]: Disallowed key ‘%4%’ used")}, - // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::DISALLOWED_KEY_NL, - N_("[%1%]: Disallowed key ‘%4%’ used")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %4% = group name ("[groupname]" in configuration file) - {keyfile::DUPLICATE_GROUP, - N_("line %1%: Duplicate group ‘%4%’")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::DUPLICATE_KEY, - N_("line %1% [%2%]: Duplicate key ‘%4%’")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %4% = line contents as read from the configuration file - {keyfile::INVALID_GROUP, - N_("line %1%: Invalid group: “%4%”")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::INVALID_KEY, - N_("line %1% [%2%]: Invalid key ‘%4%’ used")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %4% = line contents as read from the configuration file - {keyfile::INVALID_LINE, - N_("line %1%: Invalid line: “%4%”")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::MISSING_KEY, - N_("line %1% [%2%]: Required key ‘%4%’ is missing")}, - // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::MISSING_KEY_NL, - N_("[%1%]: Required key ‘%4%’ is missing")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %4% = line contents as read from the configuration file - {keyfile::NO_GROUP, - N_("line %1%: No group specified: “%4%”")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %4% = line contents as read from the configuration file - {keyfile::NO_KEY, - N_("line %1%: No key specified: “%4%”")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::OBSOLETE_KEY, - N_("line %1% [%2%]: Obsolete key ‘%4%’ used")}, - // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::OBSOLETE_KEY_NL, - N_("[%1%]: Obsolete key ‘%4%’ used")}, - // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = additional details - {keyfile::PASSTHROUGH_G, - N_("[%1%]: %4%")}, - // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %2% = key name ("keyname=value" in configuration file) - // TRANSLATORS: %4% = additional details - {keyfile::PASSTHROUGH_GK, - N_("[%1%] %2%: %4%")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = additional details - {keyfile::PASSTHROUGH_LG, - N_("line %1% [%2%]: %4%")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %3% = key name ("keyname=value" in configuration file) - // TRANSLATORS: %4% = additional details - {keyfile::PASSTHROUGH_LGK, - N_("line %1% [%2%] %3%: %4%")}, - // TRANSLATORS: %1% = line number in configuration file - // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) - // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) - {keyfile::UNKNOWN_KEY, - N_("line %1% [%2%]: Unknown key ‘%4%’ used")} - }; - -sbuild::keyfile::keyfile (): - groups(), - separator(",") -{ -} - -sbuild::keyfile::~keyfile() -{ -} - -sbuild::keyfile::group_list -sbuild::keyfile::get_groups () const +namespace sbuild { - group_list ret; - for (const auto& group : this->groups) - ret.push_back(group.first); - - return ret; -} - -sbuild::keyfile::key_list -sbuild::keyfile::get_keys (group_name_type const& group) const -{ - key_list ret; - - const group_type *found_group = find_group(group); - if (found_group) + template<> + error<keyfile::error_code>::map_type + error<keyfile::error_code>::error_strings = { - item_map_type const& items(std::get<1>(*found_group)); - for (const auto& item : items) - ret.push_back(item.first); - } - - return ret; -} - -void -sbuild::keyfile::check_keys (group_name_type const& group, - key_list const& keys) const -{ - const string_list total(get_keys(group)); + // TRANSLATORS: %1% = file + {keyfile::BAD_FILE, + N_("Can't open file ‘%1%’")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::DEPRECATED_KEY, + N_("line %1% [%2%]: Deprecated key ‘%4%’ used")}, + // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::DEPRECATED_KEY_NL, + N_("[%1%]: Deprecated key ‘%4%’ used")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::DISALLOWED_KEY, + N_("line %1% [%2%]: Disallowed key ‘%4%’ used")}, + // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::DISALLOWED_KEY_NL, + N_("[%1%]: Disallowed key ‘%4%’ used")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %4% = group name ("[groupname]" in configuration file) + {keyfile::DUPLICATE_GROUP, + N_("line %1%: Duplicate group ‘%4%’")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::DUPLICATE_KEY, + N_("line %1% [%2%]: Duplicate key ‘%4%’")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %4% = line contents as read from the configuration file + {keyfile::INVALID_GROUP, + N_("line %1%: Invalid group: “%4%”")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::INVALID_KEY, + N_("line %1% [%2%]: Invalid key ‘%4%’ used")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %4% = line contents as read from the configuration file + {keyfile::INVALID_LINE, + N_("line %1%: Invalid line: “%4%”")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::MISSING_KEY, + N_("line %1% [%2%]: Required key ‘%4%’ is missing")}, + // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::MISSING_KEY_NL, + N_("[%1%]: Required key ‘%4%’ is missing")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %4% = line contents as read from the configuration file + {keyfile::NO_GROUP, + N_("line %1%: No group specified: “%4%”")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %4% = line contents as read from the configuration file + {keyfile::NO_KEY, + N_("line %1%: No key specified: “%4%”")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::OBSOLETE_KEY, + N_("line %1% [%2%]: Obsolete key ‘%4%’ used")}, + // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::OBSOLETE_KEY_NL, + N_("[%1%]: Obsolete key ‘%4%’ used")}, + // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = additional details + {keyfile::PASSTHROUGH_G, + N_("[%1%]: %4%")}, + // TRANSLATORS: %1% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %2% = key name ("keyname=value" in configuration file) + // TRANSLATORS: %4% = additional details + {keyfile::PASSTHROUGH_GK, + N_("[%1%] %2%: %4%")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = additional details + {keyfile::PASSTHROUGH_LG, + N_("line %1% [%2%]: %4%")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %3% = key name ("keyname=value" in configuration file) + // TRANSLATORS: %4% = additional details + {keyfile::PASSTHROUGH_LGK, + N_("line %1% [%2%] %3%: %4%")}, + // TRANSLATORS: %1% = line number in configuration file + // TRANSLATORS: %2% = group name ("[groupname]" in configuration file) + // TRANSLATORS: %4% = key name ("keyname=value" in configuration file) + {keyfile::UNKNOWN_KEY, + N_("line %1% [%2%]: Unknown key ‘%4%’ used")} + }; + + sbuild::keyfile::keyfile (): + groups(), + separator(",") + { + } - const string_set a(total.begin(), total.end()); - const string_set b(keys.begin(), keys.end()); + sbuild::keyfile::~keyfile() + { + } - string_set unused; + sbuild::keyfile::group_list + sbuild::keyfile::get_groups () const + { + group_list ret; - set_difference(a.begin(), a.end(), - b.begin(), b.end(), - inserter(unused, unused.begin())); + for (const auto& group : this->groups) + ret.push_back(group.first); - for (const auto& item : unused) - { - size_type line = get_line(group, item); - error e(line, group, UNKNOWN_KEY, item); - e.set_reason(_("This option may be present in a newer version")); - log_exception_warning(e); - } -} + return ret; + } -bool -sbuild::keyfile::has_group (group_name_type const& group) const -{ - return (find_group(group) != 0); -} + sbuild::keyfile::key_list + sbuild::keyfile::get_keys (group_name_type const& group) const + { + key_list ret; + + const group_type *found_group = find_group(group); + if (found_group) + { + item_map_type const& items(std::get<1>(*found_group)); + for (const auto& item : items) + ret.push_back(item.first); + } + + return ret; + } + + void + sbuild::keyfile::check_keys (group_name_type const& group, + key_list const& keys) const + { + const string_list total(get_keys(group)); -bool -sbuild::keyfile::has_key (group_name_type const& group, - key_type const& key) const -{ - return (find_item(group, key) != 0); -} + const string_set a(total.begin(), total.end()); + const string_set b(keys.begin(), keys.end()); -void -sbuild::keyfile::set_group (group_name_type const& group, - comment_type const& comment) -{ - set_group(group, comment, 0); -} + string_set unused; -void -sbuild::keyfile::set_group (group_name_type const& group, - comment_type const& comment, - size_type line) -{ - if (!has_group(group)) - this->groups.insert - (group_map_type::value_type(group, - group_type(group, - item_map_type(), - comment, - line))); -} + set_difference(a.begin(), a.end(), + b.begin(), b.end(), + inserter(unused, unused.begin())); -sbuild::keyfile::comment_type -sbuild::keyfile::get_comment (group_name_type const& group) const -{ - const group_type *found_group = find_group(group); - if (found_group) - return std::get<2>(*found_group); - else - return comment_type(); -} + for (const auto& item : unused) + { + size_type line = get_line(group, item); + error e(line, group, UNKNOWN_KEY, item); + e.set_reason(_("This option may be present in a newer version")); + log_exception_warning(e); + } + } -sbuild::keyfile::comment_type -sbuild::keyfile::get_comment (group_name_type const& group, - key_type const& key) const -{ - const item_type *found_item = find_item(group, key); - if (found_item) - return std::get<2>(*found_item); - else - return comment_type(); -} + bool + sbuild::keyfile::has_group (group_name_type const& group) const + { + return (find_group(group) != 0); + } -sbuild::keyfile::size_type -sbuild::keyfile::get_line (group_name_type const& group) const -{ - const group_type *found_group = find_group(group); - if (found_group) - return std::get<3>(*found_group); - else - return 0; -} + bool + sbuild::keyfile::has_key (group_name_type const& group, + key_type const& key) const + { + return (find_item(group, key) != 0); + } -sbuild::keyfile::size_type -sbuild::keyfile::get_line (group_name_type const& group, - key_type const& key) const -{ - const item_type *found_item = find_item(group, key); - if (found_item) - return std::get<3>(*found_item); - else - return 0; -} + void + sbuild::keyfile::set_group (group_name_type const& group, + comment_type const& comment) + { + set_group(group, comment, 0); + } -bool -sbuild::keyfile::get_locale_string (group_name_type const& group, - key_type const& key, - value_type& value) const -{ - std::string localename; - try - { - localename = std::locale("").name(); - } - catch (std::runtime_error const& e) // Invalid locale - { - localename = std::locale::classic().name(); - } - std::string::size_type pos; - bool status = false; - - // Strip off any charset. - if ((pos = localename.find_first_of('.')) != std::string::npos) - localename = localename.substr(0, pos); - status = get_locale_string(group, key, localename, value); - - // Strip off territory. - if (status == false && - (pos = localename.find_first_of('_')) != std::string::npos) - { + void + sbuild::keyfile::set_group (group_name_type const& group, + comment_type const& comment, + size_type line) + { + if (!has_group(group)) + this->groups.insert + (group_map_type::value_type(group, + group_type(group, + item_map_type(), + comment, + line))); + } + + sbuild::keyfile::comment_type + sbuild::keyfile::get_comment (group_name_type const& group) const + { + const group_type *found_group = find_group(group); + if (found_group) + return std::get<2>(*found_group); + else + return comment_type(); + } + + sbuild::keyfile::comment_type + sbuild::keyfile::get_comment (group_name_type const& group, + key_type const& key) const + { + const item_type *found_item = find_item(group, key); + if (found_item) + return std::get<2>(*found_item); + else + return comment_type(); + } + + sbuild::keyfile::size_type + sbuild::keyfile::get_line (group_name_type const& group) const + { + const group_type *found_group = find_group(group); + if (found_group) + return std::get<3>(*found_group); + else + return 0; + } + + sbuild::keyfile::size_type + sbuild::keyfile::get_line (group_name_type const& group, + key_type const& key) const + { + const item_type *found_item = find_item(group, key); + if (found_item) + return std::get<3>(*found_item); + else + return 0; + } + + bool + sbuild::keyfile::get_locale_string (group_name_type const& group, + key_type const& key, + value_type& value) const + { + std::string localename; + try + { + localename = std::locale("").name(); + } + catch (std::runtime_error const& e) // Invalid locale + { + localename = std::locale::classic().name(); + } + std::string::size_type pos; + bool status = false; + + // Strip off any charset. + if ((pos = localename.find_first_of('.')) != std::string::npos) localename = localename.substr(0, pos); - status = get_locale_string(group, key, localename, value); - } - - // Fall back to non-localised version. - if (status == false) - status = get_value(group, key, value); - - return status; -} - -bool -sbuild::keyfile::get_locale_string (group_name_type const& group, - key_type const& key, - priority priority, - value_type& value) const -{ - bool status = get_locale_string(group, key, value); - check_priority(group, key, priority, status); - return status; -} - -bool -sbuild::keyfile::get_locale_string (group_name_type const& group, - key_type const& key, - std::string const& locale, - value_type& value) const -{ - std::string lkey = key + '[' + locale + ']'; - return get_value(group, lkey, value); -} - -bool -sbuild::keyfile::get_locale_string (group_name_type const& group, - key_type const& key, - std::string const& locale, - priority priority, - value_type& value) const -{ - bool status = get_locale_string(group, key, locale, value); - check_priority(group, key, priority, status); - return status; -} - -void -sbuild::keyfile::remove_group (group_name_type const& group) -{ - group_map_type::iterator pos = this->groups.find(group); - if (pos != this->groups.end()) - this->groups.erase(pos); -} - -void -sbuild::keyfile::remove_key (group_name_type const& group, - key_type const& key) -{ - group_type *found_group = find_group(group); - if (found_group) - { - item_map_type& items = std::get<1>(*found_group); - item_map_type::iterator pos = items.find(key); - if (pos != items.end()) - items.erase(pos); - } -} + status = get_locale_string(group, key, localename, value); + + // Strip off territory. + if (status == false && + (pos = localename.find_first_of('_')) != std::string::npos) + { + localename = localename.substr(0, pos); + status = get_locale_string(group, key, localename, value); + } + + // Fall back to non-localised version. + if (status == false) + status = get_value(group, key, value); + + return status; + } + + bool + sbuild::keyfile::get_locale_string (group_name_type const& group, + key_type const& key, + priority priority, + value_type& value) const + { + bool status = get_locale_string(group, key, value); + check_priority(group, key, priority, status); + return status; + } + + bool + sbuild::keyfile::get_locale_string (group_name_type const& group, + key_type const& key, + std::string const& locale, + value_type& value) const + { + std::string lkey = key + '[' + locale + ']'; + return get_value(group, lkey, value); + } + + bool + sbuild::keyfile::get_locale_string (group_name_type const& group, + key_type const& key, + std::string const& locale, + priority priority, + value_type& value) const + { + bool status = get_locale_string(group, key, locale, value); + check_priority(group, key, priority, status); + return status; + } -sbuild::keyfile& -sbuild::keyfile::operator += (keyfile const& rhs) -{ - for (const auto& gp : rhs.groups) - { - group_type const& group = gp.second; - group_name_type const& groupname = std::get<0>(group); - comment_type const& comment = std::get<2>(group); - size_type const& line = std::get<3>(group); - set_group(groupname, comment, line); - - item_map_type const& items(std::get<1>(group)); - for (const auto& it : items) - { - item_type const& item = it.second; - key_type const& key(std::get<0>(item)); - internal_value_type const& value(std::get<1>(item)); - comment_type const& comment(std::get<2>(item)); - size_type const& line(std::get<3>(item)); - set_value(groupname, key, value, comment, line); - } - } - return *this; -} + void + sbuild::keyfile::remove_group (group_name_type const& group) + { + group_map_type::iterator pos = this->groups.find(group); + if (pos != this->groups.end()) + this->groups.erase(pos); + } + + void + sbuild::keyfile::remove_key (group_name_type const& group, + key_type const& key) + { + group_type *found_group = find_group(group); + if (found_group) + { + item_map_type& items = std::get<1>(*found_group); + item_map_type::iterator pos = items.find(key); + if (pos != items.end()) + items.erase(pos); + } + } + + sbuild::keyfile& + sbuild::keyfile::operator += (keyfile const& rhs) + { + for (const auto& gp : rhs.groups) + { + group_type const& group = gp.second; + group_name_type const& groupname = std::get<0>(group); + comment_type const& comment = std::get<2>(group); + size_type const& line = std::get<3>(group); + set_group(groupname, comment, line); + + item_map_type const& items(std::get<1>(group)); + for (const auto& it : items) + { + item_type const& item = it.second; + key_type const& key(std::get<0>(item)); + internal_value_type const& value(std::get<1>(item)); + comment_type const& comment(std::get<2>(item)); + size_type const& line(std::get<3>(item)); + set_value(groupname, key, value, comment, line); + } + } + return *this; + } -sbuild::keyfile -operator + (sbuild::keyfile const& lhs, - sbuild::keyfile const& rhs) -{ - sbuild::keyfile ret(lhs); - ret += rhs; - return ret; -} + sbuild::keyfile + operator + (sbuild::keyfile const& lhs, + sbuild::keyfile const& rhs) + { + sbuild::keyfile ret(lhs); + ret += rhs; + return ret; + } -const sbuild::keyfile::group_type * -sbuild::keyfile::find_group (group_name_type const& group) const -{ - group_map_type::const_iterator pos = this->groups.find(group); - if (pos != this->groups.end()) - return &pos->second; + const sbuild::keyfile::group_type * + sbuild::keyfile::find_group (group_name_type const& group) const + { + group_map_type::const_iterator pos = this->groups.find(group); + if (pos != this->groups.end()) + return &pos->second; - return 0; -} + return 0; + } -sbuild::keyfile::group_type * -sbuild::keyfile::find_group (group_name_type const& group) -{ - group_map_type::iterator pos = this->groups.find(group); - if (pos != this->groups.end()) - return &pos->second; + sbuild::keyfile::group_type * + sbuild::keyfile::find_group (group_name_type const& group) + { + group_map_type::iterator pos = this->groups.find(group); + if (pos != this->groups.end()) + return &pos->second; - return 0; -} + return 0; + } -const sbuild::keyfile::item_type * -sbuild::keyfile::find_item (group_name_type const& group, - key_type const& key) const -{ - const group_type *found_group = find_group(group); - if (found_group) - { - item_map_type const& items = std::get<1>(*found_group); - item_map_type::const_iterator pos = items.find(key); - if (pos != items.end()) - return &pos->second; - } + const sbuild::keyfile::item_type * + sbuild::keyfile::find_item (group_name_type const& group, + key_type const& key) const + { + const group_type *found_group = find_group(group); + if (found_group) + { + item_map_type const& items = std::get<1>(*found_group); + item_map_type::const_iterator pos = items.find(key); + if (pos != items.end()) + return &pos->second; + } - return 0; -} + return 0; + } -sbuild::keyfile::item_type * -sbuild::keyfile::find_item (group_name_type const& group, - key_type const& key) -{ - group_type *found_group = find_group(group); - if (found_group) - { - item_map_type& items = std::get<1>(*found_group); - item_map_type::iterator pos = items.find(key); - if (pos != items.end()) - return &pos->second; - } + sbuild::keyfile::item_type * + sbuild::keyfile::find_item (group_name_type const& group, + key_type const& key) + { + group_type *found_group = find_group(group); + if (found_group) + { + item_map_type& items = std::get<1>(*found_group); + item_map_type::iterator pos = items.find(key); + if (pos != items.end()) + return &pos->second; + } - return 0; -} + return 0; + } -void -sbuild::keyfile::check_priority (group_name_type const& group, - key_type const& key, - priority priority, - bool valid) const -{ - if (valid == false) - { - size_type gline = get_line(group); + void + sbuild::keyfile::check_priority (group_name_type const& group, + key_type const& key, + priority priority, + bool valid) const + { + if (valid == false) + { + size_type gline = get_line(group); - switch (priority) - { - case PRIORITY_REQUIRED: + switch (priority) { - if (gline) - throw error(gline, group, MISSING_KEY, key); - else - throw error(group, MISSING_KEY_NL, key); + case PRIORITY_REQUIRED: + { + if (gline) + throw error(gline, group, MISSING_KEY, key); + else + throw error(group, MISSING_KEY_NL, key); + } + break; + default: + break; } - break; - default: - break; - } - } - else - { - size_type line = get_line(group, key); + } + else + { + size_type line = get_line(group, key); - switch (priority) - { - case PRIORITY_DEPRECATED: - { - if (line) - { - error e(line, group, DEPRECATED_KEY, key); - e.set_reason(_("This option will be removed in the future; please update your configuration")); - log_exception_warning(e); - } - else - { - error e(group, DEPRECATED_KEY_NL, key); - e.set_reason(_("This option will be removed in the future; please update your configuration")); - log_exception_warning(e); - } - } - break; - case PRIORITY_OBSOLETE: + switch (priority) { - if (line) - { - error e(line, group, OBSOLETE_KEY, key); - e.set_reason(_("This option has been removed, and no longer has any effect")); - log_exception_warning(e); - } - else - { - error e(group, OBSOLETE_KEY_NL, key); - e.set_reason(_("This option has been removed, and no longer has any effect")); - log_exception_warning(e); - } + case PRIORITY_DEPRECATED: + { + if (line) + { + error e(line, group, DEPRECATED_KEY, key); + e.set_reason(_("This option will be removed in the future; please update your configuration")); + log_exception_warning(e); + } + else + { + error e(group, DEPRECATED_KEY_NL, key); + e.set_reason(_("This option will be removed in the future; please update your configuration")); + log_exception_warning(e); + } + } + break; + case PRIORITY_OBSOLETE: + { + if (line) + { + error e(line, group, OBSOLETE_KEY, key); + e.set_reason(_("This option has been removed, and no longer has any effect")); + log_exception_warning(e); + } + else + { + error e(group, OBSOLETE_KEY_NL, key); + e.set_reason(_("This option has been removed, and no longer has any effect")); + log_exception_warning(e); + } + } + break; + case PRIORITY_DISALLOWED: + { + if (line) + throw error(line, group, DISALLOWED_KEY, key); + else + throw error(group, DISALLOWED_KEY_NL, key); + } + break; + default: + break; } - break; - case PRIORITY_DISALLOWED: - { - if (line) - throw error(line, group, DISALLOWED_KEY, key); - else - throw error(group, DISALLOWED_KEY_NL, key); - } - break; - default: - break; - } - } -} + } + } -/* - * Local Variables: - * mode:C++ - * End: - */ +} diff --git a/lib/sbuild/lock.cc b/lib/sbuild/lock.cc index dfa8fe9a..8eac089c 100644 --- a/lib/sbuild/lock.cc +++ b/lib/sbuild/lock.cc @@ -31,184 +31,188 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; -template<> -error<lock::error_code>::map_type -error<lock::error_code>::error_strings = - { - {lock::TIMEOUT_HANDLER, N_("Failed to set timeout handler")}, - {lock::TIMEOUT_SET, N_("Failed to set timeout")}, - {lock::TIMEOUT_CANCEL, N_("Failed to cancel timeout")}, - {lock::LOCK, N_("Failed to lock file")}, - {lock::UNLOCK, N_("Failed to unlock file")}, - // TRANSLATORS: %4% = time in seconds - {lock::LOCK_TIMEOUT, N_("Failed to lock file (timed out after %4% seconds)")}, - // TRANSLATORS: %4% = time in seconds - {lock::UNLOCK_TIMEOUT, N_("Failed to unlock file (timed out after %4% seconds)")}, - {lock::DEVICE_LOCK, N_("Failed to lock device")}, - // TRANSLATORS: %4% = time in seconds - // TRANSLATORS: %5% = integer process ID - {lock::DEVICE_LOCK_TIMEOUT, N_("Failed to lock device (timed out after %4% seconds; lock held by PID %5%)")}, - {lock::DEVICE_TEST, N_("Failed to test device lock")}, - {lock::DEVICE_UNLOCK, N_("Failed to unlock device")}, - // TRANSLATORS: %4% = time in seconds - // TRANSLATORS: %5% = integer process ID - {lock::DEVICE_UNLOCK_TIMEOUT, N_("Failed to unlock device (timed out after %4% seconds; lock held by PID %5%)")} - }; - -namespace +namespace sbuild { - /** - * Handle the SIGALRM signal. This exists so that system calls get - * interrupted. - * - * @param ignore the signal number. - */ - void - alarm_handler (int ignore) + + template<> + error<lock::error_code>::map_type + error<lock::error_code>::error_strings = + { + {lock::TIMEOUT_HANDLER, N_("Failed to set timeout handler")}, + {lock::TIMEOUT_SET, N_("Failed to set timeout")}, + {lock::TIMEOUT_CANCEL, N_("Failed to cancel timeout")}, + {lock::LOCK, N_("Failed to lock file")}, + {lock::UNLOCK, N_("Failed to unlock file")}, + // TRANSLATORS: %4% = time in seconds + {lock::LOCK_TIMEOUT, N_("Failed to lock file (timed out after %4% seconds)")}, + // TRANSLATORS: %4% = time in seconds + {lock::UNLOCK_TIMEOUT, N_("Failed to unlock file (timed out after %4% seconds)")}, + {lock::DEVICE_LOCK, N_("Failed to lock device")}, + // TRANSLATORS: %4% = time in seconds + // TRANSLATORS: %5% = integer process ID + {lock::DEVICE_LOCK_TIMEOUT, N_("Failed to lock device (timed out after %4% seconds; lock held by PID %5%)")}, + {lock::DEVICE_TEST, N_("Failed to test device lock")}, + {lock::DEVICE_UNLOCK, N_("Failed to unlock device")}, + // TRANSLATORS: %4% = time in seconds + // TRANSLATORS: %5% = integer process ID + {lock::DEVICE_UNLOCK_TIMEOUT, N_("Failed to unlock device (timed out after %4% seconds; lock held by PID %5%)")} + }; + + namespace { + /** + * Handle the SIGALRM signal. This exists so that system calls get + * interrupted. + * + * @param ignore the signal number. + */ + void + alarm_handler (int ignore) + { + } } -} -lock::lock (): - saved_signals() -{ -} + lock::lock (): + saved_signals() + { + } -lock::~lock () -{ -} + lock::~lock () + { + } -void -lock::set_alarm () -{ - struct sigaction new_sa; - sigemptyset(&new_sa.sa_mask); - new_sa.sa_flags = 0; - new_sa.sa_handler = alarm_handler; + void + lock::set_alarm () + { + struct sigaction new_sa; + sigemptyset(&new_sa.sa_mask); + new_sa.sa_flags = 0; + new_sa.sa_handler = alarm_handler; - if (sigaction(SIGALRM, &new_sa, &this->saved_signals) != 0) - throw error(TIMEOUT_HANDLER, strerror(errno)); -} + if (sigaction(SIGALRM, &new_sa, &this->saved_signals) != 0) + throw error(TIMEOUT_HANDLER, strerror(errno)); + } -void -lock::clear_alarm () -{ - /* Restore original handler */ - sigaction (SIGALRM, &this->saved_signals, 0); -} + void + lock::clear_alarm () + { + /* Restore original handler */ + sigaction (SIGALRM, &this->saved_signals, 0); + } -void -lock::set_timer(struct itimerval const& timer) -{ - set_alarm(); + void + lock::set_timer(struct itimerval const& timer) + { + set_alarm(); - if (setitimer(ITIMER_REAL, &timer, 0) == -1) - { - clear_alarm(); - throw error(TIMEOUT_SET, strerror(errno)); - } -} + if (setitimer(ITIMER_REAL, &timer, 0) == -1) + { + clear_alarm(); + throw error(TIMEOUT_SET, strerror(errno)); + } + } -void -lock::unset_timer () -{ - struct itimerval disable_timer; - disable_timer.it_interval.tv_sec = disable_timer.it_interval.tv_usec = 0; - disable_timer.it_value.tv_sec = disable_timer.it_value.tv_usec = 0; + void + lock::unset_timer () + { + struct itimerval disable_timer; + disable_timer.it_interval.tv_sec = disable_timer.it_interval.tv_usec = 0; + disable_timer.it_value.tv_sec = disable_timer.it_value.tv_usec = 0; - if (setitimer(ITIMER_REAL, &disable_timer, 0) == -1) - { - clear_alarm(); - throw error(TIMEOUT_CANCEL, strerror(errno)); - } + if (setitimer(ITIMER_REAL, &disable_timer, 0) == -1) + { + clear_alarm(); + throw error(TIMEOUT_CANCEL, strerror(errno)); + } - clear_alarm(); -} + clear_alarm(); + } -file_lock::file_lock (int fd): - lock(), - fd(fd), - locked(false) -{ -} + file_lock::file_lock (int fd): + lock(), + fd(fd), + locked(false) + { + } -file_lock::~file_lock () -{ - // Release a lock if held. Note that the code is duplicated from - // set_lock because we don't want to throw an exception in a - // destructor under any circumstances. Any error is logged. - if (locked) - { - struct flock read_lock; - read_lock.l_type = LOCK_NONE; - read_lock.l_whence = SEEK_SET; - read_lock.l_start = 0; - read_lock.l_len = 0; // Lock entire file - read_lock.l_pid = 0; - - if (fcntl(this->fd, F_SETLK, &read_lock) == -1) - log_exception_warning(error(UNLOCK, strerror(errno))); - } -} + file_lock::~file_lock () + { + // Release a lock if held. Note that the code is duplicated from + // set_lock because we don't want to throw an exception in a + // destructor under any circumstances. Any error is logged. + if (locked) + { + struct flock read_lock; + read_lock.l_type = LOCK_NONE; + read_lock.l_whence = SEEK_SET; + read_lock.l_start = 0; + read_lock.l_len = 0; // Lock entire file + read_lock.l_pid = 0; + + if (fcntl(this->fd, F_SETLK, &read_lock) == -1) + log_exception_warning(error(UNLOCK, strerror(errno))); + } + } -void -file_lock::set_lock (lock::type lock_type, - unsigned int timeout) -{ - try - { - struct itimerval timeout_timer; - timeout_timer.it_interval.tv_sec = timeout_timer.it_interval.tv_usec = 0; - timeout_timer.it_value.tv_sec = timeout; - timeout_timer.it_value.tv_usec = 0; - set_timer(timeout_timer); - - /* Now the signal handler and itimer are set, the function can't - return without stopping the timer and restoring the signal - handler to its original state. */ - - /* Wait on lock until interrupted by a signal if a timeout was set, - otherwise return immediately. */ - struct flock read_lock; - read_lock.l_type = lock_type; - read_lock.l_whence = SEEK_SET; - read_lock.l_start = 0; - read_lock.l_len = 0; // Lock entire file - read_lock.l_pid = 0; - - if (fcntl(this->fd, - (timeout != 0) ? F_SETLKW : F_SETLK, - &read_lock) == -1) - { - if (errno == EINTR) - throw error((lock_type == LOCK_SHARED || - lock_type == LOCK_EXCLUSIVE) - ? LOCK_TIMEOUT : UNLOCK_TIMEOUT, - timeout); - else - throw error((lock_type == LOCK_SHARED || - lock_type == LOCK_EXCLUSIVE) ? LOCK : UNLOCK, - strerror(errno)); - } - - if (lock_type == LOCK_SHARED || lock_type == LOCK_EXCLUSIVE) - this->locked = true; - else - this->locked = false; - - unset_timer(); - } - catch (error const& e) - { - unset_timer(); - throw; - } -} + void + file_lock::set_lock (lock::type lock_type, + unsigned int timeout) + { + try + { + struct itimerval timeout_timer; + timeout_timer.it_interval.tv_sec = timeout_timer.it_interval.tv_usec = 0; + timeout_timer.it_value.tv_sec = timeout; + timeout_timer.it_value.tv_usec = 0; + set_timer(timeout_timer); + + /* Now the signal handler and itimer are set, the function can't + return without stopping the timer and restoring the signal + handler to its original state. */ + + /* Wait on lock until interrupted by a signal if a timeout was set, + otherwise return immediately. */ + struct flock read_lock; + read_lock.l_type = lock_type; + read_lock.l_whence = SEEK_SET; + read_lock.l_start = 0; + read_lock.l_len = 0; // Lock entire file + read_lock.l_pid = 0; + + if (fcntl(this->fd, + (timeout != 0) ? F_SETLKW : F_SETLK, + &read_lock) == -1) + { + if (errno == EINTR) + throw error((lock_type == LOCK_SHARED || + lock_type == LOCK_EXCLUSIVE) + ? LOCK_TIMEOUT : UNLOCK_TIMEOUT, + timeout); + else + throw error((lock_type == LOCK_SHARED || + lock_type == LOCK_EXCLUSIVE) ? LOCK : UNLOCK, + strerror(errno)); + } + + if (lock_type == LOCK_SHARED || lock_type == LOCK_EXCLUSIVE) + this->locked = true; + else + this->locked = false; + + unset_timer(); + } + catch (error const& e) + { + unset_timer(); + throw; + } + } + + void + file_lock::unset_lock () + { + set_lock(LOCK_NONE, 0); + } -void -file_lock::unset_lock () -{ - set_lock(LOCK_NONE, 0); } diff --git a/lib/sbuild/log.cc b/lib/sbuild/log.cc index 7f7a5697..3fbaa94a 100644 --- a/lib/sbuild/log.cc +++ b/lib/sbuild/log.cc @@ -30,145 +30,149 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; -namespace +namespace sbuild { - /** - * Log an exception reason. Log the reason an exception was thrown, - * if the exception contains reason information. - * - * @param e the exception to log. - * @param ctty true to log to the CTTY or false to log to cerr. - */ - void - log_reason (std::exception const& e, - bool ctty) + namespace { - try - { - error_base const& eb(dynamic_cast<error_base const&>(e)); - string_list lines = split_string(eb.why(), "\n"); - for (const auto& line : lines) - ctty ? log_ctty_info() : log_info() - << line << std::endl; - } - catch (std::bad_cast const& discard) - { - } + + /** + * Log an exception reason. Log the reason an exception was thrown, + * if the exception contains reason information. + * + * @param e the exception to log. + * @param ctty true to log to the CTTY or false to log to cerr. + */ + void + log_reason (std::exception const& e, + bool ctty) + { + try + { + error_base const& eb(dynamic_cast<error_base const&>(e)); + string_list lines = split_string(eb.why(), "\n"); + for (const auto& line : lines) + ctty ? log_ctty_info() : log_info() + << line << std::endl; + } + catch (std::bad_cast const& discard) + { + } + } + + /** + * Log an exception reason as an informational message. + * + * @param e the exception to log. + */ + void + log_exception_reason (std::exception const& e) + { + log_reason(e, false); + } + + /** + * Log an exception reason as as an informational message to the + * Controlling TTY. + * + * @param e the exception to log. + */ + void + log_ctty_exception_reason (std::exception const& e) + { + log_reason(e, true); + } } - /** - * Log an exception reason as an informational message. - * - * @param e the exception to log. - */ - void - log_exception_reason (std::exception const& e) + std::ostream& + log_info () { - log_reason(e, false); + // TRANSLATORS: "I" is an abbreviation of "Information" + return std::cerr << _("I: "); } - /** - * Log an exception reason as as an informational message to the - * Controlling TTY. - * - * @param e the exception to log. - */ - void - log_ctty_exception_reason (std::exception const& e) + std::ostream& + log_warning () { - log_reason(e, true); + // TRANSLATORS: "W" is an abbreviation of "Warning" + return std::cerr << _("W: "); } -} -std::ostream& -sbuild::log_info () -{ - // TRANSLATORS: "I" is an abbreviation of "Information" - return std::cerr << _("I: "); -} + std::ostream& + log_error () + { + // TRANSLATORS: "E" is an abbreviation of "Error" + return std::cerr << _("E: "); + } -std::ostream& -sbuild::log_warning () -{ - // TRANSLATORS: "W" is an abbreviation of "Warning" - return std::cerr << _("W: "); -} + std::ostream& + log_debug (debug_level level) + { + if (debug_log_level > 0 && + level >= debug_log_level) + // TRANSLATORS: %1% = integer debug level + // TRANSLATORS: "D" is an abbreviation of "Debug" + return std::cerr << format(_("D(%1%): ")) % level; + else + return cnull; + } -std::ostream& -sbuild::log_error () -{ - // TRANSLATORS: "E" is an abbreviation of "Error" - return std::cerr << _("E: "); -} + std::ostream& + log_ctty_info () + { + // TRANSLATORS: "I" is an abbreviation of "Information" + return cctty << _("I: "); + } -std::ostream& -sbuild::log_debug (sbuild::debug_level level) -{ - if (debug_log_level > 0 && - level >= debug_log_level) - // TRANSLATORS: %1% = integer debug level - // TRANSLATORS: "D" is an abbreviation of "Debug" - return std::cerr << format(_("D(%1%): ")) % level; - else - return sbuild::cnull; -} + std::ostream& + log_ctty_warning () + { + // TRANSLATORS: "W" is an abbreviation of "Warning" + return cctty << _("W: "); + } -std::ostream& -sbuild::log_ctty_info () -{ - // TRANSLATORS: "I" is an abbreviation of "Information" - return cctty << _("I: "); -} + std::ostream& + log_ctty_error () + { + // TRANSLATORS: "E" is an abbreviation of "Error" + return cctty << _("E: "); + } -std::ostream& -sbuild::log_ctty_warning () -{ - // TRANSLATORS: "W" is an abbreviation of "Warning" - return cctty << _("W: "); -} + void + log_exception_warning (std::exception const& e) + { + log_warning() << e.what() << std::endl; + log_exception_reason(e); + } -std::ostream& -sbuild::log_ctty_error () -{ - // TRANSLATORS: "E" is an abbreviation of "Error" - return cctty << _("E: "); -} + void + log_exception_error (std::exception const& e) + { + log_error() << e.what() << std::endl; + log_exception_reason(e); + } -void -sbuild::log_exception_warning (std::exception const& e) -{ - log_warning() << e.what() << std::endl; - log_exception_reason(e); -} + void + log_ctty_exception_warning (std::exception const& e) + { + log_ctty_warning() << e.what() << std::endl; + log_ctty_exception_reason(e); + } -void -sbuild::log_exception_error (std::exception const& e) -{ - log_error() << e.what() << std::endl; - log_exception_reason(e); -} + void + log_ctty_exception_error (std::exception const& e) + { + log_ctty_error() << e.what() << std::endl; + log_ctty_exception_reason(e); + } -void -sbuild::log_ctty_exception_warning (std::exception const& e) -{ - log_ctty_warning() << e.what() << std::endl; - log_ctty_exception_reason(e); -} + void + log_unknown_exception_error () + { + log_error() << _("An unknown exception occurred") << std::endl; + } -void -sbuild::log_ctty_exception_error (std::exception const& e) -{ - log_ctty_error() << e.what() << std::endl; - log_ctty_exception_reason(e); -} + debug_level debug_log_level = DEBUG_NONE; -void -sbuild::log_unknown_exception_error () -{ - log_error() << _("An unknown exception occurred") << std::endl; } - -sbuild::debug_level sbuild::debug_log_level = sbuild::DEBUG_NONE; diff --git a/lib/sbuild/mntstream.cc b/lib/sbuild/mntstream.cc index 3f1e1601..c67d5ff9 100644 --- a/lib/sbuild/mntstream.cc +++ b/lib/sbuild/mntstream.cc @@ -23,146 +23,149 @@ #include <cerrno> #include <cstring> -using namespace sbuild; - -template<> -error<mntstream::error_code>::map_type -error<mntstream::error_code>::error_strings = - { - // TRANSLATORS: %1% = mount file name - {mntstream::MNT_OPEN, N_("Failed to open mount file ‘%1%’")}, - // TRANSLATORS: %1% = mount file name - {mntstream::MNT_READ, N_("Failed to read mount file ‘%1%’")} - }; - -mntstream::mntentry::mntentry (struct mntent const& entry): - filesystem_name(entry.mnt_fsname), - directory(entry.mnt_dir), - type(entry.mnt_type), - options(entry.mnt_opts), - dump_frequency(entry.mnt_freq), - fsck_pass(entry.mnt_passno) -{ -} - - -mntstream::mntstream(std::string const& file): - file(), - mntfile(0), - data(), - error_status(true), - eof_status(true) +namespace sbuild { - open(file); -} - - -mntstream::~mntstream() -{ - close(); -} -void -mntstream::open(std::string const& file) -{ - this->mntfile = setmntent(file.c_str(), "r"); - if (this->mntfile == 0) + template<> + error<mntstream::error_code>::map_type + error<mntstream::error_code>::error_strings = { - this->file.clear(); - this->error_status = true; - this->eof_status = true; - throw error(file, MNT_OPEN, strerror(errno)); - } - this->file = file; - this->error_status = false; - this->eof_status = false; - read(); -} - -void -mntstream::read(int quantity) -{ - int i; + // TRANSLATORS: %1% = mount file name + {mntstream::MNT_OPEN, N_("Failed to open mount file ‘%1%’")}, + // TRANSLATORS: %1% = mount file name + {mntstream::MNT_READ, N_("Failed to read mount file ‘%1%’")} + }; + + mntstream::mntentry::mntentry (struct mntent const& entry): + filesystem_name(entry.mnt_fsname), + directory(entry.mnt_dir), + type(entry.mnt_type), + options(entry.mnt_opts), + dump_frequency(entry.mnt_freq), + fsck_pass(entry.mnt_passno) + { + } - if (this->mntfile == 0) - return; - for (i = 0; i < quantity; ++i) - { - struct mntent* entry; - errno = 0; - entry = getmntent(mntfile); - - if (entry == 0) // EOF or error - { - //std::cerr << "Mount file read error: "; - if (errno) // error - { - this->error_status = true; - throw error(this->file, MNT_READ, strerror(errno)); - } - return; - } - - mntentry newentry(*entry); // make a mntentry - this->data.push_back(newentry); // push onto the end of the list - } -} + mntstream::mntstream(std::string const& file): + file(), + mntfile(0), + data(), + error_status(true), + eof_status(true) + { + open(file); + } -void -mntstream::close() -{ - if (this->mntfile) - endmntent(this->mntfile); // don't throw an exception on failure - // -- it could be called in the - // destructor - this->mntfile = 0; - this->data.clear(); // clear all data - this->file.clear(); - this->error_status = true; - this->eof_status = true; -} + mntstream::~mntstream() + { + close(); + } -bool -mntstream::eof() const -{ - return this->eof_status; -} + void + mntstream::open(std::string const& file) + { + this->mntfile = setmntent(file.c_str(), "r"); + if (this->mntfile == 0) + { + this->file.clear(); + this->error_status = true; + this->eof_status = true; + throw error(file, MNT_OPEN, strerror(errno)); + } + this->file = file; + this->error_status = false; + this->eof_status = false; + read(); + } + + void + mntstream::read(int quantity) + { + int i; + + if (this->mntfile == 0) + return; + + for (i = 0; i < quantity; ++i) + { + struct mntent* entry; + errno = 0; + entry = getmntent(mntfile); + + if (entry == 0) // EOF or error + { + //std::cerr << "Mount file read error: "; + if (errno) // error + { + this->error_status = true; + throw error(this->file, MNT_READ, strerror(errno)); + } + return; + } + + mntentry newentry(*entry); // make a mntentry + this->data.push_back(newentry); // push onto the end of the list + } + } + + void + mntstream::close() + { + if (this->mntfile) + endmntent(this->mntfile); // don't throw an exception on failure + // -- it could be called in the + // destructor + this->mntfile = 0; + this->data.clear(); // clear all data + this->file.clear(); + this->error_status = true; + this->eof_status = true; + } + + + bool + mntstream::eof() const + { + return this->eof_status; + } -bool -mntstream::bad() const -{ - return this->error_status; -} + bool + mntstream::bad() const + { + return this->error_status; + } -mntstream::operator bool () -{ - return !(bad() || eof()); -} + mntstream::operator bool () + { + return !(bad() || eof()); + } -bool -mntstream::operator ! () -{ - return bad() || eof(); -} + bool + mntstream::operator ! () + { + return bad() || eof(); + } -mntstream& -sbuild::operator >> (mntstream& stream, - mntstream::mntentry& entry) -{ - stream.read(); // read a new entry - if (stream && !stream.data.empty()) // not at end of file or bad. - { - entry = stream.data.front(); // assign next mntentry to entry - stream.data.pop_front(); // remove the entry - } - else // blank the mntentry and set EOF status - { - entry = mntstream::mntentry(); - stream.eof_status = true; - } + mntstream& + operator >> (mntstream& stream, + mntstream::mntentry& entry) + { + stream.read(); // read a new entry + if (stream && !stream.data.empty()) // not at end of file or bad. + { + entry = stream.data.front(); // assign next mntentry to entry + stream.data.pop_front(); // remove the entry + } + else // blank the mntentry and set EOF status + { + entry = mntstream::mntentry(); + stream.eof_status = true; + } + + return stream; + } - return stream; } diff --git a/lib/sbuild/nostream.cc b/lib/sbuild/nostream.cc index 7d38299e..1186bf5f 100644 --- a/lib/sbuild/nostream.cc +++ b/lib/sbuild/nostream.cc @@ -18,4 +18,9 @@ #include <sbuild/nostream.h> -sbuild::nostream sbuild::cnull; +namespace sbuild +{ + + nostream cnull; + +} diff --git a/lib/sbuild/parse-value.cc b/lib/sbuild/parse-value.cc index 08e3b0d7..987aa9a8 100644 --- a/lib/sbuild/parse-value.cc +++ b/lib/sbuild/parse-value.cc @@ -20,37 +20,40 @@ #include <sbuild/parse-value.h> -using namespace sbuild; +namespace sbuild +{ + + template<> + error<parse_value_error_code>::map_type + error<parse_value_error_code>::error_strings = + { + // TRANSLATORS: %1% = value (arbitrary text) + {BAD_VALUE, N_("Could not parse value ‘%1%’")} + }; -template<> -error<parse_value_error_code>::map_type -error<parse_value_error_code>::error_strings = + void + parse_value (std::string const& value, + bool& parsed_value) { - // TRANSLATORS: %1% = value (arbitrary text) - {BAD_VALUE, N_("Could not parse value ‘%1%’")} - }; + if (value == "true" || value == "yes" || value == "1") + parsed_value = true; + else if (value == "false" || value == "no" || value == "0") + parsed_value = false; + else + { + log_debug(DEBUG_NOTICE) << "parse error" << std::endl; + throw parse_value_error(value, BAD_VALUE); + } -void -sbuild::parse_value (std::string const& value, - bool& parsed_value) -{ - if (value == "true" || value == "yes" || value == "1") - parsed_value = true; - else if (value == "false" || value == "no" || value == "0") - parsed_value = false; - else - { - log_debug(DEBUG_NOTICE) << "parse error" << std::endl; - throw parse_value_error(value, BAD_VALUE); - } + log_debug(DEBUG_NOTICE) << "value=" << parsed_value << std::endl; + } - log_debug(DEBUG_NOTICE) << "value=" << parsed_value << std::endl; -} + void + parse_value (std::string const& value, + std::string& parsed_value) + { + parsed_value = value; + log_debug(DEBUG_NOTICE) << "value=" << parsed_value << std::endl; + } -void -sbuild::parse_value (std::string const& value, - std::string& parsed_value) -{ - parsed_value = value; - log_debug(DEBUG_NOTICE) << "value=" << parsed_value << std::endl; } diff --git a/lib/sbuild/personality.cc b/lib/sbuild/personality.cc index abf4beab..3c7eb1b6 100644 --- a/lib/sbuild/personality.cc +++ b/lib/sbuild/personality.cc @@ -31,155 +31,159 @@ #include <boost/format.hpp> using boost::format; -using namespace sbuild; -namespace +namespace sbuild { - sbuild::feature feature_personality - ("PERSONALITY", - N_("Linux kernel Application Binary Interface switching")); - -} - -template<> -error<sbuild::personality::error_code>::map_type -error<sbuild::personality::error_code>::error_strings = + namespace { - // TRANSLATORS: %1% = integer personality ID - {sbuild::personality::BAD, N_("Personality ‘%1%’ is unknown")}, - // TRANSLATORS: %1% = personality name - {sbuild::personality::SET, N_("Failed to set personality ‘%1%’")} - }; - -std::map<std::string,sbuild::personality::type> -sbuild::personality::personalities = - { - {"undefined", 0xffffffff}, - {"linux", PER_LINUX}, - {"linux_32bit", PER_LINUX_32BIT}, - {"svr4", PER_SVR4}, - {"scorvr3", PER_SCOSVR3}, - {"osr5", PER_OSR5}, - {"wysev386", PER_WYSEV386}, - {"iscr4", PER_ISCR4}, - {"bsd", PER_BSD}, - {"sunos", PER_SUNOS}, - {"xenix", PER_XENIX}, - {"linux32", PER_LINUX32}, - {"irix32", PER_IRIX32}, - {"irixn32", PER_IRIXN32}, - {"irix64", PER_IRIX64}, - {"riscos", PER_RISCOS}, - {"solaris", PER_SOLARIS}, - {"uw7", PER_UW7}, - {"hpux", PER_HPUX}, - {"osf4", PER_OSF4} - }; - -sbuild::personality::personality (): - persona_name("undefined"), - persona(find_personality("undefined")) -{ - set_name("undefined"); -} -sbuild::personality::personality (std::string const& persona): - persona_name("undefined"), - persona(find_personality("undefined")) -{ - set_name(persona); -} + sbuild::feature feature_personality + ("PERSONALITY", + N_("Linux kernel Application Binary Interface switching")); -sbuild::personality::~personality () -{ -} + } -sbuild::personality::type -sbuild::personality::find_personality (std::string const& persona) -{ - std::map<std::string,type>::const_iterator pos = - personalities.find(persona); + template<> + error<sbuild::personality::error_code>::map_type + error<sbuild::personality::error_code>::error_strings = + { + // TRANSLATORS: %1% = integer personality ID + {sbuild::personality::BAD, N_("Personality ‘%1%’ is unknown")}, + // TRANSLATORS: %1% = personality name + {sbuild::personality::SET, N_("Failed to set personality ‘%1%’")} + }; + + std::map<std::string,sbuild::personality::type> + sbuild::personality::personalities = + { + {"undefined", 0xffffffff}, + {"linux", PER_LINUX}, + {"linux_32bit", PER_LINUX_32BIT}, + {"svr4", PER_SVR4}, + {"scorvr3", PER_SCOSVR3}, + {"osr5", PER_OSR5}, + {"wysev386", PER_WYSEV386}, + {"iscr4", PER_ISCR4}, + {"bsd", PER_BSD}, + {"sunos", PER_SUNOS}, + {"xenix", PER_XENIX}, + {"linux32", PER_LINUX32}, + {"irix32", PER_IRIX32}, + {"irixn32", PER_IRIXN32}, + {"irix64", PER_IRIX64}, + {"riscos", PER_RISCOS}, + {"solaris", PER_SOLARIS}, + {"uw7", PER_UW7}, + {"hpux", PER_HPUX}, + {"osf4", PER_OSF4} + }; + + sbuild::personality::personality (): + persona_name("undefined"), + persona(find_personality("undefined")) + { + set_name("undefined"); + } - if (pos != personalities.end()) - return pos->second; + sbuild::personality::personality (std::string const& persona): + persona_name("undefined"), + persona(find_personality("undefined")) + { + set_name(persona); + } - return 0xffffffff; -} + sbuild::personality::~personality () + { + } -std::string const& -sbuild::personality::find_personality (type persona) -{ - static const std::string unknown("unknown"); + sbuild::personality::type + sbuild::personality::find_personality (std::string const& persona) + { + std::map<std::string,type>::const_iterator pos = + personalities.find(persona); - for (std::map<std::string,type>::const_iterator pos = personalities.begin(); - pos != personalities.end(); - ++pos) - if (pos->second == persona) - return pos->first; + if (pos != personalities.end()) + return pos->second; - return unknown; -} + return 0xffffffff; + } -std::string const& -sbuild::personality::get_name () const -{ - return this->persona_name; -} + std::string const& + sbuild::personality::find_personality (type persona) + { + static const std::string unknown("unknown"); -void -sbuild::personality::set_name (std::string const& persona) -{ - this->persona_name = persona; - this->persona = find_personality(persona); + for (std::map<std::string,type>::const_iterator pos = personalities.begin(); + pos != personalities.end(); + ++pos) + if (pos->second == persona) + return pos->first; - if (this->persona_name != "undefined" && - this->persona == find_personality("undefined")) - { - this->persona_name = "undefined"; - this->persona = find_personality("undefined"); + return unknown; + } - personality::error e(persona, personality::BAD); - e.set_reason(personality::get_personalities()); - throw e; - } -} + std::string const& + sbuild::personality::get_name () const + { + return this->persona_name; + } -sbuild::personality::type -sbuild::personality::get () const -{ - return this->persona; -} + void + sbuild::personality::set_name (std::string const& persona) + { + this->persona_name = persona; + this->persona = find_personality(persona); + + if (this->persona_name != "undefined" && + this->persona == find_personality("undefined")) + { + this->persona_name = "undefined"; + this->persona = find_personality("undefined"); + + personality::error e(persona, personality::BAD); + e.set_reason(personality::get_personalities()); + throw e; + } + } + + sbuild::personality::type + sbuild::personality::get () const + { + return this->persona; + } -void -sbuild::personality::set () const -{ - /* Set the process execution domain using personality(2). */ - if (this->persona != find_personality("undefined") && - ::personality (this->persona) < 0) - { - throw error(get_name(), SET, strerror(errno)); - } -} + void + sbuild::personality::set () const + { + /* Set the process execution domain using personality(2). */ + if (this->persona != find_personality("undefined") && + ::personality (this->persona) < 0) + { + throw error(get_name(), SET, strerror(errno)); + } + } + + std::string + sbuild::personality::get_personalities () + { + // TRANSLATORS: %1% = a comma-separated list of personality names + format fmt(_("Valid personalities: %1%\n")); + std::string ps; -std::string -sbuild::personality::get_personalities () -{ - // TRANSLATORS: %1% = a comma-separated list of personality names - format fmt(_("Valid personalities: %1%\n")); - std::string ps; + for (std::map<std::string,type>::const_iterator pos = personalities.begin(); + pos != personalities.end(); + ++pos) + { + ps += pos->first; + std::map<std::string,type>::const_iterator stpos = pos; + if (++stpos != personalities.end()) + ps += ", "; + } - for (std::map<std::string,type>::const_iterator pos = personalities.begin(); - pos != personalities.end(); - ++pos) - { - ps += pos->first; - std::map<std::string,type>::const_iterator stpos = pos; - if (++stpos != personalities.end()) - ps += ", "; - } + fmt % ps; - fmt % ps; + return fmt.str(); + } - return fmt.str(); } diff --git a/lib/sbuild/run-parts.cc b/lib/sbuild/run-parts.cc index a1ec39c1..6803631b 100644 --- a/lib/sbuild/run-parts.cc +++ b/lib/sbuild/run-parts.cc @@ -32,336 +32,340 @@ #include <boost/filesystem/operations.hpp> using boost::format; -using namespace sbuild; -template<> -error<run_parts::error_code>::map_type -error<run_parts::error_code>::error_strings = - { - {run_parts::CHILD_FORK, N_("Failed to fork child")}, - {run_parts::CHILD_WAIT, N_("Wait for child failed")}, - // TRANSLATORS: %1% = command name - {run_parts::EXEC, N_("Failed to execute “%1%”")}, - {run_parts::PIPE, N_("Failed to create pipe")}, - {run_parts::DUP, N_("Failed to duplicate file descriptor")}, - {run_parts::POLL, N_("Failed to poll file descriptor")}, - {run_parts::READ, N_("Failed to read file descriptor")} - }; - -run_parts::run_parts (std::string const& directory, - bool lsb_mode, - bool abort_on_error, - mode_t umask): - lsb_mode(true), - abort_on_error(abort_on_error), - umask(umask), - verbose(false), - reverse(false), - directory(directory), - programs() +namespace sbuild { - boost::filesystem::path dirpath(directory); - boost::filesystem::directory_iterator end_iter; - for (boost::filesystem::directory_iterator dirent(dirpath); - dirent != end_iter; - ++dirent) + + template<> + error<run_parts::error_code>::map_type + error<run_parts::error_code>::error_strings = { + {run_parts::CHILD_FORK, N_("Failed to fork child")}, + {run_parts::CHILD_WAIT, N_("Wait for child failed")}, + // TRANSLATORS: %1% = command name + {run_parts::EXEC, N_("Failed to execute “%1%”")}, + {run_parts::PIPE, N_("Failed to create pipe")}, + {run_parts::DUP, N_("Failed to duplicate file descriptor")}, + {run_parts::POLL, N_("Failed to poll file descriptor")}, + {run_parts::READ, N_("Failed to read file descriptor")} + }; + + run_parts::run_parts (std::string const& directory, + bool lsb_mode, + bool abort_on_error, + mode_t umask): + lsb_mode(true), + abort_on_error(abort_on_error), + umask(umask), + verbose(false), + reverse(false), + directory(directory), + programs() + { + boost::filesystem::path dirpath(directory); + boost::filesystem::directory_iterator end_iter; + for (boost::filesystem::directory_iterator dirent(dirpath); + dirent != end_iter; + ++dirent) + { #if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 - std::string name(dirent->leaf()); + std::string name(dirent->leaf()); #else - std::string name(dirent->path().filename().string()); + std::string name(dirent->path().filename().string()); #endif - // Skip common directories. - if (name == "." || name == "..") - continue; - - // Skip backup files and dpkg configuration backup files. - if (is_valid_filename(name, this->lsb_mode)) - this->programs.insert(name); - } -} - -run_parts::~run_parts () -{ -} + // Skip common directories. + if (name == "." || name == "..") + continue; -bool -run_parts::get_verbose () const -{ - return this->verbose; -} - -void -run_parts::set_verbose (bool verbose) -{ - this->verbose = verbose; -} - -bool -run_parts::get_reverse () const -{ - return this->reverse; -} - -void -run_parts::set_reverse (bool reverse) -{ - this->reverse = reverse; -} + // Skip backup files and dpkg configuration backup files. + if (is_valid_filename(name, this->lsb_mode)) + this->programs.insert(name); + } + } -int -run_parts::run (string_list const& command, - environment const& env) -{ - int exit_status = 0; + run_parts::~run_parts () + { + } - if (!this->reverse) - { - for (const auto& program : this->programs) - { - string_list real_command; - real_command.push_back(program); - for (const auto& arg : command) - real_command.push_back(arg); - - exit_status = run_child(program, real_command, env); - - if (exit_status && this->abort_on_error) - return exit_status; - } - } - else - { - for (program_set::const_reverse_iterator program = this->programs.rbegin(); - program != this->programs.rend(); - ++program) - { - string_list real_command; - real_command.push_back(*program); - for (const auto& arg : command) - real_command.push_back(arg); - - exit_status = run_child(*program, real_command, env); - - if (exit_status && this->abort_on_error) - return exit_status; - } - } - - return exit_status; -} + bool + run_parts::get_verbose () const + { + return this->verbose; + } -int -run_parts::run_child (std::string const& file, - string_list const& command, - environment const& env) -{ - int stdout_pipe[2]; - int stderr_pipe[2]; - int exit_status = 0; - pid_t pid; + void + run_parts::set_verbose (bool verbose) + { + this->verbose = verbose; + } - try - { - if (pipe(stdout_pipe) < 0) - throw error(PIPE, strerror(errno)); - if (pipe(stderr_pipe) < 0) - throw error(PIPE, strerror(errno)); - - if ((pid = fork()) == -1) - { - throw error(CHILD_FORK, strerror(errno)); - } - else if (pid == 0) - { - try - { - log_debug(DEBUG_INFO) << "run_parts: executing " - << string_list_to_string(command, ", ") - << std::endl; - if (this->verbose) - // TRANSLATORS: %1% = command - log_info() << format(_("Executing ‘%1%’")) - % string_list_to_string(command, " ") - << std::endl; - ::umask(this->umask); - - // Don't leak syslog file descriptor to child processes. - closelog(); - - // Set up pipes for stdout and stderr - if (dup2(stdout_pipe[1], STDOUT_FILENO) < 0) - throw error(DUP, strerror(errno)); - if (dup2(stderr_pipe[1], STDERR_FILENO) < 0) - throw error(DUP, strerror(errno)); - - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - - exec(this->directory + '/' + file, command, env); - error e(file, EXEC, strerror(errno)); - log_exception_error(e); - } - catch (std::exception const& e) - { - log_exception_error(e); - } - catch (...) - { - log_error() - << _("An unknown exception occurred") << std::endl; - } - _exit(EXIT_FAILURE); - } - - // Log stdout and stderr. - close(stdout_pipe[1]); - close(stderr_pipe[1]); - - struct pollfd pollfds[2]; - pollfds[0].fd = stdout_pipe[0]; - pollfds[0].events = POLLIN; - pollfds[0].revents = 0; - pollfds[1].fd = stderr_pipe[0]; - pollfds[1].events = POLLIN; - pollfds[1].revents = 0; - - char buffer[BUFSIZ]; - - std::string stdout_buf; - std::string stderr_buf; - - while (1) - { - int status; - if ((status = poll(pollfds, 2, -1)) < 0) - throw error(POLL, strerror(errno)); - - int outdata = 0; - int errdata = 0; - - if (pollfds[1].revents & POLLIN) - { - if ((errdata = read(pollfds[1].fd, buffer, BUFSIZ)) < 0 - && errno != EINTR) - throw error(READ, strerror(errno)); - - if (errdata) - stderr_buf += std::string(&buffer[0], errdata); - } - - if (pollfds[0].revents & POLLIN) - { - if ((outdata = read(pollfds[0].fd, buffer, BUFSIZ)) < 0 - && errno != EINTR) - throw error(READ, strerror(errno)); - - if (outdata) - stdout_buf += std::string(&buffer[0], outdata); - } - - if (!stderr_buf.empty()) - { - string_list lines = split_string_strict(stderr_buf, "\n"); - // If the buffer ends in a newline before splitting, - // it's OK to flush all lines. - bool flush = *stderr_buf.rbegin() == '\n'; - - for (string_list::const_iterator pos = lines.begin(); - pos != lines.end(); - ++pos) - { - if (pos + 1 != lines.end() || flush) - log_error() << file << ": " << *pos << '\n'; - else // Save possibly incompete line - stderr_buf = *pos; - } - - if (flush) - stderr_buf.clear(); - } - - if (!stdout_buf.empty()) - { - string_list lines = split_string_strict(stdout_buf, "\n"); - // If the buffer ends in a newline before splitting, - // it's OK to flush all lines. - bool flush = *stdout_buf.rbegin() == '\n'; - - for (string_list::const_iterator pos = lines.begin(); - pos != lines.end(); - ++pos) - { - if (pos + 1 != lines.end() || flush) - log_info() << file << ": " << *pos << '\n'; - else // Save possibly incompete line - stdout_buf = *pos; - } - - if (flush) - stdout_buf.clear(); - } - - if (outdata == 0 && errdata == 0) // pipes closed - { - // Flush any remaining lines - if (!stderr_buf.empty()) - log_error() << file << ": " << stderr_buf << '\n'; - if (!stdout_buf.empty()) - log_info() << file << ": " << stdout_buf << '\n'; - break; - } - } - - close(stdout_pipe[0]); - close(stderr_pipe[0]); - wait_for_child(pid, exit_status); - } - catch (error const& e) - { - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - throw; - } - - if (exit_status) - log_debug(DEBUG_INFO) << "run_parts: " << file - << " failed with status " << exit_status - << std::endl; - else - log_debug(DEBUG_INFO) << "run_parts: " << file - << " succeeded" - << std::endl; - - return exit_status; -} + bool + run_parts::get_reverse () const + { + return this->reverse; + } -void -run_parts::wait_for_child (pid_t pid, - int& child_status) -{ - child_status = EXIT_FAILURE; // Default exit status + void + run_parts::set_reverse (bool reverse) + { + this->reverse = reverse; + } - int status; + int + run_parts::run (string_list const& command, + environment const& env) + { + int exit_status = 0; + + if (!this->reverse) + { + for (const auto& program : this->programs) + { + string_list real_command; + real_command.push_back(program); + for (const auto& arg : command) + real_command.push_back(arg); + + exit_status = run_child(program, real_command, env); + + if (exit_status && this->abort_on_error) + return exit_status; + } + } + else + { + for (program_set::const_reverse_iterator program = this->programs.rbegin(); + program != this->programs.rend(); + ++program) + { + string_list real_command; + real_command.push_back(*program); + for (const auto& arg : command) + real_command.push_back(arg); + + exit_status = run_child(*program, real_command, env); + + if (exit_status && this->abort_on_error) + return exit_status; + } + } + + return exit_status; + } + + int + run_parts::run_child (std::string const& file, + string_list const& command, + environment const& env) + { + int stdout_pipe[2]; + int stderr_pipe[2]; + int exit_status = 0; + pid_t pid; + + try + { + if (pipe(stdout_pipe) < 0) + throw error(PIPE, strerror(errno)); + if (pipe(stderr_pipe) < 0) + throw error(PIPE, strerror(errno)); + + if ((pid = fork()) == -1) + { + throw error(CHILD_FORK, strerror(errno)); + } + else if (pid == 0) + { + try + { + log_debug(DEBUG_INFO) << "run_parts: executing " + << string_list_to_string(command, ", ") + << std::endl; + if (this->verbose) + // TRANSLATORS: %1% = command + log_info() << format(_("Executing ‘%1%’")) + % string_list_to_string(command, " ") + << std::endl; + ::umask(this->umask); + + // Don't leak syslog file descriptor to child processes. + closelog(); + + // Set up pipes for stdout and stderr + if (dup2(stdout_pipe[1], STDOUT_FILENO) < 0) + throw error(DUP, strerror(errno)); + if (dup2(stderr_pipe[1], STDERR_FILENO) < 0) + throw error(DUP, strerror(errno)); + + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[0]); + close(stderr_pipe[1]); + + exec(this->directory + '/' + file, command, env); + error e(file, EXEC, strerror(errno)); + log_exception_error(e); + } + catch (std::exception const& e) + { + log_exception_error(e); + } + catch (...) + { + log_error() + << _("An unknown exception occurred") << std::endl; + } + _exit(EXIT_FAILURE); + } + + // Log stdout and stderr. + close(stdout_pipe[1]); + close(stderr_pipe[1]); + + struct pollfd pollfds[2]; + pollfds[0].fd = stdout_pipe[0]; + pollfds[0].events = POLLIN; + pollfds[0].revents = 0; + pollfds[1].fd = stderr_pipe[0]; + pollfds[1].events = POLLIN; + pollfds[1].revents = 0; + + char buffer[BUFSIZ]; + + std::string stdout_buf; + std::string stderr_buf; + + while (1) + { + int status; + if ((status = poll(pollfds, 2, -1)) < 0) + throw error(POLL, strerror(errno)); + + int outdata = 0; + int errdata = 0; + + if (pollfds[1].revents & POLLIN) + { + if ((errdata = read(pollfds[1].fd, buffer, BUFSIZ)) < 0 + && errno != EINTR) + throw error(READ, strerror(errno)); + + if (errdata) + stderr_buf += std::string(&buffer[0], errdata); + } + + if (pollfds[0].revents & POLLIN) + { + if ((outdata = read(pollfds[0].fd, buffer, BUFSIZ)) < 0 + && errno != EINTR) + throw error(READ, strerror(errno)); + + if (outdata) + stdout_buf += std::string(&buffer[0], outdata); + } + + if (!stderr_buf.empty()) + { + string_list lines = split_string_strict(stderr_buf, "\n"); + // If the buffer ends in a newline before splitting, + // it's OK to flush all lines. + bool flush = *stderr_buf.rbegin() == '\n'; + + for (string_list::const_iterator pos = lines.begin(); + pos != lines.end(); + ++pos) + { + if (pos + 1 != lines.end() || flush) + log_error() << file << ": " << *pos << '\n'; + else // Save possibly incompete line + stderr_buf = *pos; + } + + if (flush) + stderr_buf.clear(); + } + + if (!stdout_buf.empty()) + { + string_list lines = split_string_strict(stdout_buf, "\n"); + // If the buffer ends in a newline before splitting, + // it's OK to flush all lines. + bool flush = *stdout_buf.rbegin() == '\n'; + + for (string_list::const_iterator pos = lines.begin(); + pos != lines.end(); + ++pos) + { + if (pos + 1 != lines.end() || flush) + log_info() << file << ": " << *pos << '\n'; + else // Save possibly incompete line + stdout_buf = *pos; + } + + if (flush) + stdout_buf.clear(); + } + + if (outdata == 0 && errdata == 0) // pipes closed + { + // Flush any remaining lines + if (!stderr_buf.empty()) + log_error() << file << ": " << stderr_buf << '\n'; + if (!stdout_buf.empty()) + log_info() << file << ": " << stdout_buf << '\n'; + break; + } + } + + close(stdout_pipe[0]); + close(stderr_pipe[0]); + wait_for_child(pid, exit_status); + } + catch (error const& e) + { + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[0]); + close(stderr_pipe[1]); + throw; + } + + if (exit_status) + log_debug(DEBUG_INFO) << "run_parts: " << file + << " failed with status " << exit_status + << std::endl; + else + log_debug(DEBUG_INFO) << "run_parts: " << file + << " succeeded" + << std::endl; + + return exit_status; + } + + void + run_parts::wait_for_child (pid_t pid, + int& child_status) + { + child_status = EXIT_FAILURE; // Default exit status + + int status; + + while (1) + { + if (waitpid(pid, &status, 0) == -1) + { + if (errno == EINTR) + continue; // Wait again. + else + throw error(CHILD_WAIT, strerror(errno)); + } + else + break; + } + + if (WIFEXITED(status)) + child_status = WEXITSTATUS(status); + } - while (1) - { - if (waitpid(pid, &status, 0) == -1) - { - if (errno == EINTR) - continue; // Wait again. - else - throw error(CHILD_WAIT, strerror(errno)); - } - else - break; - } - - if (WIFEXITED(status)) - child_status = WEXITSTATUS(status); } diff --git a/lib/sbuild/session.cc b/lib/sbuild/session.cc index c24146f3..b198781e 100644 --- a/lib/sbuild/session.cc +++ b/lib/sbuild/session.cc @@ -56,1529 +56,1532 @@ #include <syslog.h> - #include <boost/format.hpp> using std::cout; using std::endl; using boost::format; -using namespace sbuild; -namespace +namespace sbuild { - volatile bool sighup_called = false; - volatile bool sigint_called = false; - volatile bool sigterm_called = false; - - /** - * Handle the SIGHUP signal. - * - * @param ignore the signal number. - */ - void - sighup_handler (int ignore) + namespace { - /* This exists so that system calls get interrupted. */ - sighup_called = true; - } - /** - * Handle the SIGINT signal. - * - * We explicitly do nothing with SIGINT, and rely on the exit status - * of child processes to determine if we should care. We want to - * make sure any child process (which will also have received - * SIGINT) has exited before we do anything, and some child - * processes (for example, emacs) may expect SIGINT during normal - * operation. See http://www.cons.org/cracauer/sigint.html for a - * good discussion of SIGINT handling. - - * @param ignore the signal number. - */ - void - sigint_handler (int ignore) - { - /* - * Allows us to detect if an interrupted waitpid() was interrupted - * due to SIGINT or something else. We may also want to use this - * at exit time to see if we should re-kill ourselves with SIGINT. + volatile bool sighup_called = false; + volatile bool sigint_called = false; + volatile bool sigterm_called = false; + + /** + * Handle the SIGHUP signal. + * + * @param ignore the signal number. */ - sigint_called = true; - } + void + sighup_handler (int ignore) + { + /* This exists so that system calls get interrupted. */ + sighup_called = true; + } - /** - * Handle the SIGTERM signal. - * - * @param ignore the signal number. - */ - void - sigterm_handler (int ignore) - { - /* This exists so that system calls get interrupted. */ - sigterm_called = true; - } + /** + * Handle the SIGINT signal. + * + * We explicitly do nothing with SIGINT, and rely on the exit status + * of child processes to determine if we should care. We want to + * make sure any child process (which will also have received + * SIGINT) has exited before we do anything, and some child + * processes (for example, emacs) may expect SIGINT during normal + * operation. See http://www.cons.org/cracauer/sigint.html for a + * good discussion of SIGINT handling. + + * @param ignore the signal number. + */ + void + sigint_handler (int ignore) + { + /* + * Allows us to detect if an interrupted waitpid() was interrupted + * due to SIGINT or something else. We may also want to use this + * at exit time to see if we should re-kill ourselves with SIGINT. + */ + sigint_called = true; + } + + /** + * Handle the SIGTERM signal. + * + * @param ignore the signal number. + */ + void + sigterm_handler (int ignore) + { + /* This exists so that system calls get interrupted. */ + sigterm_called = true; + } #ifdef SBUILD_DEBUG - volatile bool child_wait = true; + volatile bool child_wait = true; #endif -} + } -template<> -error<session::error_code>::map_type -error<session::error_code>::error_strings = - { - // TRANSLATORS: %1% = directory - {session::CHDIR, N_("Failed to change to directory ‘%1%’")}, - // TRANSLATORS: %4% = directory - {session::CHDIR_FB, N_("Falling back to directory ‘%4%’")}, - {session::CHILD_CORE, N_("Child dumped core")}, - {session::CHILD_FAIL, N_("Child exited abnormally (reason unknown; not a signal or core dump)")}, - {session::CHILD_FORK, N_("Failed to fork child")}, - // TRANSLATORS: %4% = signal name - {session::CHILD_SIGNAL, N_("Child terminated by signal ‘%4%’")}, - {session::CHILD_WAIT, N_("Wait for child failed")}, - // TRANSLATORS: %1% = directory - {session::CHROOT, N_("Failed to change root to directory ‘%1%’")}, - // TRANSLATORS: %1% = chroot name - {session::CHROOT_ALIAS, N_("No chroot found matching name or alias ‘%1%’")}, - {session::CHROOT_LOCK, N_("Failed to lock chroot")}, - {session::CHROOT_NOTFOUND,N_("%1%: Chroot not found")}, - {session::CHROOT_SETUP, N_("Chroot setup failed")}, - // TRANSLATORS: %1% = chroot name - {session::CHROOT_UNLOCK, N_("Failed to unlock chroot")}, - // TRANSLATORS: %1% = command - {session::COMMAND_ABS, N_("Command “%1%” must have an absolute path")}, - // TRANSLATORS: %1% = command - {session::EXEC, N_("Failed to execute “%1%”")}, - // TRANSLATORS: A supplementary group is the list of additional - // system groups a user belongs to, in addition to their default - // group. - {session::GROUP_GET_SUP, N_("Failed to get supplementary groups")}, - // TRANSLATORS: A supplementary group is the list of additional - // system groups a user belongs to, in addition to their default - // group. - {session::GROUP_GET_SUPC, N_("Failed to get supplementary group count")}, - // TRANSLATORS: %1% = integer group ID - {session::GROUP_SET, N_("Failed to set group ‘%1%’")}, - {session::GROUP_SET_SUP, N_("Failed to set supplementary groups")}, - // TRANSLATORS: %1% = group name - {session::GROUP_UNKNOWN, N_("Group ‘%1%’ not found")}, - {session::PAM, N_("PAM error")}, - {session::ROOT_DROP, N_("Failed to drop root permissions")}, - // TRANSLATORS: %1% = chroot name - // TRANSLATORS: %4% = session identifier - {session::SET_SESSION_ID, N_("%1%: Chroot does not support setting a session ID; ignoring session ID ‘%4%’")}, - // TRANSLATORS: %1% = command - {session::SHELL, N_("Shell ‘%1%’ not available")}, - // TRANSLATORS: %4% = command - {session::SHELL_FB, N_("Falling back to shell ‘%4%’")}, - // TRANSLATORS: %4% = signal name - {session::SIGNAL_CATCH, N_("Caught signal ‘%4%’")}, - // TRANSLATORS: %4% = signal name - {session::SIGNAL_SET, N_("Failed to set signal handler ‘%4%’")}, - // TRANSLATORS: %1% = integer user ID - {session::USER_SET, N_("Failed to set user ‘%1%’")}, - // TRANSLATORS: %1% = user name - // TRANSLATORS: %2% = user name - // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 - {session::USER_SWITCH, N_("(%1%→%2%): User switching is not permitted")} - }; - -session::session (std::string const& service, - operation operation, - chroot_list const& chroots): - authstat( + template<> + error<session::error_code>::map_type + error<session::error_code>::error_strings = + { + // TRANSLATORS: %1% = directory + {session::CHDIR, N_("Failed to change to directory ‘%1%’")}, + // TRANSLATORS: %4% = directory + {session::CHDIR_FB, N_("Falling back to directory ‘%4%’")}, + {session::CHILD_CORE, N_("Child dumped core")}, + {session::CHILD_FAIL, N_("Child exited abnormally (reason unknown; not a signal or core dump)")}, + {session::CHILD_FORK, N_("Failed to fork child")}, + // TRANSLATORS: %4% = signal name + {session::CHILD_SIGNAL, N_("Child terminated by signal ‘%4%’")}, + {session::CHILD_WAIT, N_("Wait for child failed")}, + // TRANSLATORS: %1% = directory + {session::CHROOT, N_("Failed to change root to directory ‘%1%’")}, + // TRANSLATORS: %1% = chroot name + {session::CHROOT_ALIAS, N_("No chroot found matching name or alias ‘%1%’")}, + {session::CHROOT_LOCK, N_("Failed to lock chroot")}, + {session::CHROOT_NOTFOUND,N_("%1%: Chroot not found")}, + {session::CHROOT_SETUP, N_("Chroot setup failed")}, + // TRANSLATORS: %1% = chroot name + {session::CHROOT_UNLOCK, N_("Failed to unlock chroot")}, + // TRANSLATORS: %1% = command + {session::COMMAND_ABS, N_("Command “%1%” must have an absolute path")}, + // TRANSLATORS: %1% = command + {session::EXEC, N_("Failed to execute “%1%”")}, + // TRANSLATORS: A supplementary group is the list of additional + // system groups a user belongs to, in addition to their default + // group. + {session::GROUP_GET_SUP, N_("Failed to get supplementary groups")}, + // TRANSLATORS: A supplementary group is the list of additional + // system groups a user belongs to, in addition to their default + // group. + {session::GROUP_GET_SUPC, N_("Failed to get supplementary group count")}, + // TRANSLATORS: %1% = integer group ID + {session::GROUP_SET, N_("Failed to set group ‘%1%’")}, + {session::GROUP_SET_SUP, N_("Failed to set supplementary groups")}, + // TRANSLATORS: %1% = group name + {session::GROUP_UNKNOWN, N_("Group ‘%1%’ not found")}, + {session::PAM, N_("PAM error")}, + {session::ROOT_DROP, N_("Failed to drop root permissions")}, + // TRANSLATORS: %1% = chroot name + // TRANSLATORS: %4% = session identifier + {session::SET_SESSION_ID, N_("%1%: Chroot does not support setting a session ID; ignoring session ID ‘%4%’")}, + // TRANSLATORS: %1% = command + {session::SHELL, N_("Shell ‘%1%’ not available")}, + // TRANSLATORS: %4% = command + {session::SHELL_FB, N_("Falling back to shell ‘%4%’")}, + // TRANSLATORS: %4% = signal name + {session::SIGNAL_CATCH, N_("Caught signal ‘%4%’")}, + // TRANSLATORS: %4% = signal name + {session::SIGNAL_SET, N_("Failed to set signal handler ‘%4%’")}, + // TRANSLATORS: %1% = integer user ID + {session::USER_SET, N_("Failed to set user ‘%1%’")}, + // TRANSLATORS: %1% = user name + // TRANSLATORS: %2% = user name + // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 + {session::USER_SWITCH, N_("(%1%→%2%): User switching is not permitted")} + }; + + session::session (std::string const& service, + operation operation, + chroot_list const& chroots): + authstat( #ifdef SBUILD_FEATURE_PAM - auth::pam::create(service) + auth::pam::create(service) #else - auth::deny::create(service) + auth::deny::create(service) #endif // SBUILD_FEATURE_PAM - ), - chroots(chroots), - chroot_status(true), - lock_status(true), - child_status(EXIT_FAILURE), - session_operation(operation), - session_id(), - force(false), - saved_sighup_signal(), - saved_sigint_signal(), - saved_sigterm_signal(), - saved_termios(), - termios_ok(false), - verbosity(), - preserve_environment(false), - shell(), - user_options(), - cwd(sbuild::getcwd()) -{ -} - -session::~session () -{ -} + ), + chroots(chroots), + chroot_status(true), + lock_status(true), + child_status(EXIT_FAILURE), + session_operation(operation), + session_id(), + force(false), + saved_sighup_signal(), + saved_sigint_signal(), + saved_sigterm_signal(), + saved_termios(), + termios_ok(false), + verbosity(), + preserve_environment(false), + shell(), + user_options(), + cwd(sbuild::getcwd()) + { + } -auth::auth::ptr const& -session::get_auth () const -{ - return this->authstat; -} + session::~session () + { + } -void -session::set_auth (auth::auth::ptr& auth) -{ - this->authstat = auth; -} + auth::auth::ptr const& + session::get_auth () const + { + return this->authstat; + } -session::chroot_list const& -session::get_chroots () const -{ - return this->chroots; -} + void + session::set_auth (auth::auth::ptr& auth) + { + this->authstat = auth; + } -void -session::set_chroots (chroot_list const& chroots) -{ - this->chroots = chroots; -} + session::chroot_list const& + session::get_chroots () const + { + return this->chroots; + } -session::operation -session::get_operation () const -{ - return this->session_operation; -} + void + session::set_chroots (chroot_list const& chroots) + { + this->chroots = chroots; + } -void -session::set_operation (operation operation) -{ - this->session_operation = operation; -} + session::operation + session::get_operation () const + { + return this->session_operation; + } -std::string const& -session::get_session_id () const -{ - return this->session_id; -} + void + session::set_operation (operation operation) + { + this->session_operation = operation; + } -void -session::set_session_id (std::string const& session_id) -{ - this->session_id = session_id; -} + std::string const& + session::get_session_id () const + { + return this->session_id; + } -std::string const& -session::get_verbosity () const -{ - return this->verbosity; -} + void + session::set_session_id (std::string const& session_id) + { + this->session_id = session_id; + } -void -session::set_verbosity (std::string const& verbosity) -{ - this->verbosity = verbosity; -} + std::string const& + session::get_verbosity () const + { + return this->verbosity; + } -bool -session::get_preserve_environment () const -{ - return this->preserve_environment; -} + void + session::set_verbosity (std::string const& verbosity) + { + this->verbosity = verbosity; + } -void -session::set_preserve_environment (bool preserve_environment) -{ - this->preserve_environment = preserve_environment; -} + bool + session::get_preserve_environment () const + { + return this->preserve_environment; + } -std::string const& -session::get_shell_override () const -{ - return this->shell; -} + void + session::set_preserve_environment (bool preserve_environment) + { + this->preserve_environment = preserve_environment; + } -void -session::set_shell_override (std::string const& shell) -{ - this->shell = shell; -} + std::string const& + session::get_shell_override () const + { + return this->shell; + } -string_map const& -session::get_user_options () const -{ - return this->user_options; -} + void + session::set_shell_override (std::string const& shell) + { + this->shell = shell; + } -void -session::set_user_options (string_map const& user_options) -{ - this->user_options = user_options; -} + string_map const& + session::get_user_options () const + { + return this->user_options; + } -bool -session::get_force () const -{ - return this->force; -} + void + session::set_user_options (string_map const& user_options) + { + this->user_options = user_options; + } -void -session::set_force (bool force) -{ - this->force = force; -} + bool + session::get_force () const + { + return this->force; + } -void -session::save_termios () -{ - string_list const& command(this->authstat->get_command()); + void + session::set_force (bool force) + { + this->force = force; + } - this->termios_ok = false; + void + session::save_termios () + { + string_list const& command(this->authstat->get_command()); + + this->termios_ok = false; + + // Save if running a login shell and have a controlling terminal. + if (CTTY_FILENO >= 0 && + (command.empty() || command[0].empty())) + { + if (tcgetattr(CTTY_FILENO, &this->saved_termios) < 0) + { + log_warning() + << _("Error saving terminal settings") + << endl; + } + else + this->termios_ok = true; + } + } - // Save if running a login shell and have a controlling terminal. - if (CTTY_FILENO >= 0 && - (command.empty() || command[0].empty())) - { - if (tcgetattr(CTTY_FILENO, &this->saved_termios) < 0) - { + void + session::restore_termios () + { + string_list const& command(this->authstat->get_command()); + + // Restore if running a login shell and have a controlling terminal, + // and have previously saved the terminal state. + if (CTTY_FILENO >= 0 && + (command.empty() || command[0].empty()) && + termios_ok) + { + if (tcsetattr(CTTY_FILENO, TCSANOW, &this->saved_termios) < 0) log_warning() - << _("Error saving terminal settings") + << _("Error restoring terminal settings") << endl; - } - else - this->termios_ok = true; - } -} - -void -session::restore_termios () -{ - string_list const& command(this->authstat->get_command()); - - // Restore if running a login shell and have a controlling terminal, - // and have previously saved the terminal state. - if (CTTY_FILENO >= 0 && - (command.empty() || command[0].empty()) && - termios_ok) - { - if (tcsetattr(CTTY_FILENO, TCSANOW, &this->saved_termios) < 0) - log_warning() - << _("Error restoring terminal settings") - << endl; - } -} - -int -session::get_child_status () const -{ - return this->child_status; -} - -/** - * Check group membership. - * - * @param group the group to check for. - * @returns true if the user is a member of group, otherwise false. - */ -bool -session::is_group_member (std::string const& groupname) const -{ - errno = 0; - sbuild::group grp(groupname); - if (!grp) - { - if (errno == 0) - log_debug(DEBUG_INFO) << "Group " << groupname << "not found" << endl; - else - log_debug(DEBUG_INFO) << "Group " << groupname - << "not found: " << strerror(errno) << endl; - return false; - } + } + } - bool group_member = false; - if (grp.gr_gid == getgid()) - { - group_member = true; - } - else - { - int supp_group_count = getgroups(0, 0); - if (supp_group_count < 0) - throw session::error(session::GROUP_GET_SUPC, strerror(errno)); - if (supp_group_count > 0) - { - gid_t *supp_groups = new gid_t[supp_group_count]; - assert (supp_groups); - if (getgroups(supp_group_count, supp_groups) < 1) - { - // Free supp_groups before throwing to avoid leak. - delete[] supp_groups; - throw session::error(session::GROUP_GET_SUP, strerror(errno)); - } - - for (int i = 0; i < supp_group_count; ++i) - { - if (grp.gr_gid == supp_groups[i]) - group_member = true; - } - delete[] supp_groups; - } - } + int + session::get_child_status () const + { + return this->child_status; + } - return group_member; -} + /** + * Check group membership. + * + * @param group the group to check for. + * @returns true if the user is a member of group, otherwise false. + */ + bool + session::is_group_member (std::string const& groupname) const + { + errno = 0; + sbuild::group grp(groupname); + if (!grp) + { + if (errno == 0) + log_debug(DEBUG_INFO) << "Group " << groupname << "not found" << endl; + else + log_debug(DEBUG_INFO) << "Group " << groupname + << "not found: " << strerror(errno) << endl; + return false; + } + + bool group_member = false; + if (grp.gr_gid == getgid()) + { + group_member = true; + } + else + { + int supp_group_count = getgroups(0, 0); + if (supp_group_count < 0) + throw session::error(session::GROUP_GET_SUPC, strerror(errno)); + if (supp_group_count > 0) + { + gid_t *supp_groups = new gid_t[supp_group_count]; + assert (supp_groups); + if (getgroups(supp_group_count, supp_groups) < 1) + { + // Free supp_groups before throwing to avoid leak. + delete[] supp_groups; + throw session::error(session::GROUP_GET_SUP, strerror(errno)); + } + + for (int i = 0; i < supp_group_count; ++i) + { + if (grp.gr_gid == supp_groups[i]) + group_member = true; + } + delete[] supp_groups; + } + } + + return group_member; + } -void -session::get_chroot_membership (chroot::chroot::ptr const& chroot, - bool& in_users, - bool& in_root_users, - bool& in_groups, - bool& in_root_groups) const -{ - string_list const& users = chroot->get_users(); - string_list const& root_users = chroot->get_root_users(); - string_list const& groups = chroot->get_groups(); - string_list const& root_groups = chroot->get_root_groups(); - - in_users = false; - in_root_users = false; - in_groups = false; - in_root_groups = false; - - string_list::const_iterator upos = - find(users.begin(), users.end(), this->authstat->get_ruser()); - if (upos != users.end()) - in_users = true; - - string_list::const_iterator rupos = - find(root_users.begin(), root_users.end(), this->authstat->get_ruser()); - if (rupos != root_users.end()) - in_root_users = true; - - if (!groups.empty()) - { - for (const auto& gp : groups) - if (is_group_member(gp)) - in_groups = true; - } + void + session::get_chroot_membership (chroot::chroot::ptr const& chroot, + bool& in_users, + bool& in_root_users, + bool& in_groups, + bool& in_root_groups) const + { + string_list const& users = chroot->get_users(); + string_list const& root_users = chroot->get_root_users(); + string_list const& groups = chroot->get_groups(); + string_list const& root_groups = chroot->get_root_groups(); + + in_users = false; + in_root_users = false; + in_groups = false; + in_root_groups = false; + + string_list::const_iterator upos = + find(users.begin(), users.end(), this->authstat->get_ruser()); + if (upos != users.end()) + in_users = true; + + string_list::const_iterator rupos = + find(root_users.begin(), root_users.end(), this->authstat->get_ruser()); + if (rupos != root_users.end()) + in_root_users = true; + + if (!groups.empty()) + { + for (const auto& gp : groups) + if (is_group_member(gp)) + in_groups = true; + } + + if (!root_groups.empty()) + { + for (const auto& rgp : root_groups) + if (is_group_member(rgp)) + in_root_groups = true; + } + + log_debug(DEBUG_INFO) + << "In users: " << in_users << endl + << "In groups: " << in_groups << endl + << "In root-users: " << in_root_users << endl + << "In root-groups: " << in_root_groups << endl; - if (!root_groups.empty()) - { - for (const auto& rgp : root_groups) - if (is_group_member(rgp)) - in_root_groups = true; - } + } - log_debug(DEBUG_INFO) - << "In users: " << in_users << endl - << "In groups: " << in_groups << endl - << "In root-users: " << in_root_users << endl - << "In root-groups: " << in_root_groups << endl; + auth::auth::status + session::get_chroot_auth_status (auth::auth::status status, + chroot::chroot::ptr const& chroot) const + { + bool in_users = false; + bool in_root_users = false; + bool in_groups = false; + bool in_root_groups = false; -} + get_chroot_membership(chroot, + in_users, in_root_users, + in_groups, in_root_groups); -auth::auth::status -session::get_chroot_auth_status (auth::auth::status status, - chroot::chroot::ptr const& chroot) const -{ - bool in_users = false; - bool in_root_users = false; - bool in_groups = false; - bool in_root_groups = false; - - get_chroot_membership(chroot, - in_users, in_root_users, - in_groups, in_root_groups); - - /* - * No auth required if in root users or root groups and - * changing to root, or if the uid is not changing. If not - * in user or group, authentication fails immediately. - */ - if ((in_users == true || in_groups == true || - in_root_users == true || in_root_groups == true) && - this->authstat->get_ruid() == this->authstat->get_uid()) - { - status = auth::auth::change_auth(status, auth::auth::STATUS_NONE); - } - else if ((in_root_users == true || in_root_groups == true) && - this->authstat->get_uid() == 0) - { - status = auth::auth::change_auth(status, auth::auth::STATUS_NONE); - } - else if (in_users == true || in_groups == true) - // Auth required if not in root group - { - status = auth::auth::change_auth(status, auth::auth::STATUS_USER); - } - else // Not in any groups - { - if (this->authstat->get_ruid() == 0) + /* + * No auth required if in root users or root groups and + * changing to root, or if the uid is not changing. If not + * in user or group, authentication fails immediately. + */ + if ((in_users == true || in_groups == true || + in_root_users == true || in_root_groups == true) && + this->authstat->get_ruid() == this->authstat->get_uid()) + { + status = auth::auth::change_auth(status, auth::auth::STATUS_NONE); + } + else if ((in_root_users == true || in_root_groups == true) && + this->authstat->get_uid() == 0) + { + status = auth::auth::change_auth(status, auth::auth::STATUS_NONE); + } + else if (in_users == true || in_groups == true) + // Auth required if not in root group + { status = auth::auth::change_auth(status, auth::auth::STATUS_USER); - else - status = auth::auth::change_auth(status, auth::auth::STATUS_FAIL); - } - - return status; -} - -auth::auth::status -session::get_auth_status () const -{ - assert(!this->chroots.empty()); - - /* - * Note that the root user can't escape authentication. This is - * because pam_rootok.so should be used in the PAM configuration if - * root should automatically be granted access. The only exception - * is that the root group doesn't need to be added to the groups or - * root groups lists. - */ + } + else // Not in any groups + { + if (this->authstat->get_ruid() == 0) + status = auth::auth::change_auth(status, auth::auth::STATUS_USER); + else + status = auth::auth::change_auth(status, auth::auth::STATUS_FAIL); + } + + return status; + } - auth::auth::status status = auth::auth::STATUS_NONE; + auth::auth::status + session::get_auth_status () const + { + assert(!this->chroots.empty()); - /** @todo Use set difference rather than iteration and - * is_group_member. - */ - for (const auto& chrootent : this->chroots) - status = auth::auth::change_auth(status, - get_chroot_auth_status(status, chrootent.chroot)); + /* + * Note that the root user can't escape authentication. This is + * because pam_rootok.so should be used in the PAM configuration if + * root should automatically be granted access. The only exception + * is that the root group doesn't need to be added to the groups or + * root groups lists. + */ - return status; -} + auth::auth::status status = auth::auth::STATUS_NONE; -void -session::run () -{ - try - { - this->authstat->start(); - this->authstat->authenticate(get_auth_status()); - this->authstat->setupenv(); - this->authstat->account(); - try - { - this->authstat->cred_establish(); - - run_impl(); - - /* The session is now finished, either - successfully or not. All PAM operations are - now for cleanup and shutdown, and we must - clean up whether or not errors were raised at - any previous point. This means only the - first error is reported back to the user. */ - - /* Don't cope with failure, since we are now - already bailing out, and an error may already - have been raised */ - } - catch (auth::auth::error const& e) - { - try - { - this->authstat->cred_delete(); - } - catch (auth::auth::error const& discard) - { - } - throw; - } - this->authstat->cred_delete(); - } - catch (auth::auth::error const& e) - { - try - { - /* Don't cope with failure, since we are now already bailing out, - and an error may already have been raised */ - this->authstat->stop(); - } - catch (auth::auth::error const& discard) - { - } - throw; - } - this->authstat->stop(); -} + /** @todo Use set difference rather than iteration and + * is_group_member. + */ + for (const auto& chrootent : this->chroots) + status = auth::auth::change_auth(status, + get_chroot_auth_status(status, chrootent.chroot)); -void -session::run_impl () -{ - assert(!this->chroots.empty()); + return status; + } - try - { - sighup_called = false; - set_sighup_handler(); - sigint_called = false; - set_sigint_handler(); - sigterm_called = false; - set_sigterm_handler(); - - for (const auto& chrootent : this->chroots) - { - log_debug(DEBUG_NOTICE) - << format("Running session in %1% chroot:") % chrootent.alias - << endl; + void + session::run () + { + try + { + this->authstat->start(); + this->authstat->authenticate(get_auth_status()); + this->authstat->setupenv(); + this->authstat->account(); + try + { + this->authstat->cred_establish(); + + run_impl(); + + /* The session is now finished, either + successfully or not. All PAM operations are + now for cleanup and shutdown, and we must + clean up whether or not errors were raised at + any previous point. This means only the + first error is reported back to the user. */ + + /* Don't cope with failure, since we are now + already bailing out, and an error may already + have been raised */ + } + catch (auth::auth::error const& e) + { + try + { + this->authstat->cred_delete(); + } + catch (auth::auth::error const& discard) + { + } + throw; + } + this->authstat->cred_delete(); + } + catch (auth::auth::error const& e) + { + try + { + /* Don't cope with failure, since we are now already bailing out, + and an error may already have been raised */ + this->authstat->stop(); + } + catch (auth::auth::error const& discard) + { + } + throw; + } + this->authstat->stop(); + } - const chroot::chroot::ptr ch = chrootent.chroot; - - // TODO: Make chroot/session selection automatically fail - // if no session exists earlier on when selecting chroots. - if (ch->get_session_flags() & chroot::facet::facet::SESSION_CREATE && - (this->session_operation != OPERATION_AUTOMATIC && - this->session_operation != OPERATION_BEGIN)) - throw error(chrootent.alias, CHROOT_NOTFOUND); - - // For now, use a copy of the chroot; if we create a session - // later, we will replace it. - chroot::chroot::ptr chroot(ch->clone()); - assert(chroot); - - /* Create a session using randomly-generated session ID. */ - if (ch->get_session_flags() & chroot::facet::facet::SESSION_CREATE) - { - assert(ch->get_facet<chroot::facet::session_clonable>()); - - std::string new_session_id; - - if (!get_session_id().empty()) - { - new_session_id = get_session_id(); - } - else - { - new_session_id = - ch->get_name() + '-' + unique_identifier(); - } - - // Replace clone of chroot with cloned session. - - bool in_users = false; - bool in_root_users = false; - bool in_groups = false; - bool in_root_groups = false; - - get_chroot_membership(chroot, - in_users, in_root_users, - in_groups, in_root_groups); - - chroot = ch->clone_session(new_session_id, - chrootent.alias, - this->authstat->get_ruser(), - (in_root_users || in_root_groups)); - assert(chroot->get_facet<chroot::facet::session>()); - } - assert(chroot); - - // Override chroot verbosity if needed. - if (!this->verbosity.empty()) - chroot->set_verbosity(this->verbosity); - - // Set user options. - chroot::facet::userdata::ptr userdata = - chroot->get_facet<chroot::facet::userdata>(); - if (userdata) - { - // If the user running the command is root, or the user - // being switched to is root, permit setting of - // root-modifiable options in addition to - // user-modifiable options. - if (this->authstat->get_uid() == 0 || - this->authstat->get_ruid() == 0) - userdata->set_root_data(this->user_options); - else - userdata->set_user_data(this->user_options); - } - - // Following authentication success, default child status to - // success so that operations such as beginning, ending and - // recovering sessions will return success unless an - // exception is thrown. - this->child_status = EXIT_SUCCESS; - - try - { - /* Run setup-start chroot setup scripts. */ - setup_chroot(chroot, chroot::chroot::SETUP_START); - if (this->session_operation == OPERATION_BEGIN) - { - cout << chroot->get_name() << endl; - } - - /* Run recover scripts. */ - setup_chroot(chroot, chroot::chroot::SETUP_RECOVER); - - try - { + void + session::run_impl () + { + assert(!this->chroots.empty()); + + try + { + sighup_called = false; + set_sighup_handler(); + sigint_called = false; + set_sigint_handler(); + sigterm_called = false; + set_sigterm_handler(); + + for (const auto& chrootent : this->chroots) + { + log_debug(DEBUG_NOTICE) + << format("Running session in %1% chroot:") % chrootent.alias + << endl; + + const chroot::chroot::ptr ch = chrootent.chroot; + + // TODO: Make chroot/session selection automatically fail + // if no session exists earlier on when selecting chroots. + if (ch->get_session_flags() & chroot::facet::facet::SESSION_CREATE && + (this->session_operation != OPERATION_AUTOMATIC && + this->session_operation != OPERATION_BEGIN)) + throw error(chrootent.alias, CHROOT_NOTFOUND); + + // For now, use a copy of the chroot; if we create a session + // later, we will replace it. + chroot::chroot::ptr chroot(ch->clone()); + assert(chroot); + + /* Create a session using randomly-generated session ID. */ + if (ch->get_session_flags() & chroot::facet::facet::SESSION_CREATE) + { + assert(ch->get_facet<chroot::facet::session_clonable>()); + + std::string new_session_id; + + if (!get_session_id().empty()) + { + new_session_id = get_session_id(); + } + else + { + new_session_id = + ch->get_name() + '-' + unique_identifier(); + } + + // Replace clone of chroot with cloned session. + + bool in_users = false; + bool in_root_users = false; + bool in_groups = false; + bool in_root_groups = false; + + get_chroot_membership(chroot, + in_users, in_root_users, + in_groups, in_root_groups); + + chroot = ch->clone_session(new_session_id, + chrootent.alias, + this->authstat->get_ruser(), + (in_root_users || in_root_groups)); + assert(chroot->get_facet<chroot::facet::session>()); + } + assert(chroot); + + // Override chroot verbosity if needed. + if (!this->verbosity.empty()) + chroot->set_verbosity(this->verbosity); + + // Set user options. + chroot::facet::userdata::ptr userdata = + chroot->get_facet<chroot::facet::userdata>(); + if (userdata) + { + // If the user running the command is root, or the user + // being switched to is root, permit setting of + // root-modifiable options in addition to + // user-modifiable options. + if (this->authstat->get_uid() == 0 || + this->authstat->get_ruid() == 0) + userdata->set_root_data(this->user_options); + else + userdata->set_user_data(this->user_options); + } + + // Following authentication success, default child status to + // success so that operations such as beginning, ending and + // recovering sessions will return success unless an + // exception is thrown. + this->child_status = EXIT_SUCCESS; + + try + { + /* Run setup-start chroot setup scripts. */ + setup_chroot(chroot, chroot::chroot::SETUP_START); + if (this->session_operation == OPERATION_BEGIN) + { + cout << chroot->get_name() << endl; + } + + /* Run recover scripts. */ + setup_chroot(chroot, chroot::chroot::SETUP_RECOVER); + + try + { #ifdef SBUILD_FEATURE_UNSHARE - /* Unshare execution context */ - chroot::facet::unshare::const_ptr pu = chroot->get_facet<chroot::facet::unshare>(); - if (pu) - pu->do_unshare(); + /* Unshare execution context */ + chroot::facet::unshare::const_ptr pu = chroot->get_facet<chroot::facet::unshare>(); + if (pu) + pu->do_unshare(); #endif // SBUILD_FEATURE_UNSHARE - /* Run exec-start scripts. */ - setup_chroot(chroot, chroot::chroot::EXEC_START); - - /* Run session if setup succeeded. */ - if (this->session_operation == OPERATION_AUTOMATIC || - this->session_operation == OPERATION_RUN) - { - try - { - this->authstat->open_session(); - save_termios(); - run_chroot(chroot); - } - catch (std::runtime_error const& e) - { - log_debug(DEBUG_WARNING) - << "Chroot session failed" << endl; - restore_termios(); - this->authstat->close_session(); - throw; - } - restore_termios(); - this->authstat->close_session(); - } - } - catch (error const& e) - { - log_debug(DEBUG_WARNING) - << "Chroot exec scripts or session failed" << endl; - setup_chroot(chroot, chroot::chroot::EXEC_STOP); - throw; - } - - /* Run exec-stop scripts whether or not there was an - error. */ - setup_chroot(chroot, chroot::chroot::EXEC_STOP); - } - catch (error const& e) - { - log_debug(DEBUG_WARNING) - << "Chroot setup scripts, exec scripts or session failed" << endl; - try - { - setup_chroot(chroot, chroot::chroot::SETUP_STOP); - } - catch (error const& discard) - { - log_debug(DEBUG_WARNING) - << "Chroot setup scripts failed during stop" << endl; - } - throw; - } - - /* Run setup-stop chroot setup scripts whether or not there - was an error. */ - setup_chroot(chroot, chroot::chroot::SETUP_STOP); - } - } - catch (error const& e) - { - clear_sigterm_handler(); - clear_sigint_handler(); - clear_sighup_handler(); - - /* If a command was not run, but something failed, the exit - status still needs setting. */ - if (this->child_status == 0) - this->child_status = EXIT_FAILURE; - throw; - } + /* Run exec-start scripts. */ + setup_chroot(chroot, chroot::chroot::EXEC_START); + + /* Run session if setup succeeded. */ + if (this->session_operation == OPERATION_AUTOMATIC || + this->session_operation == OPERATION_RUN) + { + try + { + this->authstat->open_session(); + save_termios(); + run_chroot(chroot); + } + catch (std::runtime_error const& e) + { + log_debug(DEBUG_WARNING) + << "Chroot session failed" << endl; + restore_termios(); + this->authstat->close_session(); + throw; + } + restore_termios(); + this->authstat->close_session(); + } + } + catch (error const& e) + { + log_debug(DEBUG_WARNING) + << "Chroot exec scripts or session failed" << endl; + setup_chroot(chroot, chroot::chroot::EXEC_STOP); + throw; + } + + /* Run exec-stop scripts whether or not there was an + error. */ + setup_chroot(chroot, chroot::chroot::EXEC_STOP); + } + catch (error const& e) + { + log_debug(DEBUG_WARNING) + << "Chroot setup scripts, exec scripts or session failed" << endl; + try + { + setup_chroot(chroot, chroot::chroot::SETUP_STOP); + } + catch (error const& discard) + { + log_debug(DEBUG_WARNING) + << "Chroot setup scripts failed during stop" << endl; + } + throw; + } + + /* Run setup-stop chroot setup scripts whether or not there + was an error. */ + setup_chroot(chroot, chroot::chroot::SETUP_STOP); + } + } + catch (error const& e) + { + clear_sigterm_handler(); + clear_sigint_handler(); + clear_sighup_handler(); + + /* If a command was not run, but something failed, the exit + status still needs setting. */ + if (this->child_status == 0) + this->child_status = EXIT_FAILURE; + throw; + } + + clear_sigterm_handler(); + clear_sigint_handler(); + clear_sighup_handler(); + } - clear_sigterm_handler(); - clear_sigint_handler(); - clear_sighup_handler(); -} + string_list + session::get_login_directories (chroot::chroot::ptr& session_chroot, + environment const& env) const + { + string_list ret; + + std::string const& wd(this->authstat->get_wd()); + if (!wd.empty()) + { + // Set specified working directory. + ret.push_back(wd); + } + else + { + // Set current working directory. + ret.push_back(this->cwd); + + // Set $HOME. + std::string home; + if (env.get("HOME", home) && + std::find(ret.begin(), ret.end(), home) == ret.end()) + ret.push_back(home); + + // Set passwd home. + if (std::find(ret.begin(), ret.end(), this->authstat->get_home()) == ret.end()) + ret.push_back(this->authstat->get_home()); + + // Final fallback to root. + if (std::find(ret.begin(), ret.end(), "/") == ret.end()) + ret.push_back("/"); + } + + return ret; + } -string_list -session::get_login_directories (chroot::chroot::ptr& session_chroot, - environment const& env) const -{ - string_list ret; + string_list + session::get_command_directories (chroot::chroot::ptr& session_chroot, + environment const& env) const + { + string_list ret; - std::string const& wd(this->authstat->get_wd()); - if (!wd.empty()) - { + std::string const& wd(this->authstat->get_wd()); + if (!wd.empty()) // Set specified working directory. ret.push_back(wd); - } - else - { + else // Set current working directory. ret.push_back(this->cwd); - // Set $HOME. - std::string home; - if (env.get("HOME", home) && - std::find(ret.begin(), ret.end(), home) == ret.end()) - ret.push_back(home); - - // Set passwd home. - if (std::find(ret.begin(), ret.end(), this->authstat->get_home()) == ret.end()) - ret.push_back(this->authstat->get_home()); - - // Final fallback to root. - if (std::find(ret.begin(), ret.end(), "/") == ret.end()) - ret.push_back("/"); - } - - return ret; -} - -string_list -session::get_command_directories (chroot::chroot::ptr& session_chroot, - environment const& env) const -{ - string_list ret; - - std::string const& wd(this->authstat->get_wd()); - if (!wd.empty()) - // Set specified working directory. - ret.push_back(wd); - else - // Set current working directory. - ret.push_back(this->cwd); - - return ret; -} - -string_list -session::get_shells (chroot::chroot::ptr& session_chroot) const -{ - string_list ret; - - // Shell set with --shell (if any) - if (!this->shell.empty()) - { - ret.push_back(this->shell); - } - else if (!session_chroot->get_default_shell().empty()) - { - ret.push_back(session_chroot->get_default_shell()); - } - else - { - if (get_preserve_environment()) - { - // $SHELL (if --preserve-environment used) - environment const& env(this->authstat->get_complete_environment()); - - std::string envshell; - if (env.get("SHELL", envshell) && - std::find(ret.begin(), ret.end(), envshell) == ret.end()) - ret.push_back(envshell); - } - - // passwd pw_shell - std::string const& shell = this->authstat->get_shell(); - if (!shell.empty()) - ret.push_back(shell); - - // Fallback nice interactive shell - if (std::find(ret.begin(), ret.end(), "/bin/bash") == ret.end()) - ret.push_back("/bin/bash"); - - // Fallback basic interactive shell - if (std::find(ret.begin(), ret.end(), "/bin/sh") == ret.end()) - ret.push_back("/bin/sh"); - } - - return ret; -} - -std::string -session::get_shell (chroot::chroot::ptr& session_chroot) const -{ - string_list shells(get_shells(session_chroot)); - - std::string found_shell; - - for (const auto& shell : shells) - { - try - { - stat(shell).check(); - found_shell = shell; - break; - } - catch (std::runtime_error const& e) - { - error e1(shell, SHELL, e.what()); - log_exception_warning(e1); - } - } - - if (found_shell != *shells.begin()) - { - error e2(SHELL_FB, shell); - log_exception_warning(e2); - } - - return found_shell; -} + return ret; + } -void -session::get_command (chroot::chroot::ptr& session_chroot, - std::string& file, - string_list& command, - environment& env) const -{ - /* Run login shell */ - if (command.empty() || - command[0].empty()) // No command - get_login_command(session_chroot, file, command, env); - else - get_user_command(session_chroot, file, command, env); -} + string_list + session::get_shells (chroot::chroot::ptr& session_chroot) const + { + string_list ret; + + // Shell set with --shell (if any) + if (!this->shell.empty()) + { + ret.push_back(this->shell); + } + else if (!session_chroot->get_default_shell().empty()) + { + ret.push_back(session_chroot->get_default_shell()); + } + else + { + if (get_preserve_environment()) + { + // $SHELL (if --preserve-environment used) + environment const& env(this->authstat->get_complete_environment()); + + std::string envshell; + if (env.get("SHELL", envshell) && + std::find(ret.begin(), ret.end(), envshell) == ret.end()) + ret.push_back(envshell); + } + + // passwd pw_shell + std::string const& shell = this->authstat->get_shell(); + if (!shell.empty()) + ret.push_back(shell); + + // Fallback nice interactive shell + if (std::find(ret.begin(), ret.end(), "/bin/bash") == ret.end()) + ret.push_back("/bin/bash"); + + // Fallback basic interactive shell + if (std::find(ret.begin(), ret.end(), "/bin/sh") == ret.end()) + ret.push_back("/bin/sh"); + } + + return ret; + } -void -session::get_login_command (chroot::chroot::ptr& session_chroot, - std::string& file, - string_list& command, - environment& env) const -{ - command.clear(); + std::string + session::get_shell (chroot::chroot::ptr& session_chroot) const + { + string_list shells(get_shells(session_chroot)); + + std::string found_shell; + + for (const auto& shell : shells) + { + try + { + stat(shell).check(); + found_shell = shell; + break; + } + catch (std::runtime_error const& e) + { + error e1(shell, SHELL, e.what()); + log_exception_warning(e1); + } + } + + if (found_shell != *shells.begin()) + { + error e2(SHELL_FB, shell); + log_exception_warning(e2); + } + + return found_shell; + } - std::string shell = get_shell(session_chroot); - file = shell; - env.add("SHELL", shell); + void + session::get_command (chroot::chroot::ptr& session_chroot, + std::string& file, + string_list& command, + environment& env) const + { + /* Run login shell */ + if (command.empty() || + command[0].empty()) // No command + get_login_command(session_chroot, file, command, env); + else + get_user_command(session_chroot, file, command, env); + } - bool login_shell = - !(get_preserve_environment() || - session_chroot->get_preserve_environment()) && - session_chroot->get_command_prefix().empty(); + void + session::get_login_command (chroot::chroot::ptr& session_chroot, + std::string& file, + string_list& command, + environment& env) const + { + command.clear(); + + std::string shell = get_shell(session_chroot); + file = shell; + env.add("SHELL", shell); + + bool login_shell = + !(get_preserve_environment() || + session_chroot->get_preserve_environment()) && + session_chroot->get_command_prefix().empty(); + + // Not keeping environment and can setup argv correctly; login shell + if (login_shell) + { + std::string shellbase = basename(shell); + std::string loginshell = "-" + shellbase; + command.push_back(loginshell); + + log_debug(DEBUG_NOTICE) + << format("Running login shell: %1%") % shell << endl; + if (this->authstat->get_uid() == 0 || this->authstat->get_ruid() != this->authstat->get_uid()) + syslog(LOG_USER|LOG_NOTICE, + "[%s chroot] (%s->%s) Running login shell: '%s'", + session_chroot->get_name().c_str(), + this->authstat->get_ruser().c_str(), this->authstat->get_user().c_str(), + shell.c_str()); + } + else + { + command.push_back(shell); + log_debug(DEBUG_NOTICE) + << format("Running shell: %1%") % shell << endl; + if (this->authstat->get_uid() == 0 || this->authstat->get_ruid() != this->authstat->get_uid()) + syslog(LOG_USER|LOG_NOTICE, + "[%s chroot] (%s->%s) Running shell: '%s'", + session_chroot->get_name().c_str(), + this->authstat->get_ruser().c_str(), this->authstat->get_user().c_str(), + shell.c_str()); + } + + if (session_chroot->get_verbosity() == chroot::chroot::VERBOSITY_VERBOSE) + { + std::string format_string; + if (this->authstat->get_ruid() == this->authstat->get_uid()) + { + if (login_shell) + // TRANSLATORS: %1% = chroot name + // TRANSLATORS: %4% = command + format_string = _("[%1% chroot] Running login shell: ‘%4%’"); + else + // TRANSLATORS: %1% = chroot name + // TRANSLATORS: %4% = command + format_string = _("[%1% chroot] Running shell: ‘%4%’"); + } + else + { + if (login_shell) + // TRANSLATORS: %1% = chroot name + // TRANSLATORS: %2% = user name + // TRANSLATORS: %3% = user name + // TRANSLATORS: %4% = command + // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 + format_string = _("[%1% chroot] (%2%→%3%) Running login shell: ‘%4%’"); + else + // TRANSLATORS: %1% = chroot name + // TRANSLATORS: %2% = user name + // TRANSLATORS: %3% = user name + // TRANSLATORS: %4% = command + // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 + format_string = _("[%1% chroot] (%2%→%3%) Running shell: ‘%4%’"); + } + + format fmt(format_string); + fmt % session_chroot->get_name() + % this->authstat->get_ruser() % this->authstat->get_user() + % shell; + log_info() << fmt << endl; + } + } - // Not keeping environment and can setup argv correctly; login shell - if (login_shell) - { - std::string shellbase = basename(shell); - std::string loginshell = "-" + shellbase; - command.push_back(loginshell); - - log_debug(DEBUG_NOTICE) - << format("Running login shell: %1%") % shell << endl; - if (this->authstat->get_uid() == 0 || this->authstat->get_ruid() != this->authstat->get_uid()) - syslog(LOG_USER|LOG_NOTICE, - "[%s chroot] (%s->%s) Running login shell: '%s'", - session_chroot->get_name().c_str(), - this->authstat->get_ruser().c_str(), this->authstat->get_user().c_str(), - shell.c_str()); - } - else - { - command.push_back(shell); - log_debug(DEBUG_NOTICE) - << format("Running shell: %1%") % shell << endl; - if (this->authstat->get_uid() == 0 || this->authstat->get_ruid() != this->authstat->get_uid()) - syslog(LOG_USER|LOG_NOTICE, - "[%s chroot] (%s->%s) Running shell: '%s'", - session_chroot->get_name().c_str(), - this->authstat->get_ruser().c_str(), this->authstat->get_user().c_str(), - shell.c_str()); - } + void + session::get_user_command (chroot::chroot::ptr& session_chroot, + std::string& file, + string_list& command, + environment const& env) const + { + /* Search for program in path. */ + std::string path; + if (!env.get("PATH", path)) + path.clear(); + + file = find_program_in_path(command[0], path, ""); + if (file.empty()) + file = command[0]; + std::string commandstring = string_list_to_string(command, " "); + log_debug(DEBUG_NOTICE) + << format("Running command: %1%") % commandstring << endl; + if (this->authstat->get_uid() == 0 || this->authstat->get_ruid() != this->authstat->get_uid()) + syslog(LOG_USER|LOG_NOTICE, "[%s chroot] (%s->%s) Running command: \"%s\"", + session_chroot->get_name().c_str(), this->authstat->get_ruser().c_str(), this->authstat->get_user().c_str(), commandstring.c_str()); + + if (session_chroot->get_verbosity() == chroot::chroot::VERBOSITY_VERBOSE) + { + std::string format_string; + if (this->authstat->get_ruid() == this->authstat->get_uid()) + // TRANSLATORS: %1% = chroot name + // TRANSLATORS: %4% = command + format_string = _("[%1% chroot] Running command: “%4%”"); + else + // TRANSLATORS: %1% = chroot name + // TRANSLATORS: %2% = user name + // TRANSLATORS: %3% = user name + // TRANSLATORS: %4% = command + // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 + format_string = (_("[%1% chroot] (%2%→%3%) Running command: “%4%”")); + + format fmt(format_string); + fmt % session_chroot->get_name() + % this->authstat->get_ruser() % this->authstat->get_user() + % commandstring; + log_info() << fmt << endl; + } + } - if (session_chroot->get_verbosity() == chroot::chroot::VERBOSITY_VERBOSE) - { - std::string format_string; - if (this->authstat->get_ruid() == this->authstat->get_uid()) - { - if (login_shell) - // TRANSLATORS: %1% = chroot name - // TRANSLATORS: %4% = command - format_string = _("[%1% chroot] Running login shell: ‘%4%’"); - else - // TRANSLATORS: %1% = chroot name - // TRANSLATORS: %4% = command - format_string = _("[%1% chroot] Running shell: ‘%4%’"); - } - else - { - if (login_shell) - // TRANSLATORS: %1% = chroot name - // TRANSLATORS: %2% = user name - // TRANSLATORS: %3% = user name - // TRANSLATORS: %4% = command - // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 - format_string = _("[%1% chroot] (%2%→%3%) Running login shell: ‘%4%’"); - else - // TRANSLATORS: %1% = chroot name - // TRANSLATORS: %2% = user name - // TRANSLATORS: %3% = user name - // TRANSLATORS: %4% = command - // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 - format_string = _("[%1% chroot] (%2%→%3%) Running shell: ‘%4%’"); - } - - format fmt(format_string); - fmt % session_chroot->get_name() - % this->authstat->get_ruser() % this->authstat->get_user() - % shell; - log_info() << fmt << endl; - } -} + void + session::setup_chroot (chroot::chroot::ptr& session_chroot, + chroot::chroot::setup_type setup_type) + { + assert(!session_chroot->get_name().empty()); -void -session::get_user_command (chroot::chroot::ptr& session_chroot, - std::string& file, - string_list& command, - environment const& env) const -{ - /* Search for program in path. */ - std::string path; - if (!env.get("PATH", path)) - path.clear(); - - file = find_program_in_path(command[0], path, ""); - if (file.empty()) - file = command[0]; - std::string commandstring = string_list_to_string(command, " "); - log_debug(DEBUG_NOTICE) - << format("Running command: %1%") % commandstring << endl; - if (this->authstat->get_uid() == 0 || this->authstat->get_ruid() != this->authstat->get_uid()) - syslog(LOG_USER|LOG_NOTICE, "[%s chroot] (%s->%s) Running command: \"%s\"", - session_chroot->get_name().c_str(), this->authstat->get_ruser().c_str(), this->authstat->get_user().c_str(), commandstring.c_str()); - - if (session_chroot->get_verbosity() == chroot::chroot::VERBOSITY_VERBOSE) - { - std::string format_string; - if (this->authstat->get_ruid() == this->authstat->get_uid()) - // TRANSLATORS: %1% = chroot name - // TRANSLATORS: %4% = command - format_string = _("[%1% chroot] Running command: “%4%”"); - else - // TRANSLATORS: %1% = chroot name - // TRANSLATORS: %2% = user name - // TRANSLATORS: %3% = user name - // TRANSLATORS: %4% = command - // TRANSLATORS: Please translate "->" as a right arrow, e.g. U+2192 - format_string = (_("[%1% chroot] (%2%→%3%) Running command: “%4%”")); - - format fmt(format_string); - fmt % session_chroot->get_name() - % this->authstat->get_ruser() % this->authstat->get_user() - % commandstring; - log_info() << fmt << endl; - } -} + log_debug(DEBUG_INFO) << format("setup_chroot: chroot=%1%, setup_type=%2%, chroot_status=%3%, lock_status=%4%") + % session_chroot->get_name() % setup_type % chroot_status % lock_status + << std::endl; -void -session::setup_chroot (chroot::chroot::ptr& session_chroot, - chroot::chroot::setup_type setup_type) -{ - assert(!session_chroot->get_name().empty()); - - log_debug(DEBUG_INFO) << format("setup_chroot: chroot=%1%, setup_type=%2%, chroot_status=%3%, lock_status=%4%") - % session_chroot->get_name() % setup_type % chroot_status % lock_status - << std::endl; - - if (!((this->session_operation == OPERATION_BEGIN && - setup_type == chroot::chroot::SETUP_START) || - (this->session_operation == OPERATION_RECOVER && - setup_type == chroot::chroot::SETUP_RECOVER) || - (this->session_operation == OPERATION_END && - setup_type == chroot::chroot::SETUP_STOP) || - (this->session_operation == OPERATION_RUN && - (setup_type == chroot::chroot::EXEC_START || - setup_type == chroot::chroot::EXEC_STOP)) || - (this->session_operation == OPERATION_AUTOMATIC && - (setup_type == chroot::chroot::SETUP_START || + if (!((this->session_operation == OPERATION_BEGIN && + setup_type == chroot::chroot::SETUP_START) || + (this->session_operation == OPERATION_RECOVER && + setup_type == chroot::chroot::SETUP_RECOVER) || + (this->session_operation == OPERATION_END && + setup_type == chroot::chroot::SETUP_STOP) || + (this->session_operation == OPERATION_RUN && + (setup_type == chroot::chroot::EXEC_START || + setup_type == chroot::chroot::EXEC_STOP)) || + (this->session_operation == OPERATION_AUTOMATIC && + (setup_type == chroot::chroot::SETUP_START || + setup_type == chroot::chroot::SETUP_STOP || + setup_type == chroot::chroot::EXEC_START || + setup_type == chroot::chroot::EXEC_STOP)))) + return; + + // Don't clean up chroot on a lock failure--it's actually in use. + if (this->lock_status == false) + return; + + if (((setup_type == chroot::chroot::SETUP_START || + setup_type == chroot::chroot::SETUP_RECOVER || setup_type == chroot::chroot::SETUP_STOP || setup_type == chroot::chroot::EXEC_START || - setup_type == chroot::chroot::EXEC_STOP)))) - return; - - // Don't clean up chroot on a lock failure--it's actually in use. - if (this->lock_status == false) - return; - - if (((setup_type == chroot::chroot::SETUP_START || - setup_type == chroot::chroot::SETUP_RECOVER || - setup_type == chroot::chroot::SETUP_STOP || - setup_type == chroot::chroot::EXEC_START || - setup_type == chroot::chroot::EXEC_STOP) && - session_chroot->get_run_setup_scripts() == false)) - return; - - if (setup_type == chroot::chroot::SETUP_START) - this->chroot_status = true; - - try - { - session_chroot->lock(setup_type); - } - catch (chroot::chroot::error const& e) - { - this->chroot_status = false; - this->lock_status = false; - try - { - // Release lock, which also removes session metadata. - session_chroot->unlock(setup_type, 0); - } - catch (chroot::chroot::error const& ignore) - { - } - throw error(session_chroot->get_name(), CHROOT_LOCK, e); - } - - std::string setup_type_string; - if (setup_type == chroot::chroot::SETUP_START) - setup_type_string = "setup-start"; - else if (setup_type == chroot::chroot::SETUP_RECOVER) - setup_type_string = "setup-recover"; - else if (setup_type == chroot::chroot::SETUP_STOP) - setup_type_string = "setup-stop"; - else if (setup_type == chroot::chroot::EXEC_START) - setup_type_string = "exec-start"; - else if (setup_type == chroot::chroot::EXEC_STOP) - setup_type_string = "exec-stop"; - - std::string chroot_status_string; - if (this->chroot_status) - chroot_status_string = "ok"; - else - chroot_status_string = "fail"; - - string_list arg_list; - arg_list.push_back(setup_type_string); - arg_list.push_back(chroot_status_string); - - /* Get a complete list of environment variables to set. We need to - query the chroot here, since this can vary depending upon the - chroot type. */ - environment env; - session_chroot->setup_env(env); - env.add("AUTH_USER", this->authstat->get_user()); - env.add("AUTH_RUSER", this->authstat->get_ruser()); - env.add("AUTH_RGROUP", this->authstat->get_rgroup()); - env.add("AUTH_UID", this->authstat->get_uid()); - env.add("AUTH_GID", this->authstat->get_gid()); - env.add("AUTH_RUID", this->authstat->get_ruid()); - env.add("AUTH_RGID", this->authstat->get_rgid()); - env.add("AUTH_HOME", this->authstat->get_home()); - env.add("AUTH_SHELL", this->authstat->get_shell()); - - env.add("VERBOSE", session_chroot->get_verbosity_string()); - env.add("MOUNT_DIR", SCHROOT_MOUNT_DIR); - env.add("LIBEXEC_DIR", SCHROOT_LIBEXEC_DIR); - env.add("SYSCONF_DIR", SCHROOT_SYSCONF_DIR); - env.add("DATA_DIR", SCHROOT_DATA_DIR); - env.add("SETUP_DATA_DIR", SCHROOT_SETUP_DATA_DIR); - env.add("PID", getpid()); - env.add("HOST", SBUILD_HOST); - env.add("HOST_OS", SBUILD_HOST_OS); - env.add("HOST_VENDOR", SBUILD_HOST_VENDOR); - env.add("HOST_CPU", SBUILD_HOST_CPU); - env.add("PLATFORM", SBUILD_PLATFORM); - - env.add("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"); - - run_parts rp(SCHROOT_CONF_SETUP_D, - true, true, 022); - rp.set_reverse(setup_type == chroot::chroot::SETUP_STOP || - setup_type == chroot::chroot::EXEC_STOP); - rp.set_verbose(session_chroot->get_verbosity() == chroot::chroot::VERBOSITY_VERBOSE); - - log_debug(DEBUG_INFO) << rp << std::endl; - - int exit_status = 0; - pid_t pid; - - if ((pid = fork()) == -1) - { - this->chroot_status = false; - throw error(session_chroot->get_name(), CHILD_FORK, strerror(errno)); - } - else if (pid == 0) - { - try - { - // The setup scripts don't use our syslog fd. - closelog(); - - if (chdir("/")) - throw error("/", CHDIR, strerror(errno)); - /* This is required to ensure the scripts run with uid=0 and gid=0, - otherwise setuid programs such as mount(8) will fail. This - should always succeed, because our euid=0 and egid=0.*/ - setuid(0); - setgid(0); - initgroups("root", 0); - - int status = rp.run(arg_list, env); - - _exit (status); - } - catch (std::exception const& e) - { - log_exception_error(e); - } - catch (...) - { - log_error() - << _("An unknown exception occurred") << std::endl; - } - _exit(EXIT_FAILURE); - } - else - { - wait_for_child(pid, exit_status); - } - - try - { - session_chroot->unlock(setup_type, exit_status); - } - catch (chroot::chroot::error const& e) - { - this->chroot_status = false; - this->lock_status = false; - throw error(session_chroot->get_name(), CHROOT_UNLOCK, e); - } - - if (exit_status != 0) - { - this->chroot_status = false; - - format fmt(_("stage=%1%")); - fmt % setup_type_string; - throw error(session_chroot->get_name(), CHROOT_SETUP, fmt.str()); - } -} + setup_type == chroot::chroot::EXEC_STOP) && + session_chroot->get_run_setup_scripts() == false)) + return; + + if (setup_type == chroot::chroot::SETUP_START) + this->chroot_status = true; + + try + { + session_chroot->lock(setup_type); + } + catch (chroot::chroot::error const& e) + { + this->chroot_status = false; + this->lock_status = false; + try + { + // Release lock, which also removes session metadata. + session_chroot->unlock(setup_type, 0); + } + catch (chroot::chroot::error const& ignore) + { + } + throw error(session_chroot->get_name(), CHROOT_LOCK, e); + } + + std::string setup_type_string; + if (setup_type == chroot::chroot::SETUP_START) + setup_type_string = "setup-start"; + else if (setup_type == chroot::chroot::SETUP_RECOVER) + setup_type_string = "setup-recover"; + else if (setup_type == chroot::chroot::SETUP_STOP) + setup_type_string = "setup-stop"; + else if (setup_type == chroot::chroot::EXEC_START) + setup_type_string = "exec-start"; + else if (setup_type == chroot::chroot::EXEC_STOP) + setup_type_string = "exec-stop"; + + std::string chroot_status_string; + if (this->chroot_status) + chroot_status_string = "ok"; + else + chroot_status_string = "fail"; + + string_list arg_list; + arg_list.push_back(setup_type_string); + arg_list.push_back(chroot_status_string); + + /* Get a complete list of environment variables to set. We need to + query the chroot here, since this can vary depending upon the + chroot type. */ + environment env; + session_chroot->setup_env(env); + env.add("AUTH_USER", this->authstat->get_user()); + env.add("AUTH_RUSER", this->authstat->get_ruser()); + env.add("AUTH_RGROUP", this->authstat->get_rgroup()); + env.add("AUTH_UID", this->authstat->get_uid()); + env.add("AUTH_GID", this->authstat->get_gid()); + env.add("AUTH_RUID", this->authstat->get_ruid()); + env.add("AUTH_RGID", this->authstat->get_rgid()); + env.add("AUTH_HOME", this->authstat->get_home()); + env.add("AUTH_SHELL", this->authstat->get_shell()); + + env.add("VERBOSE", session_chroot->get_verbosity_string()); + env.add("MOUNT_DIR", SCHROOT_MOUNT_DIR); + env.add("LIBEXEC_DIR", SCHROOT_LIBEXEC_DIR); + env.add("SYSCONF_DIR", SCHROOT_SYSCONF_DIR); + env.add("DATA_DIR", SCHROOT_DATA_DIR); + env.add("SETUP_DATA_DIR", SCHROOT_SETUP_DATA_DIR); + env.add("PID", getpid()); + env.add("HOST", SBUILD_HOST); + env.add("HOST_OS", SBUILD_HOST_OS); + env.add("HOST_VENDOR", SBUILD_HOST_VENDOR); + env.add("HOST_CPU", SBUILD_HOST_CPU); + env.add("PLATFORM", SBUILD_PLATFORM); + + env.add("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"); + + run_parts rp(SCHROOT_CONF_SETUP_D, + true, true, 022); + rp.set_reverse(setup_type == chroot::chroot::SETUP_STOP || + setup_type == chroot::chroot::EXEC_STOP); + rp.set_verbose(session_chroot->get_verbosity() == chroot::chroot::VERBOSITY_VERBOSE); + + log_debug(DEBUG_INFO) << rp << std::endl; + + int exit_status = 0; + pid_t pid; + + if ((pid = fork()) == -1) + { + this->chroot_status = false; + throw error(session_chroot->get_name(), CHILD_FORK, strerror(errno)); + } + else if (pid == 0) + { + try + { + // The setup scripts don't use our syslog fd. + closelog(); + + if (chdir("/")) + throw error("/", CHDIR, strerror(errno)); + /* This is required to ensure the scripts run with uid=0 and gid=0, + otherwise setuid programs such as mount(8) will fail. This + should always succeed, because our euid=0 and egid=0.*/ + setuid(0); + setgid(0); + initgroups("root", 0); + + int status = rp.run(arg_list, env); + + _exit (status); + } + catch (std::exception const& e) + { + log_exception_error(e); + } + catch (...) + { + log_error() + << _("An unknown exception occurred") << std::endl; + } + _exit(EXIT_FAILURE); + } + else + { + wait_for_child(pid, exit_status); + } + + try + { + session_chroot->unlock(setup_type, exit_status); + } + catch (chroot::chroot::error const& e) + { + this->chroot_status = false; + this->lock_status = false; + throw error(session_chroot->get_name(), CHROOT_UNLOCK, e); + } + + if (exit_status != 0) + { + this->chroot_status = false; + + format fmt(_("stage=%1%")); + fmt % setup_type_string; + throw error(session_chroot->get_name(), CHROOT_SETUP, fmt.str()); + } + } -void -session::run_child (chroot::chroot::ptr& session_chroot) -{ - assert(!session_chroot->get_name().empty()); + void + session::run_child (chroot::chroot::ptr& session_chroot) + { + assert(!session_chroot->get_name().empty()); - assert(!this->authstat->get_user().empty()); - assert(this->authstat->is_initialised()); // PAM must be initialised + assert(!this->authstat->get_user().empty()); + assert(this->authstat->is_initialised()); // PAM must be initialised - /* Set up environment */ - environment env; - env.set_filter(session_chroot->get_environment_filter()); + /* Set up environment */ + environment env; + env.set_filter(session_chroot->get_environment_filter()); - if (get_preserve_environment() || session_chroot->get_preserve_environment()) - env += this->authstat->get_complete_environment(); - else - env += this->authstat->get_auth_environment(); + if (get_preserve_environment() || session_chroot->get_preserve_environment()) + env += this->authstat->get_complete_environment(); + else + env += this->authstat->get_auth_environment(); - // Store before chroot call. - this->cwd = sbuild::getcwd(); - log_debug(DEBUG_INFO) << "CWD=" << this->cwd << std::endl; + // Store before chroot call. + this->cwd = sbuild::getcwd(); + log_debug(DEBUG_INFO) << "CWD=" << this->cwd << std::endl; - std::string location(session_chroot->get_path()); - log_debug(DEBUG_INFO) << "location=" << location << std::endl; + std::string location(session_chroot->get_path()); + log_debug(DEBUG_INFO) << "location=" << location << std::endl; - /* Set group ID and supplementary groups */ - if (setgid (this->authstat->get_gid())) - throw error(this->authstat->get_gid(), GROUP_SET, strerror(errno)); - log_debug(DEBUG_NOTICE) << "Set GID=" << this->authstat->get_gid() << std::endl; - if (initgroups (this->authstat->get_user().c_str(), this->authstat->get_gid())) - throw error(GROUP_SET_SUP, strerror(errno)); - log_debug(DEBUG_NOTICE) << "Set supplementary groups" << std::endl; + /* Set group ID and supplementary groups */ + if (setgid (this->authstat->get_gid())) + throw error(this->authstat->get_gid(), GROUP_SET, strerror(errno)); + log_debug(DEBUG_NOTICE) << "Set GID=" << this->authstat->get_gid() << std::endl; + if (initgroups (this->authstat->get_user().c_str(), this->authstat->get_gid())) + throw error(GROUP_SET_SUP, strerror(errno)); + log_debug(DEBUG_NOTICE) << "Set supplementary groups" << std::endl; #ifdef SBUILD_FEATURE_PERSONALITY - /* Set the process execution domain. */ - /* Will throw on failure. */ - chroot::facet::personality::const_ptr pfac = - session_chroot->get_facet<chroot::facet::personality>(); - if (pfac) - { - pfac->get_persona().set(); - log_debug(DEBUG_NOTICE) << "Set personality=" - << pfac->get_persona() << std::endl; - } - else - { - log_debug(DEBUG_NOTICE) << "Personality support unavailable" << std::endl; - } + /* Set the process execution domain. */ + /* Will throw on failure. */ + chroot::facet::personality::const_ptr pfac = + session_chroot->get_facet<chroot::facet::personality>(); + if (pfac) + { + pfac->get_persona().set(); + log_debug(DEBUG_NOTICE) << "Set personality=" + << pfac->get_persona() << std::endl; + } + else + { + log_debug(DEBUG_NOTICE) << "Personality support unavailable" << std::endl; + } #endif // SBUILD_FEATURE_PERSONALITY - /* Enter the chroot */ - if (chdir (location.c_str())) - throw error(location, CHDIR, strerror(errno)); - log_debug(DEBUG_NOTICE) << "Changed directory to " << location << std::endl; - if (::chroot (location.c_str())) - throw error(location, CHROOT, strerror(errno)); - log_debug(DEBUG_NOTICE) << "Changed root to " << location << std::endl; - - /* Set uid and check we are not still root */ - if (setuid (this->authstat->get_uid())) - throw error(this->authstat->get_uid(), USER_SET, strerror(errno)); - log_debug(DEBUG_NOTICE) << "Set UID=" << this->authstat->get_uid() << std::endl; - if (!setuid (0) && this->authstat->get_uid()) - throw error(ROOT_DROP); - if (this->authstat->get_uid()) - log_debug(DEBUG_NOTICE) << "Dropped root privileges" << std::endl; - - std::string file; - string_list command(this->authstat->get_command()); - - string_list dlist; - if (command.empty() || - command[0].empty()) // No command - dlist = get_login_directories(session_chroot, env); - else - dlist = get_command_directories(session_chroot, env); - log_debug(DEBUG_INFO) - << format("Directory fallbacks: %1%") % string_list_to_string(dlist, ", ") << endl; - - /* Attempt to chdir to current directory. */ - for (string_list::const_iterator dpos = dlist.begin(); - dpos != dlist.end(); - ++dpos) - { - if (chdir ((*dpos).c_str()) < 0) - { - error e(*dpos, CHDIR, strerror(errno)); - e.set_reason(_("The directory does not exist inside the chroot. Use the --directory option to run the command in a different directory.")); - - if (dpos + 1 == dlist.end()) - throw e; - else - log_exception_warning(e); - } - else - { - log_debug(DEBUG_NOTICE) << "Changed directory to " - << *dpos << std::endl; - if (dpos != dlist.begin()) - { - error e(CHDIR_FB, *dpos); + /* Enter the chroot */ + if (chdir (location.c_str())) + throw error(location, CHDIR, strerror(errno)); + log_debug(DEBUG_NOTICE) << "Changed directory to " << location << std::endl; + if (::chroot (location.c_str())) + throw error(location, CHROOT, strerror(errno)); + log_debug(DEBUG_NOTICE) << "Changed root to " << location << std::endl; + + /* Set uid and check we are not still root */ + if (setuid (this->authstat->get_uid())) + throw error(this->authstat->get_uid(), USER_SET, strerror(errno)); + log_debug(DEBUG_NOTICE) << "Set UID=" << this->authstat->get_uid() << std::endl; + if (!setuid (0) && this->authstat->get_uid()) + throw error(ROOT_DROP); + if (this->authstat->get_uid()) + log_debug(DEBUG_NOTICE) << "Dropped root privileges" << std::endl; + + std::string file; + string_list command(this->authstat->get_command()); + + string_list dlist; + if (command.empty() || + command[0].empty()) // No command + dlist = get_login_directories(session_chroot, env); + else + dlist = get_command_directories(session_chroot, env); + log_debug(DEBUG_INFO) + << format("Directory fallbacks: %1%") % string_list_to_string(dlist, ", ") << endl; + + /* Attempt to chdir to current directory. */ + for (string_list::const_iterator dpos = dlist.begin(); + dpos != dlist.end(); + ++dpos) + { + if (chdir ((*dpos).c_str()) < 0) + { + error e(*dpos, CHDIR, strerror(errno)); + e.set_reason(_("The directory does not exist inside the chroot. Use the --directory option to run the command in a different directory.")); + + if (dpos + 1 == dlist.end()) + throw e; + else log_exception_warning(e); - } - break; - } - } - - /* Fix up the command for exec. */ - get_command(session_chroot, file, command, env); - log_debug(DEBUG_NOTICE) << "command=" - << string_list_to_string(command, ", ") - << std::endl; - - // Add equivalents to sudo's SUDO_USER, SUDO_UID, SUDO_GID, and - // SUDO_COMMAND. - env.add(std::make_pair("SCHROOT_COMMAND", - string_list_to_string(command, " "))); - env.add(std::make_pair("SCHROOT_USER", this->authstat->get_ruser())); - env.add(std::make_pair("SCHROOT_GROUP", this->authstat->get_rgroup())); - env.add("SCHROOT_UID", this->authstat->get_ruid()); - env.add("SCHROOT_GID", this->authstat->get_rgid()); - // Add session ID. - chroot::facet::session::const_ptr psess = - session_chroot->get_facet<chroot::facet::session>(); - if (psess && psess->get_original_name().length()) - env.add("SCHROOT_CHROOT_NAME", psess->get_original_name()); - else - env.add("SCHROOT_CHROOT_NAME", session_chroot->get_name()); - if (psess && psess->get_selected_name().length()) - env.add("SCHROOT_ALIAS_NAME", psess->get_selected_name()); - else - env.add("SCHROOT_ALIAS_NAME", session_chroot->get_name()); - env.add("SCHROOT_SESSION_ID", session_chroot->get_name()); - - log_debug(DEBUG_INFO) << "Set environment:\n" << env; - - // The user's command does not use our syslog fd. - closelog(); - - // Add command prefix. - string_list full_command(session_chroot->get_command_prefix()); - if (full_command.size() > 0) - { - std::string path; - if (!env.get("PATH", path)) - path.clear(); - file = find_program_in_path(full_command[0], path, ""); - if (file.empty()) - file = full_command[0]; - } - for (const auto& arg : command) - full_command.push_back(arg); - - /* Execute */ - if (exec (file, full_command, env)) - throw error(file, EXEC, strerror(errno)); - - /* This should never be reached */ - _exit(EXIT_FAILURE); -} - -void -session::wait_for_child (pid_t pid, - int& child_status) -{ - child_status = EXIT_FAILURE; // Default exit status - - int status; - bool child_killed = false; - - while (1) - { - /* - * If we (the parent process) gets SIGHUP or SIGTERM, pass this - * signal on to the child (once). Note that we do not handle - * SIGINT this way, because when a user presses Ctrl-C, the - * SIGINT is sent to all processes attached to that TTY (so the - * child will already have gotten it). In any case, once the - * child gets the signal, we just have to continue waiting for - * it to exit. - */ - if ((sighup_called || sigterm_called) && !child_killed) - { - if (sighup_called) - { - error e(SIGNAL_CATCH, strsignal(SIGHUP), - _("terminating immediately")); - log_exception_error(e); - kill(pid, SIGHUP); - } - else // SIGTERM - { - error e(SIGNAL_CATCH, strsignal(SIGTERM), - _("terminating immediately")); - log_exception_error(e); - kill(pid, SIGTERM); - } - this->chroot_status = false; - child_killed = true; - } - - if (waitpid(pid, &status, 0) == -1) - { - if (errno == EINTR && (sighup_called || sigterm_called || sigint_called)) - continue; // Kill child and wait again. - else - throw error(CHILD_WAIT, strerror(errno)); - } - else if (sighup_called) - { - sighup_called = false; - throw error(SIGNAL_CATCH, strsignal(SIGHUP)); - } - else if (sigterm_called) - { - sigterm_called = false; - throw error(SIGNAL_CATCH, strsignal(SIGTERM)); - } - // No need to handle the SIGINT case here; it is handled - // correctly below - else - break; - } - - if (!WIFEXITED(status)) - { - if (WIFSIGNALED(status)) - throw error(CHILD_SIGNAL, strsignal(WTERMSIG(status))); - else if (WCOREDUMP(status)) - throw error(CHILD_CORE); - else - throw error(CHILD_FAIL); - } - - child_status = WEXITSTATUS(status); -} + } + else + { + log_debug(DEBUG_NOTICE) << "Changed directory to " + << *dpos << std::endl; + if (dpos != dlist.begin()) + { + error e(CHDIR_FB, *dpos); + log_exception_warning(e); + } + break; + } + } + + /* Fix up the command for exec. */ + get_command(session_chroot, file, command, env); + log_debug(DEBUG_NOTICE) << "command=" + << string_list_to_string(command, ", ") + << std::endl; + + // Add equivalents to sudo's SUDO_USER, SUDO_UID, SUDO_GID, and + // SUDO_COMMAND. + env.add(std::make_pair("SCHROOT_COMMAND", + string_list_to_string(command, " "))); + env.add(std::make_pair("SCHROOT_USER", this->authstat->get_ruser())); + env.add(std::make_pair("SCHROOT_GROUP", this->authstat->get_rgroup())); + env.add("SCHROOT_UID", this->authstat->get_ruid()); + env.add("SCHROOT_GID", this->authstat->get_rgid()); + // Add session ID. + chroot::facet::session::const_ptr psess = + session_chroot->get_facet<chroot::facet::session>(); + if (psess && psess->get_original_name().length()) + env.add("SCHROOT_CHROOT_NAME", psess->get_original_name()); + else + env.add("SCHROOT_CHROOT_NAME", session_chroot->get_name()); + if (psess && psess->get_selected_name().length()) + env.add("SCHROOT_ALIAS_NAME", psess->get_selected_name()); + else + env.add("SCHROOT_ALIAS_NAME", session_chroot->get_name()); + env.add("SCHROOT_SESSION_ID", session_chroot->get_name()); + + log_debug(DEBUG_INFO) << "Set environment:\n" << env; + + // The user's command does not use our syslog fd. + closelog(); + + // Add command prefix. + string_list full_command(session_chroot->get_command_prefix()); + if (full_command.size() > 0) + { + std::string path; + if (!env.get("PATH", path)) + path.clear(); + file = find_program_in_path(full_command[0], path, ""); + if (file.empty()) + file = full_command[0]; + } + for (const auto& arg : command) + full_command.push_back(arg); + + /* Execute */ + if (exec (file, full_command, env)) + throw error(file, EXEC, strerror(errno)); + + /* This should never be reached */ + _exit(EXIT_FAILURE); + } -void -session::run_chroot (chroot::chroot::ptr& session_chroot) -{ - assert(!session_chroot->get_name().empty()); + void + session::wait_for_child (pid_t pid, + int& child_status) + { + child_status = EXIT_FAILURE; // Default exit status + + int status; + bool child_killed = false; + + while (1) + { + /* + * If we (the parent process) gets SIGHUP or SIGTERM, pass this + * signal on to the child (once). Note that we do not handle + * SIGINT this way, because when a user presses Ctrl-C, the + * SIGINT is sent to all processes attached to that TTY (so the + * child will already have gotten it). In any case, once the + * child gets the signal, we just have to continue waiting for + * it to exit. + */ + if ((sighup_called || sigterm_called) && !child_killed) + { + if (sighup_called) + { + error e(SIGNAL_CATCH, strsignal(SIGHUP), + _("terminating immediately")); + log_exception_error(e); + kill(pid, SIGHUP); + } + else // SIGTERM + { + error e(SIGNAL_CATCH, strsignal(SIGTERM), + _("terminating immediately")); + log_exception_error(e); + kill(pid, SIGTERM); + } + this->chroot_status = false; + child_killed = true; + } + + if (waitpid(pid, &status, 0) == -1) + { + if (errno == EINTR && (sighup_called || sigterm_called || sigint_called)) + continue; // Kill child and wait again. + else + throw error(CHILD_WAIT, strerror(errno)); + } + else if (sighup_called) + { + sighup_called = false; + throw error(SIGNAL_CATCH, strsignal(SIGHUP)); + } + else if (sigterm_called) + { + sigterm_called = false; + throw error(SIGNAL_CATCH, strsignal(SIGTERM)); + } + // No need to handle the SIGINT case here; it is handled + // correctly below + else + break; + } + + if (!WIFEXITED(status)) + { + if (WIFSIGNALED(status)) + throw error(CHILD_SIGNAL, strsignal(WTERMSIG(status))); + else if (WCOREDUMP(status)) + throw error(CHILD_CORE); + else + throw error(CHILD_FAIL); + } + + child_status = WEXITSTATUS(status); + } - pid_t pid; - if ((pid = fork()) == -1) - { - throw error(CHILD_FORK, strerror(errno)); - } - else if (pid == 0) - { + void + session::run_chroot (chroot::chroot::ptr& session_chroot) + { + assert(!session_chroot->get_name().empty()); + + pid_t pid; + if ((pid = fork()) == -1) + { + throw error(CHILD_FORK, strerror(errno)); + } + else if (pid == 0) + { #ifdef SBUILD_DEBUG - while (child_wait) - ; + while (child_wait) + ; #endif - try - { - run_child(session_chroot); - } - catch (std::runtime_error const& e) - { - log_exception_error(e); - } - catch (...) - { - log_error() - << _("An unknown exception occurred") << std::endl; - } - _exit (EXIT_FAILURE); - } - else - { - wait_for_child(pid, this->child_status); - } -} + try + { + run_child(session_chroot); + } + catch (std::runtime_error const& e) + { + log_exception_error(e); + } + catch (...) + { + log_error() + << _("An unknown exception occurred") << std::endl; + } + _exit (EXIT_FAILURE); + } + else + { + wait_for_child(pid, this->child_status); + } + } -void -session::set_sighup_handler () -{ - set_signal_handler(SIGHUP, &this->saved_sighup_signal, sighup_handler); -} + void + session::set_sighup_handler () + { + set_signal_handler(SIGHUP, &this->saved_sighup_signal, sighup_handler); + } -void -session::clear_sighup_handler () -{ - clear_signal_handler(SIGHUP, &this->saved_sighup_signal); -} + void + session::clear_sighup_handler () + { + clear_signal_handler(SIGHUP, &this->saved_sighup_signal); + } -void -session::set_sigint_handler () -{ - set_signal_handler(SIGINT, &this->saved_sigint_signal, sigint_handler); -} + void + session::set_sigint_handler () + { + set_signal_handler(SIGINT, &this->saved_sigint_signal, sigint_handler); + } -void -session::clear_sigint_handler () -{ - clear_signal_handler(SIGINT, &this->saved_sigint_signal); -} + void + session::clear_sigint_handler () + { + clear_signal_handler(SIGINT, &this->saved_sigint_signal); + } -void -session::set_sigterm_handler () -{ - set_signal_handler(SIGTERM, &this->saved_sigterm_signal, sigterm_handler); -} + void + session::set_sigterm_handler () + { + set_signal_handler(SIGTERM, &this->saved_sigterm_signal, sigterm_handler); + } -void -session::clear_sigterm_handler () -{ - clear_signal_handler(SIGTERM, &this->saved_sigterm_signal); -} + void + session::clear_sigterm_handler () + { + clear_signal_handler(SIGTERM, &this->saved_sigterm_signal); + } -void -session::set_signal_handler (int signal, - struct sigaction *saved_signal, - void (*handler)(int)) -{ - struct sigaction new_sa; - sigemptyset(&new_sa.sa_mask); - new_sa.sa_flags = 0; - new_sa.sa_handler = handler; + void + session::set_signal_handler (int signal, + struct sigaction *saved_signal, + void (*handler)(int)) + { + struct sigaction new_sa; + sigemptyset(&new_sa.sa_mask); + new_sa.sa_flags = 0; + new_sa.sa_handler = handler; - if (sigaction(signal, &new_sa, saved_signal) != 0) - throw error(SIGNAL_SET, strsignal(signal), strerror(errno)); -} + if (sigaction(signal, &new_sa, saved_signal) != 0) + throw error(SIGNAL_SET, strsignal(signal), strerror(errno)); + } + + void + session::clear_signal_handler (int signal, + struct sigaction *saved_signal) + { + /* Restore original handler */ + sigaction (signal, saved_signal, 0); + } -void -session::clear_signal_handler (int signal, - struct sigaction *saved_signal) -{ - /* Restore original handler */ - sigaction (signal, saved_signal, 0); } diff --git a/lib/sbuild/types.cc b/lib/sbuild/types.cc index d033c84e..2b2501f9 100644 --- a/lib/sbuild/types.cc +++ b/lib/sbuild/types.cc @@ -21,24 +21,27 @@ #include <sbuild/types.h> #include <sbuild/i18n.h> -using namespace sbuild; - -const char * -sbuild::date_base::get_date_format () const +namespace sbuild { - // TRANSLATORS: Format string for date representation: - // %d = day (number, e.g. 14) - // %b = month (three letters, e.g. Jul) - // %Y = year (four digits, e.g. 2006) - // If required, any of the standard strftime(3) - // format specifiers may be used instead, as long as - // the day, month and year are clearly displayed in - // the equivalent standard method for your locale. - return _("%d %b %Y"); -} -const char * -sbuild::isodate::get_date_format () const -{ - return "%Y-%m-%dT%H:%M:%SZ"; + const char * + date_base::get_date_format () const + { + // TRANSLATORS: Format string for date representation: + // %d = day (number, e.g. 14) + // %b = month (three letters, e.g. Jul) + // %Y = year (four digits, e.g. 2006) + // If required, any of the standard strftime(3) + // format specifiers may be used instead, as long as + // the day, month and year are clearly displayed in + // the equivalent standard method for your locale. + return _("%d %b %Y"); + } + + const char * + isodate::get_date_format () const + { + return "%Y-%m-%dT%H:%M:%SZ"; + } + } diff --git a/lib/sbuild/util.cc b/lib/sbuild/util.cc index 68cf9a1f..44058e94 100644 --- a/lib/sbuild/util.cc +++ b/lib/sbuild/util.cc @@ -31,738 +31,741 @@ #include <boost/filesystem/convenience.hpp> -using namespace sbuild; - -namespace +namespace sbuild { - /** - * Remove duplicate adjacent characters from a string. - * - * @param str the string to check. - * @param dup the duplicate character to check for. - * @returns a string with any duplicates removed. - */ - std::string remove_duplicates (std::string const& str, - char dup) + namespace { - std::string ret; - for (std::string::size_type pos = 0; - pos < str.length(); - ++pos) - { - ret += str[pos]; - if (str[pos] == dup) - { - while (pos + 1 < str.length() && - str[pos + 1] == dup) - ++pos; - } - } + /** + * Remove duplicate adjacent characters from a string. + * + * @param str the string to check. + * @param dup the duplicate character to check for. + * @returns a string with any duplicates removed. + */ + std::string remove_duplicates (std::string const& str, + char dup) + { + std::string ret; - return ret; - } + for (std::string::size_type pos = 0; + pos < str.length(); + ++pos) + { + ret += str[pos]; + if (str[pos] == dup) + { + while (pos + 1 < str.length() && + str[pos + 1] == dup) + ++pos; + } + } + return ret; + } -} -template<> -error<sbuild::stat::error_code>::map_type -error<sbuild::stat::error_code>::error_strings = + } + + template<> + error<stat::error_code>::map_type + error<stat::error_code>::error_strings = + { + {stat::FILE, N_("Failed to stat file")}, + {stat::FD, N_("Failed to stat file descriptor")} + }; + + std::string + basename (std::string name) { - {sbuild::stat::FILE, N_("Failed to stat file")}, - {sbuild::stat::FD, N_("Failed to stat file descriptor")} - }; + const char separator = '/'; -std::string -sbuild::basename (std::string name) -{ - const char separator = '/'; - - // Remove trailing separators - std::string::size_type cur = name.length(); - while (cur - 1 != 0 && name[cur - 1] == separator) - --cur; - name.resize(cur); - - // Find last separator - std::string::size_type pos = name.rfind(separator); - - std::string ret; - if (pos == std::string::npos) - ret = name; // No separators - else if (pos == 0 && name.length() == 1 && name[0] == separator) - ret = separator; // Only separators - else - ret = name.substr(pos + 1); // Basename only - - return remove_duplicates(ret, separator); -} + // Remove trailing separators + std::string::size_type cur = name.length(); + while (cur - 1 != 0 && name[cur - 1] == separator) + --cur; + name.resize(cur); -std::string -sbuild::dirname (std::string name) -{ - const char separator = '/'; - - // Remove trailing separators - std::string::size_type cur = name.length(); - while (cur - 1 != 0 && name[cur - 1] == separator) - --cur; - name.resize(cur); - - // Find last separator - std::string::size_type pos = name.rfind(separator); - - std::string ret; - if (pos == std::string::npos) - ret = "."; // No directory components - else if (pos == 0) - ret = separator; - else - ret = name.substr(0, pos); // Dirname part - - return remove_duplicates(ret, separator); -} + // Find last separator + std::string::size_type pos = name.rfind(separator); -std::string -sbuild::normalname (std::string name) -{ - const char separator = '/'; + std::string ret; + if (pos == std::string::npos) + ret = name; // No separators + else if (pos == 0 && name.length() == 1 && name[0] == separator) + ret = separator; // Only separators + else + ret = name.substr(pos + 1); // Basename only + + return remove_duplicates(ret, separator); + } - // Remove trailing separators - std::string::size_type cur = name.length(); - while (cur - 1 != 0 && name[cur - 1] == separator) - --cur; - name.resize(cur); + std::string + dirname (std::string name) + { + const char separator = '/'; - return remove_duplicates(name, separator); -} + // Remove trailing separators + std::string::size_type cur = name.length(); + while (cur - 1 != 0 && name[cur - 1] == separator) + --cur; + name.resize(cur); -bool -sbuild::is_absname (std::string const& name) -{ - if (name.empty() || name[0] != '/') - return false; - else - return true; -} + // Find last separator + std::string::size_type pos = name.rfind(separator); -bool -sbuild::is_valid_sessionname (std::string const& name) -{ - bool match = false; + std::string ret; + if (pos == std::string::npos) + ret = "."; // No directory components + else if (pos == 0) + ret = separator; + else + ret = name.substr(0, pos); // Dirname part + + return remove_duplicates(ret, separator); + } + + std::string + normalname (std::string name) + { + const char separator = '/'; - static regex file_namespace("^[^:/,.][^:/,]*$"); - static regex editor_backup("~$"); - static regex debian_dpkg_conffile_cruft("dpkg-(old|dist|new|tmp)$"); + // Remove trailing separators + std::string::size_type cur = name.length(); + while (cur - 1 != 0 && name[cur - 1] == separator) + --cur; + name.resize(cur); - if (regex_search(name, file_namespace) && - !regex_search(name, editor_backup) && - !regex_search(name, debian_dpkg_conffile_cruft)) { - match = true; + return remove_duplicates(name, separator); } - return match; -} + bool + is_absname (std::string const& name) + { + if (name.empty() || name[0] != '/') + return false; + else + return true; + } -bool -sbuild::is_valid_filename (std::string const& name, - bool lsb_mode) -{ - bool match = false; + bool + is_valid_sessionname (std::string const& name) + { + bool match = false; - if (lsb_mode) - { - static regex lanana_namespace("^[a-z0-9]+$"); - static regex lsb_namespace("^_?([a-z0-9_.]+-)+[a-z0-9]+$"); - static regex debian_cron_namespace("^[a-z0-9][a-z0-9-]*$"); - static regex debian_dpkg_conffile_cruft("dpkg-(old|dist|new|tmp)$"); - - if ((regex_search(name, lanana_namespace) || - regex_search(name, lsb_namespace) || - regex_search(name, debian_cron_namespace)) && - !regex_search(name, debian_dpkg_conffile_cruft)) - match = true; - } - else - { - static regex traditional_namespace("^[a-zA-Z0-9_-]$"); - if (regex_search(name, traditional_namespace)) - match = true; + static regex file_namespace("^[^:/,.][^:/,]*$"); + static regex editor_backup("~$"); + static regex debian_dpkg_conffile_cruft("dpkg-(old|dist|new|tmp)$"); + + if (regex_search(name, file_namespace) && + !regex_search(name, editor_backup) && + !regex_search(name, debian_dpkg_conffile_cruft)) { + match = true; } - return match; -} + return match; + } -std::string -sbuild::getcwd () -{ - std::string cwd; + bool + is_valid_filename (std::string const& name, + bool lsb_mode) + { + bool match = false; - char *raw_cwd = ::getcwd (0, 0); - if (raw_cwd) - cwd = raw_cwd; - else - cwd = "/"; - free(raw_cwd); + if (lsb_mode) + { + static regex lanana_namespace("^[a-z0-9]+$"); + static regex lsb_namespace("^_?([a-z0-9_.]+-)+[a-z0-9]+$"); + static regex debian_cron_namespace("^[a-z0-9][a-z0-9-]*$"); + static regex debian_dpkg_conffile_cruft("dpkg-(old|dist|new|tmp)$"); + + if ((regex_search(name, lanana_namespace) || + regex_search(name, lsb_namespace) || + regex_search(name, debian_cron_namespace)) && + !regex_search(name, debian_dpkg_conffile_cruft)) + match = true; + } + else + { + static regex traditional_namespace("^[a-zA-Z0-9_-]$"); + if (regex_search(name, traditional_namespace)) + match = true; + } - return cwd; -} + return match; + } -std::string -sbuild::unique_identifier () -{ - std::ostringstream id; - id.imbue(std::locale::classic()); + std::string + getcwd () + { + std::string cwd; - struct timeval tv; - gettimeofday(&tv, nullptr); + char *raw_cwd = ::getcwd (0, 0); + if (raw_cwd) + cwd = raw_cwd; + else + cwd = "/"; + free(raw_cwd); - uint64_t bits = static_cast<uint64_t>(tv.tv_usec << 16) ^ tv.tv_sec; - static const std::string letters("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); - std::string ids; - for (int i=0; i<6; ++i) - { - ids += letters[bits % 62]; - bits /= 62; - } + return cwd; + } - id << ids << '-' << getpid(); + std::string + unique_identifier () + { + std::ostringstream id; + id.imbue(std::locale::classic()); - return id.str(); -} + struct timeval tv; + gettimeofday(&tv, nullptr); -std::string -sbuild::string_list_to_string (string_list const& list, - std::string const& separator) -{ - std::string ret; + uint64_t bits = static_cast<uint64_t>(tv.tv_usec << 16) ^ tv.tv_sec; + static const std::string letters("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); + std::string ids; + for (int i=0; i<6; ++i) + { + ids += letters[bits % 62]; + bits /= 62; + } - for (string_list::const_iterator cur = list.begin(); - cur != list.end(); - ++cur) - { - ret += *cur; - if (cur + 1 != list.end()) - ret += separator; - } + id << ids << '-' << getpid(); - return ret; -} + return id.str(); + } -string_list -sbuild::split_string (std::string const& value, - std::string const& separator) -{ - string_list ret; + std::string + string_list_to_string (string_list const& list, + std::string const& separator) + { + std::string ret; - // Skip any separators at the start - std::string::size_type last_pos = - value.find_first_not_of(separator, 0); - // Find first separator. - std::string::size_type pos = value.find_first_of(separator, last_pos); + for (string_list::const_iterator cur = list.begin(); + cur != list.end(); + ++cur) + { + ret += *cur; + if (cur + 1 != list.end()) + ret += separator; + } - while (pos !=std::string::npos || last_pos != std::string::npos) - { - // Add to list - if (pos == std::string::npos) - // Entire string from last_pos - ret.push_back(value.substr(last_pos, pos)); - else - // Between pos and last_pos - ret.push_back(value.substr(last_pos, pos - last_pos)); - - // Find next - last_pos = value.find_first_not_of(separator, pos); - pos = value.find_first_of(separator, last_pos); - } + return ret; + } - return ret; -} + string_list + split_string (std::string const& value, + std::string const& separator) + { + string_list ret; -string_list -sbuild::split_string_strict (std::string const& value, - std::string const& separator) -{ - string_list ret; + // Skip any separators at the start + std::string::size_type last_pos = + value.find_first_not_of(separator, 0); + // Find first separator. + std::string::size_type pos = value.find_first_of(separator, last_pos); - std::string::size_type last_pos = 0; - // Find first separator. - std::string::size_type pos = value.find_first_of(separator, last_pos); + while (pos !=std::string::npos || last_pos != std::string::npos) + { + // Add to list + if (pos == std::string::npos) + // Entire string from last_pos + ret.push_back(value.substr(last_pos, pos)); + else + // Between pos and last_pos + ret.push_back(value.substr(last_pos, pos - last_pos)); + + // Find next + last_pos = value.find_first_not_of(separator, pos); + pos = value.find_first_of(separator, last_pos); + } - while (pos !=std::string::npos) - { - // Add to list - if (pos == std::string::npos) - // Entire string from last_pos - ret.push_back(value.substr(last_pos, pos)); - else - // Between pos and last_pos - ret.push_back(value.substr(last_pos, pos - last_pos)); - - // Find next - last_pos = pos + separator.length(); - pos = value.find_first_of(separator, last_pos); - } + return ret; + } - return ret; -} + string_list + split_string_strict (std::string const& value, + std::string const& separator) + { + string_list ret; -std::wstring -sbuild::widen_string (std::string const& str, - std::locale locale) -{ - typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type; - codecvt_type const& cvt = std::use_facet<codecvt_type>(locale); - mbstate_t state; - const char *cbegin = str.data(), *cend = str.data() + str.size(), *cnext; - wchar_t *wcnext; - wchar_t wcbuf[80]; - std::wstring ret; + std::string::size_type last_pos = 0; + // Find first separator. + std::string::size_type pos = value.find_first_of(separator, last_pos); - std::memset(&state, 0, sizeof(mbstate_t)); + while (pos !=std::string::npos) + { + // Add to list + if (pos == std::string::npos) + // Entire string from last_pos + ret.push_back(value.substr(last_pos, pos)); + else + // Between pos and last_pos + ret.push_back(value.substr(last_pos, pos - last_pos)); + + // Find next + last_pos = pos + separator.length(); + pos = value.find_first_of(separator, last_pos); + } - while (1) - { - std::codecvt_base::result res = - cvt.in(state, - cbegin, cend, cnext, - wcbuf, wcbuf + (sizeof(wcbuf) / sizeof(wcbuf[0])), wcnext); + return ret; + } - if (res == std::codecvt_base::ok || res == std::codecvt_base::partial) - { - ret += std::wstring(wcbuf, wcnext); - if (cend == cnext) + std::wstring + widen_string (std::string const& str, + std::locale locale) + { + typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type; + codecvt_type const& cvt = std::use_facet<codecvt_type>(locale); + mbstate_t state; + const char *cbegin = str.data(), *cend = str.data() + str.size(), *cnext; + wchar_t *wcnext; + wchar_t wcbuf[80]; + std::wstring ret; + + std::memset(&state, 0, sizeof(mbstate_t)); + + while (1) + { + std::codecvt_base::result res = + cvt.in(state, + cbegin, cend, cnext, + wcbuf, wcbuf + (sizeof(wcbuf) / sizeof(wcbuf[0])), wcnext); + + if (res == std::codecvt_base::ok || res == std::codecvt_base::partial) + { + ret += std::wstring(wcbuf, wcnext); + if (cend == cnext) + break; + } + else if (res == std::codecvt_base::noconv) + { + ret += std::wstring(cbegin, cend); break; - } - else if (res == std::codecvt_base::noconv) - { - ret += std::wstring(cbegin, cend); - break; - } - else if (res == std::codecvt_base::error) - { - throw std::runtime_error - ("A character set conversion failed. Please report this bug."); + } + else if (res == std::codecvt_base::error) + { + throw std::runtime_error + ("A character set conversion failed. Please report this bug."); + break; + } + else break; - } - else - break; - cbegin = cnext; - } + cbegin = cnext; + } - return ret; -} + return ret; + } -std::string -sbuild::narrow_string (std::wstring const& str, - std::locale locale) -{ - typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type; - codecvt_type const& cvt = std::use_facet<codecvt_type>(locale); - mbstate_t state; - const wchar_t *wcbegin = str.data(), *wcend = str.data() + str.size(), *wcnext; - char *cnext; - char cbuf[80]; - std::string ret; + std::string + narrow_string (std::wstring const& str, + std::locale locale) + { + typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type; + codecvt_type const& cvt = std::use_facet<codecvt_type>(locale); + mbstate_t state; + const wchar_t *wcbegin = str.data(), *wcend = str.data() + str.size(), *wcnext; + char *cnext; + char cbuf[80]; + std::string ret; - std::memset(&state, 0, sizeof(mbstate_t)); + std::memset(&state, 0, sizeof(mbstate_t)); - while (1) - { - std::codecvt_base::result res = - cvt.out(state, - wcbegin, wcend, wcnext, - cbuf, cbuf + (sizeof(cbuf) / sizeof(cbuf[0])), cnext); + while (1) + { + std::codecvt_base::result res = + cvt.out(state, + wcbegin, wcend, wcnext, + cbuf, cbuf + (sizeof(cbuf) / sizeof(cbuf[0])), cnext); - if (res == std::codecvt_base::ok || res == std::codecvt_base::partial) - { - ret += std::string(cbuf, cnext); - if (wcend == wcnext) + if (res == std::codecvt_base::ok || res == std::codecvt_base::partial) + { + ret += std::string(cbuf, cnext); + if (wcend == wcnext) + break; + } + else if (res == std::codecvt_base::noconv) + { + ret += std::string(wcbegin, wcend); break; - } - else if (res == std::codecvt_base::noconv) - { - ret += std::string(wcbegin, wcend); - break; - } - else if (res == std::codecvt_base::error) - { - throw std::runtime_error - ("A character set conversion failed. Please report this bug."); + } + else if (res == std::codecvt_base::error) + { + throw std::runtime_error + ("A character set conversion failed. Please report this bug."); + break; + } + else break; - } - else - break; - wcbegin = wcnext; - } + wcbegin = wcnext; + } - return ret; -} + return ret; + } -std::string -sbuild::find_program_in_path (std::string const& program, - std::string const& path, - std::string const& prefix) -{ - if (program.find_first_of('/') != std::string::npos) - return program; + std::string + find_program_in_path (std::string const& program, + std::string const& path, + std::string const& prefix) + { + if (program.find_first_of('/') != std::string::npos) + return program; - string_list dirs = split_string(path, std::string(1, ':')); + string_list dirs = split_string(path, std::string(1, ':')); - for (const auto& dir : dirs) - { - std::string realname = dir + '/' + program; - std::string absname; - if (prefix.length() > 0) - { - absname = prefix; - if (dir.length() > 0 && (dir)[0] != '/') - absname += '/'; - } - absname += realname; + for (const auto& dir : dirs) + { + std::string realname = dir + '/' + program; + std::string absname; + if (prefix.length() > 0) + { + absname = prefix; + if (dir.length() > 0 && (dir)[0] != '/') + absname += '/'; + } + absname += realname; - try - { - if (stat(absname).is_regular() && - access (absname.c_str(), X_OK) == 0) - return realname; - } - catch (std::runtime_error const& e) - { - } - } + try + { + if (stat(absname).is_regular() && + access (absname.c_str(), X_OK) == 0) + return realname; + } + catch (std::runtime_error const& e) + { + } + } - return ""; -} + return ""; + } -char ** -sbuild::string_list_to_strv (string_list const& str) -{ - char **ret = new char *[str.size() + 1]; + char ** + string_list_to_strv (string_list const& str) + { + char **ret = new char *[str.size() + 1]; - for (string_list::size_type i = 0; - i < str.size(); - ++i) - { - ret[i] = new char[str[i].length() + 1]; - std::strcpy(ret[i], str[i].c_str()); - } - ret[str.size()] = 0; + for (string_list::size_type i = 0; + i < str.size(); + ++i) + { + ret[i] = new char[str[i].length() + 1]; + std::strcpy(ret[i], str[i].c_str()); + } + ret[str.size()] = 0; - return ret; -} + return ret; + } -void -sbuild::strv_delete (char **strv) -{ - for (char **pos = strv; pos != 0 && *pos != 0; ++pos) - delete *pos; - delete[] strv; -} + void + strv_delete (char **strv) + { + for (char **pos = strv; pos != 0 && *pos != 0; ++pos) + delete *pos; + delete[] strv; + } -int -sbuild::exec (std::string const& file, - string_list const& command, - environment const& env) -{ - char **argv = string_list_to_strv(command); - char **envp = env.get_strv(); - int status; + int + exec (std::string const& file, + string_list const& command, + environment const& env) + { + char **argv = string_list_to_strv(command); + char **envp = env.get_strv(); + int status; - if ((status = execve(file.c_str(), argv, envp)) != 0) - { - strv_delete(argv); - strv_delete(envp); - } + if ((status = execve(file.c_str(), argv, envp)) != 0) + { + strv_delete(argv); + strv_delete(envp); + } - return status; -} + return status; + } -sbuild::stat::stat (const char *file, - bool link): - file(file), - fd(0), - errorno(0), - status() -{ - if (link) - { - if (::lstat(file, &this->status) < 0) - this->errorno = errno; - } - else - { - if (::stat(file, &this->status) < 0) - this->errorno = errno; - } -} + stat::stat (const char *file, + bool link): + file(file), + fd(0), + errorno(0), + status() + { + if (link) + { + if (::lstat(file, &this->status) < 0) + this->errorno = errno; + } + else + { + if (::stat(file, &this->status) < 0) + this->errorno = errno; + } + } -sbuild::stat::stat (std::string const& file, - bool link): - file(file), - fd(0), - errorno(0), - status() -{ - if (link) - { - if (::lstat(file.c_str(), &this->status) < 0) - this->errorno = errno; - } - else - { - if (::stat(file.c_str(), &this->status) < 0) - this->errorno = errno; - } -} + stat::stat (std::string const& file, + bool link): + file(file), + fd(0), + errorno(0), + status() + { + if (link) + { + if (::lstat(file.c_str(), &this->status) < 0) + this->errorno = errno; + } + else + { + if (::stat(file.c_str(), &this->status) < 0) + this->errorno = errno; + } + } -sbuild::stat::stat (std::string const& file, - int fd): - file(file), - fd(fd), - errorno(0), - status() -{ - if (::fstat(fd, &this->status) < 0) - this->errorno = errno; -} + stat::stat (std::string const& file, + int fd): + file(file), + fd(fd), + errorno(0), + status() + { + if (::fstat(fd, &this->status) < 0) + this->errorno = errno; + } -sbuild::stat::stat (int fd): - file(), - fd(fd), - errorno(0), - status() -{ - if (::fstat(fd, &this->status) < 0) - this->errorno = errno; -} + stat::stat (int fd): + file(), + fd(fd), + errorno(0), + status() + { + if (::fstat(fd, &this->status) < 0) + this->errorno = errno; + } -sbuild::stat::~stat () -{ -} + stat::~stat () + { + } -sbuild::passwd::passwd (): - ::passwd(), - buffer(), - valid(false) -{ - clear(); -} + passwd::passwd (): + ::passwd(), + buffer(), + valid(false) + { + clear(); + } -sbuild::passwd::passwd (uid_t uid): - ::passwd(), - buffer(), - valid(false) -{ - clear(); + passwd::passwd (uid_t uid): + ::passwd(), + buffer(), + valid(false) + { + clear(); - query_uid(uid); -} + query_uid(uid); + } -sbuild::passwd::passwd (const char *name): - ::passwd(), - buffer(), - valid(false) -{ - clear(); + passwd::passwd (const char *name): + ::passwd(), + buffer(), + valid(false) + { + clear(); - query_name(name); -} + query_name(name); + } -sbuild::passwd::passwd (std::string const& name): - ::passwd(), - buffer(), - valid(false) -{ - clear(); + passwd::passwd (std::string const& name): + ::passwd(), + buffer(), + valid(false) + { + clear(); - query_name(name); -} + query_name(name); + } -void -sbuild::passwd::clear () -{ - valid = false; + void + passwd::clear () + { + valid = false; - buffer.clear(); + buffer.clear(); - ::passwd::pw_name = 0; - ::passwd::pw_passwd = 0; - ::passwd::pw_uid = 0; - ::passwd::pw_gid = 0; - ::passwd::pw_gecos = 0; - ::passwd::pw_dir = 0; - ::passwd::pw_shell = 0; -} + ::passwd::pw_name = 0; + ::passwd::pw_passwd = 0; + ::passwd::pw_uid = 0; + ::passwd::pw_gid = 0; + ::passwd::pw_gecos = 0; + ::passwd::pw_dir = 0; + ::passwd::pw_shell = 0; + } -void -sbuild::passwd::query_uid (uid_t uid) -{ - buffer_type::size_type size = 1 << 7; - buffer.reserve(size); - int error; + void + passwd::query_uid (uid_t uid) + { + buffer_type::size_type size = 1 << 7; + buffer.reserve(size); + int error; - ::passwd *pwd_result; + ::passwd *pwd_result; - while ((error = getpwuid_r(uid, this, - &buffer[0], buffer.capacity(), - &pwd_result))) - { - size <<= 1; - buffer.reserve(size); - } + while ((error = getpwuid_r(uid, this, + &buffer[0], buffer.capacity(), + &pwd_result))) + { + size <<= 1; + buffer.reserve(size); + } - if (pwd_result) - valid = true; - else - errno = error; -} + if (pwd_result) + valid = true; + else + errno = error; + } -void -sbuild::passwd::query_name (const char *name) -{ - buffer_type::size_type size = 1 << 8; - buffer.reserve(size); - int error; + void + passwd::query_name (const char *name) + { + buffer_type::size_type size = 1 << 8; + buffer.reserve(size); + int error; - ::passwd *pwd_result; + ::passwd *pwd_result; - while ((error = getpwnam_r(name, this, - &buffer[0], buffer.capacity(), - &pwd_result))) - { - size <<= 1; - buffer.reserve(size); - } + while ((error = getpwnam_r(name, this, + &buffer[0], buffer.capacity(), + &pwd_result))) + { + size <<= 1; + buffer.reserve(size); + } - if (pwd_result) - valid = true; - else - errno = error; -} + if (pwd_result) + valid = true; + else + errno = error; + } -void -sbuild::passwd::query_name (std::string const& name) -{ - query_name(name.c_str()); -} + void + passwd::query_name (std::string const& name) + { + query_name(name.c_str()); + } -bool -sbuild::passwd::operator ! () const -{ - return !valid; -} + bool + passwd::operator ! () const + { + return !valid; + } -sbuild::group::group (): - ::group(), - buffer(), - valid(false) -{ - clear(); -} + group::group (): + ::group(), + buffer(), + valid(false) + { + clear(); + } -sbuild::group::group (gid_t gid): - ::group(), - buffer(), - valid(false) -{ - clear(); + group::group (gid_t gid): + ::group(), + buffer(), + valid(false) + { + clear(); - query_gid(gid); -} + query_gid(gid); + } -sbuild::group::group (const char *name): - ::group(), - buffer(), - valid(false) -{ - clear(); + group::group (const char *name): + ::group(), + buffer(), + valid(false) + { + clear(); - query_name(name); -} + query_name(name); + } -sbuild::group::group (std::string const& name): - ::group(), - buffer(), - valid(false) -{ - clear(); + group::group (std::string const& name): + ::group(), + buffer(), + valid(false) + { + clear(); - query_name(name); -} + query_name(name); + } -void -sbuild::group::clear () -{ - valid = false; + void + group::clear () + { + valid = false; - buffer.clear(); + buffer.clear(); - ::group::gr_name = 0; - ::group::gr_passwd = 0; - ::group::gr_gid = 0; - ::group::gr_mem = 0; -} + ::group::gr_name = 0; + ::group::gr_passwd = 0; + ::group::gr_gid = 0; + ::group::gr_mem = 0; + } -void -sbuild::group::query_gid (gid_t gid) -{ - buffer_type::size_type size = 1 << 7; - buffer.reserve(size); - int error; + void + group::query_gid (gid_t gid) + { + buffer_type::size_type size = 1 << 7; + buffer.reserve(size); + int error; - ::group *grp_result; + ::group *grp_result; - while ((error = getgrgid_r(gid, this, - &buffer[0], buffer.capacity(), - &grp_result))) - { - size <<= 1; - buffer.reserve(size); - } + while ((error = getgrgid_r(gid, this, + &buffer[0], buffer.capacity(), + &grp_result))) + { + size <<= 1; + buffer.reserve(size); + } - if (grp_result) - valid = true; - else - errno = error; -} + if (grp_result) + valid = true; + else + errno = error; + } -void -sbuild::group::query_name (const char *name) -{ - buffer_type::size_type size = 1 << 8; - buffer.reserve(size); - int error; + void + group::query_name (const char *name) + { + buffer_type::size_type size = 1 << 8; + buffer.reserve(size); + int error; - ::group *grp_result; + ::group *grp_result; - while ((error = getgrnam_r(name, this, - &buffer[0], buffer.capacity(), - &grp_result))) - { - size <<= 1; - buffer.reserve(size); - } + while ((error = getgrnam_r(name, this, + &buffer[0], buffer.capacity(), + &grp_result))) + { + size <<= 1; + buffer.reserve(size); + } - if (grp_result) - valid = true; - else - errno = error; -} + if (grp_result) + valid = true; + else + errno = error; + } -void -sbuild::group::query_name (std::string const& name) -{ - query_name(name.c_str()); -} + void + group::query_name (std::string const& name) + { + query_name(name.c_str()); + } + + bool + group::operator ! () const + { + return !valid; + } -bool -sbuild::group::operator ! () const -{ - return !valid; } diff --git a/lib/schroot-common/main.cc b/lib/schroot-common/main.cc index ebd44ccb..65f7a34f 100644 --- a/lib/schroot-common/main.cc +++ b/lib/schroot-common/main.cc @@ -43,342 +43,346 @@ using std::endl; using boost::format; using sbuild::_; using sbuild::N_; -using namespace schroot_common; -template<> -sbuild::error<main::error_code>::map_type -sbuild::error<main::error_code>::error_strings = - { - // TRANSLATORS: %4% = file - {main::CHROOT_FILE, N_("No chroots are defined in ‘%4%’")}, - // TRANSLATORS: %4% = file - // TRANSLATORS: %5% = file - {main::CHROOT_FILE2, N_("No chroots are defined in ‘%4%’ or ‘%5%’")}, - // TRANSLATORS: %1% = file - {main::CHROOT_NOTDEFINED, N_("The specified chroots are not defined in ‘%1%’")}, - {main::SESSION_INVALID, N_("%1%: Invalid session name")} - }; - -main::main (std::string const& program_name, - std::string const& program_usage, - options::ptr& options, - bool use_syslog): - bin_common::main(program_name, program_usage, - std::static_pointer_cast<bin_common::options>(options), - use_syslog), - options(options) -{ -} - -main::~main () -{ -} - -void -main::action_version (std::ostream& stream) -{ - bin_common::main::action_version(stream); - - stream << '\n' - << _("Installed chroot facets:") - << '\n'; - sbuild::chroot::facet::factory::print_facets(stream); - - stream << std::flush; -} - -void -main::action_info () -{ - for(auto chroot_name = this->chroot_names.begin(); - chroot_name != this->chroot_names.end(); - ++chroot_name) - { - // This should never fail, so no error handling here--we already - // validated everything when we got the chroot map. - sbuild::chroot::config::chroot_map::const_iterator c = this->chroots.find(*chroot_name); - assert(c->second); - - std::cout << c->second; - if (chroot_name + 1 != this->chroot_names.end()) - std::cout << '\n'; - } - - std::cout << std::flush; -} - -void -main::action_location () -{ - for(const auto& chroot_name : this->chroot_names) - { - // This should never fail, so no error handling here--we already - // validated everything when we got the chroot map. - const auto chroot = this->chroots.find(chroot_name); - assert(chroot->second); - - std::cout << chroot->second->get_path() << '\n'; - } - - std::cout << std::flush; -} - -void -main::action_config () -{ - std::cout << "# " - // TRANSLATORS: %1% = program name - // TRANSLATORS: %2% = program version - // TRANSLATORS: %3% = current date - << format(_("schroot configuration generated by %1% %2% on %3%")) - % this->program_name % VERSION % sbuild::date(time(0)) - << endl; - std::cout << endl; - - sbuild::keyfile info; - - for(const auto& chroot_name : this->chroot_names) - { - // This should never fail, so no error handling here--we already - // validated everything when we got the chroot map. - const auto chroot = this->chroots.find(chroot_name); - assert(chroot->second); - - // Generated chroots (e.g. source chroots) are not printed. - if (chroot->second->get_original()) - info << chroot->second; - } - - std::cout << sbuild::keyfile_writer(info) << std::flush; -} - -void -main::get_chroot_options () +namespace schroot_common { - if (this->options->all_chroots == true || - this->options->all_sessions == true || - this->options->all_source_chroots == true) + template<> + sbuild::error<main::error_code>::map_type + sbuild::error<main::error_code>::error_strings = { - if (this->options->all_chroots) - { - sbuild::string_list chroots; - if (this->options->action == options::ACTION_LIST && - !this->options->exclude_aliases) - chroots = this->config->get_alias_list("chroot"); - else - chroots = this->config->get_chroot_list("chroot"); - this->chroot_names.insert(this->chroot_names.end(), chroots.begin(), chroots.end()); - } - if (this->options->all_sessions) - { - sbuild::string_list sessions; - if (this->options->action == options::ACTION_LIST && - !this->options->exclude_aliases) - sessions = this->config->get_alias_list("session"); - else - sessions = this->config->get_chroot_list("session"); - this->chroot_names.insert(this->chroot_names.end(), sessions.begin(), sessions.end()); - } - if (this->options->all_source_chroots) - { - sbuild::string_list sources; - if (this->options->action == options::ACTION_LIST && - !this->options->exclude_aliases) - sources = this->config->get_alias_list("source"); - else - sources = this->config->get_chroot_list("source"); - this->chroot_names.insert(this->chroot_names.end(), sources.begin(), sources.end()); - } - - // Validate and normalise - this->chroots = this->config->validate_chroots("", this->chroot_names); - } - else - { - // Search in the appropriate namespace. - std::string chroot_namespace("chroot"); - if (this->options->action == options::ACTION_SESSION_RECOVER || - this->options->action == options::ACTION_SESSION_RUN || - this->options->action == options::ACTION_SESSION_END) - chroot_namespace = "session"; - - // Validate and normalise - this->chroot_names = this->options->chroots; - this->chroots = this->config->validate_chroots - (chroot_namespace, this->chroot_names); - } -} + // TRANSLATORS: %4% = file + {schroot_common::main::CHROOT_FILE, N_("No chroots are defined in ‘%4%’")}, + // TRANSLATORS: %4% = file + // TRANSLATORS: %5% = file + {schroot_common::main::CHROOT_FILE2, N_("No chroots are defined in ‘%4%’ or ‘%5%’")}, + // TRANSLATORS: %1% = file + {schroot_common::main::CHROOT_NOTDEFINED, N_("The specified chroots are not defined in ‘%1%’")}, + {schroot_common::main::SESSION_INVALID, N_("%1%: Invalid session name")} + }; + + main::main (std::string const& program_name, + std::string const& program_usage, + options::ptr& options, + bool use_syslog): + bin_common::main(program_name, program_usage, + std::static_pointer_cast<bin_common::options>(options), + use_syslog), + options(options) + { + } -void -main::load_config () -{ - this->config = sbuild::chroot::config::ptr(new sbuild::chroot::config); - /* The normal chroot list is used when starting a session or running - any chroot type or session, or displaying chroot information. */ - if (this->options->load_chroots == true) - { - this->config->add("chroot", SCHROOT_CONF); - this->config->add("chroot", SCHROOT_CONF_CHROOT_D); - } - /* The session chroot list is used when running or ending an - existing session, or displaying chroot information. */ - if (this->options->load_sessions == true) - this->config->add("session", SCHROOT_SESSION_DIR); -} + main::~main () + { + } -int -main::run_impl () -{ - if (this->options->action == options::ACTION_HELP) - { - action_help(std::cout); - return EXIT_SUCCESS; - } + void + main::action_version (std::ostream& stream) + { + bin_common::main::action_version(stream); - if (this->options->action == options::ACTION_VERSION) - { - action_version(std::cout); - return EXIT_SUCCESS; - } + stream << '\n' + << _("Installed chroot facets:") + << '\n'; + sbuild::chroot::facet::factory::print_facets(stream); - /* Initialise chroot configuration. */ - load_config(); + stream << std::flush; + } - if (this->options->load_chroots && - this->config->get_chroots("chroot").empty() && - this->options->quiet == false) - log_exception_warning(error(CHROOT_FILE2, SCHROOT_CONF, SCHROOT_CONF_CHROOT_D)); + void + main::action_info () + { + for(auto chroot_name = this->chroot_names.begin(); + chroot_name != this->chroot_names.end(); + ++chroot_name) + { + // This should never fail, so no error handling here--we already + // validated everything when we got the chroot map. + sbuild::chroot::config::chroot_map::const_iterator c = this->chroots.find(*chroot_name); + assert(c->second); + + std::cout << c->second; + if (chroot_name + 1 != this->chroot_names.end()) + std::cout << '\n'; + } + + std::cout << std::flush; + } + + void + main::action_location () + { + for(const auto& chroot_name : this->chroot_names) + { + // This should never fail, so no error handling here--we already + // validated everything when we got the chroot map. + const auto chroot = this->chroots.find(chroot_name); + assert(chroot->second); - /* Get list of chroots to use */ - get_chroot_options(); - if (this->chroots.empty()) - { - if (!(this->options->all_chroots == true || - this->options->all_sessions == true || - this->options->all_source_chroots == true)) - throw error(SCHROOT_CONF, CHROOT_NOTDEFINED); - else - { - // If one of the --all options was used, then don't treat - // the lack of chroots as an error. TODO: Also check if any - // additional chroots were specified with -c; this needs - // changes in get_chroot_options. - if (this->options->verbose) - log_exception_warning(error((this->options->all_chroots == true) ? - SCHROOT_CONF : SCHROOT_SESSION_DIR, - CHROOT_NOTDEFINED)); - return EXIT_SUCCESS; - } - } - this->chroot_objects.clear(); - for(const auto& chroot_name : this->chroot_names) - { - // This should never fail, so no error handling here--we already - // validated everything when we got the chroot map. - const auto chroot = this->chroots.find(chroot_name); - assert(chroot->second); - sbuild::session::chroot_list::value_type e; - e.alias = chroot->first; - e.chroot = chroot->second; - chroot_objects.push_back(e); - } - - /* Print chroot list. */ - if (this->options->action == options::ACTION_LIST) - { - action_list(); - return EXIT_SUCCESS; - } + std::cout << chroot->second->get_path() << '\n'; + } - if (this->config->find_alias("session", this->options->session_name)) - throw error(this->options->session_name, SESSION_INVALID); + std::cout << std::flush; + } - /* Print chroot information for specified chroots. */ - if (this->options->action == options::ACTION_INFO) - { - action_info(); - return EXIT_SUCCESS; - } - if (this->options->action == options::ACTION_LOCATION) - { - action_location(); - return EXIT_SUCCESS; - } - if (this->options->action == options::ACTION_CONFIG) - { - action_config(); - return EXIT_SUCCESS; - } - - /* Create a session. */ - sbuild::session::operation sess_op(sbuild::session::OPERATION_AUTOMATIC); - if (this->options->action == options::ACTION_SESSION_BEGIN) - sess_op = sbuild::session::OPERATION_BEGIN; - else if (this->options->action == options::ACTION_SESSION_RECOVER) - sess_op = sbuild::session::OPERATION_RECOVER; - else if (this->options->action == options::ACTION_SESSION_RUN) - sess_op = sbuild::session::OPERATION_RUN; - else if (this->options->action == options::ACTION_SESSION_END) - sess_op = sbuild::session::OPERATION_END; - - try - { - create_session(sess_op); - add_session_auth(); - - if (!this->options->command.empty()) - this->session->get_auth()->set_command(this->options->command); - if (!this->options->directory.empty()) - this->session->get_auth()->set_wd(this->options->directory); - if (!this->options->shell.empty()) - this->session->set_shell_override(this->options->shell); - this->session->set_preserve_environment(this->options->preserve); - this->session->set_session_id(this->options->session_name); - this->session->set_force(this->options->session_force); - if (this->options->quiet) - this->session->set_verbosity("quiet"); - else if (this->options->verbose) - this->session->set_verbosity("verbose"); - this->session->set_user_options(this->options->useroptions_map); - - /* Run session. */ - this->session->run(); - } - catch (std::runtime_error const& e) - { - if (!this->options->quiet) - sbuild::log_exception_error(e); - } - - if (this->session) - return this->session->get_child_status(); - else - return EXIT_FAILURE; -} + void + main::action_config () + { + std::cout << "# " + // TRANSLATORS: %1% = program name + // TRANSLATORS: %2% = program version + // TRANSLATORS: %3% = current date + << format(_("schroot configuration generated by %1% %2% on %3%")) + % this->program_name % VERSION % sbuild::date(time(0)) + << endl; + std::cout << endl; + + sbuild::keyfile info; + + for(const auto& chroot_name : this->chroot_names) + { + // This should never fail, so no error handling here--we already + // validated everything when we got the chroot map. + const auto chroot = this->chroots.find(chroot_name); + assert(chroot->second); + + // Generated chroots (e.g. source chroots) are not printed. + if (chroot->second->get_original()) + info << chroot->second; + } + + std::cout << sbuild::keyfile_writer(info) << std::flush; + } + + void + main::get_chroot_options () + { -void -main::add_session_auth () -{ - // Add PAM authentication handler. If PAM isn't available, just - // continue to use the default handler + if (this->options->all_chroots == true || + this->options->all_sessions == true || + this->options->all_source_chroots == true) + { + if (this->options->all_chroots) + { + sbuild::string_list chroots; + if (this->options->action == options::ACTION_LIST && + !this->options->exclude_aliases) + chroots = this->config->get_alias_list("chroot"); + else + chroots = this->config->get_chroot_list("chroot"); + this->chroot_names.insert(this->chroot_names.end(), chroots.begin(), chroots.end()); + } + if (this->options->all_sessions) + { + sbuild::string_list sessions; + if (this->options->action == options::ACTION_LIST && + !this->options->exclude_aliases) + sessions = this->config->get_alias_list("session"); + else + sessions = this->config->get_chroot_list("session"); + this->chroot_names.insert(this->chroot_names.end(), sessions.begin(), sessions.end()); + } + if (this->options->all_source_chroots) + { + sbuild::string_list sources; + if (this->options->action == options::ACTION_LIST && + !this->options->exclude_aliases) + sources = this->config->get_alias_list("source"); + else + sources = this->config->get_chroot_list("source"); + this->chroot_names.insert(this->chroot_names.end(), sources.begin(), sources.end()); + } + + // Validate and normalise + this->chroots = this->config->validate_chroots("", this->chroot_names); + } + else + { + // Search in the appropriate namespace. + std::string chroot_namespace("chroot"); + if (this->options->action == options::ACTION_SESSION_RECOVER || + this->options->action == options::ACTION_SESSION_RUN || + this->options->action == options::ACTION_SESSION_END) + chroot_namespace = "session"; + + // Validate and normalise + this->chroot_names = this->options->chroots; + this->chroots = this->config->validate_chroots + (chroot_namespace, this->chroot_names); + } + } + + void + main::load_config () + { + this->config = sbuild::chroot::config::ptr(new sbuild::chroot::config); + /* The normal chroot list is used when starting a session or running + any chroot type or session, or displaying chroot information. */ + if (this->options->load_chroots == true) + { + this->config->add("chroot", SCHROOT_CONF); + this->config->add("chroot", SCHROOT_CONF_CHROOT_D); + } + /* The session chroot list is used when running or ending an + existing session, or displaying chroot information. */ + if (this->options->load_sessions == true) + this->config->add("session", SCHROOT_SESSION_DIR); + } + + int + main::run_impl () + { + if (this->options->action == options::ACTION_HELP) + { + action_help(std::cout); + return EXIT_SUCCESS; + } + + if (this->options->action == options::ACTION_VERSION) + { + action_version(std::cout); + return EXIT_SUCCESS; + } + + /* Initialise chroot configuration. */ + load_config(); + + if (this->options->load_chroots && + this->config->get_chroots("chroot").empty() && + this->options->quiet == false) + log_exception_warning(error(CHROOT_FILE2, SCHROOT_CONF, SCHROOT_CONF_CHROOT_D)); + + /* Get list of chroots to use */ + get_chroot_options(); + if (this->chroots.empty()) + { + if (!(this->options->all_chroots == true || + this->options->all_sessions == true || + this->options->all_source_chroots == true)) + throw error(SCHROOT_CONF, CHROOT_NOTDEFINED); + else + { + // If one of the --all options was used, then don't treat + // the lack of chroots as an error. TODO: Also check if any + // additional chroots were specified with -c; this needs + // changes in get_chroot_options. + if (this->options->verbose) + log_exception_warning(error((this->options->all_chroots == true) ? + SCHROOT_CONF : SCHROOT_SESSION_DIR, + CHROOT_NOTDEFINED)); + return EXIT_SUCCESS; + } + } + this->chroot_objects.clear(); + for(const auto& chroot_name : this->chroot_names) + { + // This should never fail, so no error handling here--we already + // validated everything when we got the chroot map. + const auto chroot = this->chroots.find(chroot_name); + assert(chroot->second); + sbuild::session::chroot_list::value_type e; + e.alias = chroot->first; + e.chroot = chroot->second; + chroot_objects.push_back(e); + } + + /* Print chroot list. */ + if (this->options->action == options::ACTION_LIST) + { + action_list(); + return EXIT_SUCCESS; + } + + if (this->config->find_alias("session", this->options->session_name)) + throw error(this->options->session_name, SESSION_INVALID); + + /* Print chroot information for specified chroots. */ + if (this->options->action == options::ACTION_INFO) + { + action_info(); + return EXIT_SUCCESS; + } + if (this->options->action == options::ACTION_LOCATION) + { + action_location(); + return EXIT_SUCCESS; + } + if (this->options->action == options::ACTION_CONFIG) + { + action_config(); + return EXIT_SUCCESS; + } + + /* Create a session. */ + sbuild::session::operation sess_op(sbuild::session::OPERATION_AUTOMATIC); + if (this->options->action == options::ACTION_SESSION_BEGIN) + sess_op = sbuild::session::OPERATION_BEGIN; + else if (this->options->action == options::ACTION_SESSION_RECOVER) + sess_op = sbuild::session::OPERATION_RECOVER; + else if (this->options->action == options::ACTION_SESSION_RUN) + sess_op = sbuild::session::OPERATION_RUN; + else if (this->options->action == options::ACTION_SESSION_END) + sess_op = sbuild::session::OPERATION_END; + + try + { + create_session(sess_op); + add_session_auth(); + + if (!this->options->command.empty()) + this->session->get_auth()->set_command(this->options->command); + if (!this->options->directory.empty()) + this->session->get_auth()->set_wd(this->options->directory); + if (!this->options->shell.empty()) + this->session->set_shell_override(this->options->shell); + this->session->set_preserve_environment(this->options->preserve); + this->session->set_session_id(this->options->session_name); + this->session->set_force(this->options->session_force); + if (this->options->quiet) + this->session->set_verbosity("quiet"); + else if (this->options->verbose) + this->session->set_verbosity("verbose"); + this->session->set_user_options(this->options->useroptions_map); + + /* Run session. */ + this->session->run(); + } + catch (std::runtime_error const& e) + { + if (!this->options->quiet) + sbuild::log_exception_error(e); + } + + if (this->session) + return this->session->get_child_status(); + else + return EXIT_FAILURE; + } + + void + main::add_session_auth () + { + // Add PAM authentication handler. If PAM isn't available, just + // continue to use the default handler #ifdef SBUILD_FEATURE_PAM - sbuild::auth::auth::ptr auth = sbuild::auth::pam::create("schroot"); + sbuild::auth::auth::ptr auth = sbuild::auth::pam::create("schroot"); - sbuild::auth::pam_conv::auth_ptr pam_auth = - std::dynamic_pointer_cast<sbuild::auth::pam>(auth); + sbuild::auth::pam_conv::auth_ptr pam_auth = + std::dynamic_pointer_cast<sbuild::auth::pam>(auth); - sbuild::auth::pam_conv::ptr conv = sbuild::auth::pam_conv_tty::create(pam_auth); + sbuild::auth::pam_conv::ptr conv = sbuild::auth::pam_conv_tty::create(pam_auth); - /* Set up authentication timeouts. */ - time_t curtime = 0; - time(&curtime); - conv->set_warning_timeout(curtime + 15); - conv->set_fatal_timeout(curtime + 20); - pam_auth->set_conv(conv); + /* Set up authentication timeouts. */ + time_t curtime = 0; + time(&curtime); + conv->set_warning_timeout(curtime + 15); + conv->set_fatal_timeout(curtime + 20); + pam_auth->set_conv(conv); - this->session->set_auth(auth); + this->session->set_auth(auth); #endif // SBUILD_FEATURE_PAM + } + } diff --git a/lib/schroot-common/options.cc b/lib/schroot-common/options.cc index 4e5f6d52..b0af5ae0 100644 --- a/lib/schroot-common/options.cc +++ b/lib/schroot-common/options.cc @@ -33,239 +33,243 @@ using std::endl; using boost::format; using sbuild::_; namespace opt = boost::program_options; -using namespace schroot_common; -const options::action_type options::ACTION_SESSION_AUTO ("session_auto"); -const options::action_type options::ACTION_SESSION_BEGIN ("session_begin"); -const options::action_type options::ACTION_SESSION_RECOVER ("session_recover"); -const options::action_type options::ACTION_SESSION_RUN ("session_run"); -const options::action_type options::ACTION_SESSION_END ("session_end"); -const options::action_type options::ACTION_LIST ("list"); -const options::action_type options::ACTION_INFO ("info"); -const options::action_type options::ACTION_LOCATION ("location"); -const options::action_type options::ACTION_CONFIG ("config"); - -options::options (): - bin_common::options (), - chroots(), - command(), - directory(), - shell(), - user(), - preserve(false), - all(false), - all_chroots(false), - all_sessions(false), - all_source_chroots(false), - exclude_aliases(false), - session_name(), - session_force(false), - useroptions(), - useroptions_map(), - chroot(_("Chroot selection")), - chrootenv(_("Chroot environment")), - session_actions(_("Session actions")), - session_options(_("Session options")) +namespace schroot_common { -} -options::~options () -{ -} + const options::action_type options::ACTION_SESSION_AUTO ("session_auto"); + const options::action_type options::ACTION_SESSION_BEGIN ("session_begin"); + const options::action_type options::ACTION_SESSION_RECOVER ("session_recover"); + const options::action_type options::ACTION_SESSION_RUN ("session_run"); + const options::action_type options::ACTION_SESSION_END ("session_end"); + const options::action_type options::ACTION_LIST ("list"); + const options::action_type options::ACTION_INFO ("info"); + const options::action_type options::ACTION_LOCATION ("location"); + const options::action_type options::ACTION_CONFIG ("config"); -void -options::add_options () -{ - // Chain up to add basic options. - bin_common::options::add_options(); + options::options (): + bin_common::options (), + chroots(), + command(), + directory(), + shell(), + user(), + preserve(false), + all(false), + all_chroots(false), + all_sessions(false), + all_source_chroots(false), + exclude_aliases(false), + session_name(), + session_force(false), + useroptions(), + useroptions_map(), + chroot(_("Chroot selection")), + chrootenv(_("Chroot environment")), + session_actions(_("Session actions")), + session_options(_("Session options")) + { + } - action.add(ACTION_SESSION_AUTO); - action.set_default(ACTION_SESSION_AUTO); - action.add(ACTION_SESSION_BEGIN); - action.add(ACTION_SESSION_RECOVER); - action.add(ACTION_SESSION_RUN); - action.add(ACTION_SESSION_END); - action.add(ACTION_LIST); - action.add(ACTION_INFO); - action.add(ACTION_LOCATION); - action.add(ACTION_CONFIG); + options::~options () + { + } - actions.add_options() - ("list,l", - _("List available chroots")) - ("info,i", - _("Show information about selected chroots")) - ("config", - _("Dump configuration of selected chroots")); + void + options::add_options () + { + // Chain up to add basic options. + bin_common::options::add_options(); - chroot.add_options() - ("chroot,c", opt::value<sbuild::string_list>(&this->chroots), - _("Use specified chroot")); + action.add(ACTION_SESSION_AUTO); + action.set_default(ACTION_SESSION_AUTO); + action.add(ACTION_SESSION_BEGIN); + action.add(ACTION_SESSION_RECOVER); + action.add(ACTION_SESSION_RUN); + action.add(ACTION_SESSION_END); + action.add(ACTION_LIST); + action.add(ACTION_INFO); + action.add(ACTION_LOCATION); + action.add(ACTION_CONFIG); - hidden.add_options() - ("command", opt::value<sbuild::string_list>(&this->command), - _("Command to run")); + actions.add_options() + ("list,l", + _("List available chroots")) + ("info,i", + _("Show information about selected chroots")) + ("config", + _("Dump configuration of selected chroots")); - positional.add("command", -1); -} + chroot.add_options() + ("chroot,c", opt::value<sbuild::string_list>(&this->chroots), + _("Use specified chroot")); -void -options::add_option_groups () -{ - // Chain up to add basic option groups. - bin_common::options::add_option_groups(); + hidden.add_options() + ("command", opt::value<sbuild::string_list>(&this->command), + _("Command to run")); + + positional.add("command", -1); + } + + void + options::add_option_groups () + { + // Chain up to add basic option groups. + bin_common::options::add_option_groups(); #ifndef BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD - if (!chroot.options().empty()) + if (!chroot.options().empty()) #else - if (!chroot.primary_keys().empty()) + if (!chroot.primary_keys().empty()) #endif - { - visible.add(chroot); - global.add(chroot); - } + { + visible.add(chroot); + global.add(chroot); + } #ifndef BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD - if (!chrootenv.options().empty()) + if (!chrootenv.options().empty()) #else - if (!chrootenv.primary_keys().empty()) + if (!chrootenv.primary_keys().empty()) #endif - { - visible.add(chrootenv); - global.add(chrootenv); - } + { + visible.add(chrootenv); + global.add(chrootenv); + } #ifndef BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD - if (!session_actions.options().empty()) + if (!session_actions.options().empty()) #else - if (!session_actions.primary_keys().empty()) + if (!session_actions.primary_keys().empty()) #endif - { - visible.add(session_actions); - global.add(session_actions); - } + { + visible.add(session_actions); + global.add(session_actions); + } #ifndef BOOST_PROGRAM_OPTIONS_DESCRIPTION_OLD - if (!session_options.options().empty()) + if (!session_options.options().empty()) #else - if (!session_options.primary_keys().empty()) + if (!session_options.primary_keys().empty()) #endif - { - visible.add(session_options); - global.add(session_options); - } -} - -void -options::check_options () -{ - // Chain up to check basic options. - bin_common::options::check_options(); + { + visible.add(session_options); + global.add(session_options); + } + } - if (vm.count("list")) - this->action = ACTION_LIST; - if (vm.count("info")) - this->action = ACTION_INFO; - if (vm.count("config")) - this->action = ACTION_CONFIG; -} + void + options::check_options () + { + // Chain up to check basic options. + bin_common::options::check_options(); -void -options::check_actions () -{ - // Chain up to check basic actions. - bin_common::options::check_actions(); + if (vm.count("list")) + this->action = ACTION_LIST; + if (vm.count("info")) + this->action = ACTION_INFO; + if (vm.count("config")) + this->action = ACTION_CONFIG; + } - if (this->quiet && this->verbose) - { - sbuild::log_warning() - << _("--quiet and --verbose may not be used at the same time") - << endl; - sbuild::log_info() << _("Using verbose output") << endl; - } + void + options::check_actions () + { + // Chain up to check basic actions. + bin_common::options::check_actions(); - if (!this->chroots.empty() && all_used()) - { - sbuild::log_warning() - << _("--chroot and --all may not be used at the same time") - << endl; - sbuild::log_info() << _("Using --chroots only") << endl; - this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; - } + if (this->quiet && this->verbose) + { + sbuild::log_warning() + << _("--quiet and --verbose may not be used at the same time") + << endl; + sbuild::log_info() << _("Using verbose output") << endl; + } - /* Determine which chroots to load and use. */ - if (this->action == ACTION_SESSION_AUTO) - { - // Only allow normal chroots - this->load_chroots = true; - this->load_sessions = false; - this->all = this->all_sessions = false; + if (!this->chroots.empty() && all_used()) + { + sbuild::log_warning() + << _("--chroot and --all may not be used at the same time") + << endl; + sbuild::log_info() << _("Using --chroots only") << endl; + this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; + } - // If no chroot was specified, fall back to the "default" chroot. - if (this->chroots.empty() && all_used() == false) - this->chroots.push_back("default"); - } - else if (this->action == ACTION_SESSION_BEGIN) - { - // Only allow one session chroot - this->load_chroots = true; - this->load_sessions = false; - if (this->chroots.size() != 1 || all_used()) - throw error - (_("Exactly one chroot must be specified when beginning a session")); + /* Determine which chroots to load and use. */ + if (this->action == ACTION_SESSION_AUTO) + { + // Only allow normal chroots + this->load_chroots = true; + this->load_sessions = false; + this->all = this->all_sessions = false; - this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; - } - else if (this->action == ACTION_SESSION_RECOVER || - this->action == ACTION_SESSION_RUN || - this->action == ACTION_SESSION_END) - { - // Session operations work on all chroots. - this->load_chroots = this->load_sessions = true; + // If no chroot was specified, fall back to the "default" chroot. + if (this->chroots.empty() && all_used() == false) + this->chroots.push_back("default"); + } + else if (this->action == ACTION_SESSION_BEGIN) + { + // Only allow one session chroot + this->load_chroots = true; + this->load_sessions = false; + if (this->chroots.size() != 1 || all_used()) + throw error + (_("Exactly one chroot must be specified when beginning a session")); - if (!this->session_name.empty()) - throw error - (_("--session-name is not permitted for the specified action; did you mean to use --chroot?")); - } - else if (this->action == ACTION_HELP || - this->action == ACTION_VERSION) - { - // Chroots don't make sense here. - this->load_chroots = this->load_sessions = false; - this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; - } - else if (this->action == ACTION_LIST || - this->action == ACTION_INFO || - this->action == ACTION_LOCATION || - this->action == ACTION_CONFIG) - { - // If not specified otherwise, load normal chroots, but allow - // --all options. - if (!this->chroots.empty()) // chroot specified + this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; + } + else if (this->action == ACTION_SESSION_RECOVER || + this->action == ACTION_SESSION_RUN || + this->action == ACTION_SESSION_END) + { + // Session operations work on all chroots. this->load_chroots = this->load_sessions = true; - else if (!all_used()) // no chroots specified - { - this->all_chroots = true; - if (this->action == ACTION_LIST || this->action == ACTION_INFO) - this->all_source_chroots = true; + + if (!this->session_name.empty()) + throw error + (_("--session-name is not permitted for the specified action; did you mean to use --chroot?")); + } + else if (this->action == ACTION_HELP || + this->action == ACTION_VERSION) + { + // Chroots don't make sense here. + this->load_chroots = this->load_sessions = false; + this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; + } + else if (this->action == ACTION_LIST || + this->action == ACTION_INFO || + this->action == ACTION_LOCATION || + this->action == ACTION_CONFIG) + { + // If not specified otherwise, load normal chroots, but allow + // --all options. + if (!this->chroots.empty()) // chroot specified + this->load_chroots = this->load_sessions = true; + else if (!all_used()) // no chroots specified + { + this->all_chroots = true; + if (this->action == ACTION_LIST || this->action == ACTION_INFO) + this->all_source_chroots = true; + this->load_chroots = true; + } + if (this->all_chroots || this->all_source_chroots) this->load_chroots = true; - } - if (this->all_chroots || this->all_source_chroots) - this->load_chroots = true; - if (this->all_sessions) - this->load_chroots = this->load_sessions = true; - } - else - { - // Something went wrong - this->load_chroots = this->load_sessions = false; - this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; - throw error(_("Unknown action specified")); - } + if (this->all_sessions) + this->load_chroots = this->load_sessions = true; + } + else + { + // Something went wrong + this->load_chroots = this->load_sessions = false; + this->all = this->all_chroots = this->all_source_chroots = this->all_sessions = false; + throw error(_("Unknown action specified")); + } + + if (!this->session_name.empty() && this->action != ACTION_SESSION_BEGIN) + throw error + (_("--session-name is not permitted for the specified action")); - if (!this->session_name.empty() && this->action != ACTION_SESSION_BEGIN) - throw error - (_("--session-name is not permitted for the specified action")); + if (!this->session_name.empty() && + !sbuild::is_valid_sessionname(this->session_name)) + throw error(_("Invalid session name")); + } - if (!this->session_name.empty() && - !sbuild::is_valid_sessionname(this->session_name)) - throw error(_("Invalid session name")); } |