summaryrefslogtreecommitdiff
path: root/sbuild/sbuild-run-parts.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sbuild/sbuild-run-parts.cc')
-rw-r--r--sbuild/sbuild-run-parts.cc253
1 files changed, 253 insertions, 0 deletions
diff --git a/sbuild/sbuild-run-parts.cc b/sbuild/sbuild-run-parts.cc
new file mode 100644
index 00000000..9fd124e1
--- /dev/null
+++ b/sbuild/sbuild-run-parts.cc
@@ -0,0 +1,253 @@
+/* Copyright © 2005-2006 Roger Leigh <rleigh@debian.org>
+ *
+ * schroot is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * schroot is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *********************************************************************/
+
+#include <config.h>
+
+#include "sbuild-dirstream.h"
+#include "sbuild-run-parts.h"
+#include "sbuild-util.h"
+
+#include <cerrno>
+
+#include <sys/wait.h>
+
+#include <boost/format.hpp>
+#include <boost/regex.hpp>
+
+using boost::format;
+using boost::regex;
+using namespace sbuild;
+
+namespace
+{
+
+ typedef std::pair<sbuild::run_parts::error_code,const char *> emap;
+
+ /**
+ * This is a list of the supported error codes. It's used to
+ * construct the real error codes map.
+ */
+ emap init_errors[] =
+ {
+ emap(run_parts::CHILD_FORK, N_("Failed to fork child")),
+ emap(run_parts::CHILD_WAIT, N_("Wait for child failed")),
+ emap(run_parts::EXEC, N_("Failed to execute"))
+ };
+
+}
+
+template<>
+std::map<run_parts::error_code,const char *>
+custom_error<run_parts::error_code>::error_strings
+(init_errors,
+ init_errors + (sizeof(init_errors) / sizeof(init_errors[0])));
+
+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),
+ // restricted(true),
+ directory(directory),
+ programs()
+{
+ dirstream stream(directory);
+ direntry de;
+ while (stream >> de)
+ {
+ std::string name(de.name());
+ if (check_filename(name))
+ this->programs.insert(name);
+ }
+}
+
+run_parts::~run_parts ()
+{
+}
+
+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;
+}
+
+int
+run_parts::run (string_list const& command,
+ environment const& env)
+{
+ int exit_status = 0;
+
+ if (!this->reverse)
+ {
+ for (program_set::const_iterator pos = this->programs.begin();
+ pos != this->programs.end();
+ ++pos)
+ {
+ string_list real_command;
+ real_command.push_back(*pos);
+ for (string_list::const_iterator spos = command.begin();
+ spos != command.end();
+ ++spos)
+ real_command.push_back(*spos);
+
+ exit_status = run_child(*pos, real_command, env);
+
+ if (exit_status && this->abort_on_error)
+ return exit_status;
+ }
+ }
+ else
+ {
+ for (program_set::const_reverse_iterator pos = this->programs.rbegin();
+ pos != this->programs.rend();
+ ++pos)
+ {
+ string_list real_command;
+ real_command.push_back(*pos);
+ for (string_list::const_iterator spos = command.begin();
+ spos != command.end();
+ ++spos)
+ real_command.push_back(*spos);
+
+ exit_status = run_child(*pos, 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 exit_status = 0;
+ pid_t pid;
+
+ if ((pid = fork()) == -1)
+ {
+ throw error(CHILD_FORK, errno);
+ }
+ else if (pid == 0)
+ {
+ if (this->verbose)
+ log_info() << format(_("Executing %1%"))
+ % string_list_to_string(command, " ")
+ << std::endl;
+ ::umask(this->umask);
+ exec(this->directory + '/' + file, command, env);
+ error e(file, EXEC, errno);
+ log_error() << e.what() << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ else
+ {
+ wait_for_child(pid, exit_status);
+ }
+
+ 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 (wait(&status) != pid)
+ {
+ if (errno == EINTR)
+ continue; // Wait again.
+ else
+ throw error(CHILD_WAIT, errno);
+ }
+ else
+ break;
+ }
+
+ if (WIFEXITED(status))
+ child_status = WEXITSTATUS(status);
+}
+
+bool
+run_parts::check_filename (std::string const& name)
+{
+ bool match = false;
+
+ if (this->lsb_mode)
+ {
+ static regex lanana_namespace("^[a-z0-9]+$", boost::regex::basic);
+ static regex lsb_namespace("^_?([a-z0-9_.]+-)+[a-z0-9]+$",
+ boost::regex::basic);
+ static regex debian_cron_namespace("^[a-z0-9][a-z0-9-]*$",
+ boost::regex::basic);
+ static regex debian_dpkg_conffile_cruft("dpkg-(old|dist|new|tmp)$",
+ boost::regex::extended);
+
+ if ((regex_match(name, lanana_namespace) ||
+ regex_match(name, lsb_namespace) ||
+ regex_match(name, debian_cron_namespace)) &&
+ !regex_match(name, debian_dpkg_conffile_cruft))
+ match = true;
+ }
+ else
+ {
+ static regex traditional_namespace("^[a-zA-Z0-9_-]$",
+ boost::regex::basic);
+ if (regex_match(name, traditional_namespace))
+ match = true;
+ }
+
+ return match;
+}
+
+/*
+ * Local Variables:
+ * mode:C++
+ * End:
+ */