source: trunk/debathena/third/schroot/bin/schroot-mount/schroot-mount-main.cc @ 24167

Revision 24167, 5.6 KB checked in by broder, 15 years ago (diff)
Import schroot upstream into subversion.
Line 
1/* Copyright © 2005-2007  Roger Leigh <rleigh@debian.org>
2 *
3 * schroot is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * schroot is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program.  If not, see
15 * <http://www.gnu.org/licenses/>.
16 *
17 *********************************************************************/
18
19#include <config.h>
20
21#include <sbuild/sbuild-mntstream.h>
22
23#include "schroot-mount-main.h"
24
25#include <cerrno>
26#include <climits>
27#include <cstdio>
28#include <cstdlib>
29#include <ctime>
30#include <iostream>
31#include <locale>
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <unistd.h>
36
37#include <boost/format.hpp>
38#include <boost/filesystem.hpp>
39
40#include <mntent.h>
41
42using std::endl;
43using boost::format;
44using sbuild::_;
45using sbuild::N_;
46using namespace schroot_mount;
47
48namespace
49{
50
51  typedef std::pair<main::error_code,const char *> emap;
52
53  /**
54   * This is a list of the supported error codes.  It's used to
55   * construct the real error codes map.
56   */
57  emap init_errors[] =
58    {
59      emap(main::CHILD_FORK, N_("Failed to fork child")),
60      emap(main::CHILD_WAIT, N_("Wait for child failed")),
61      // TRANSLATORS: %1% = command name
62      emap(main::EXEC,       N_("Failed to execute '%1%'"))
63    };
64
65}
66
67template<>
68sbuild::error<main::error_code>::map_type
69sbuild::error<main::error_code>::error_strings
70(init_errors,
71 init_errors + (sizeof(init_errors) / sizeof(init_errors[0])));
72
73main::main (options::ptr& options):
74  schroot_base::main("schroot-mount",
75                     // TRANSLATORS: '...' is an ellipsis e.g. U+2026,
76                     // and '-' is an em-dash.
77                     _("[OPTION...] - mount filesystems"),
78                     options,
79                     false),
80  opts(options)
81{
82}
83
84main::~main ()
85{
86}
87
88void
89main::action_mount ()
90{
91  // Check mounts.
92  sbuild::mntstream mounts(opts->fstab);
93
94  sbuild::mntstream::mntentry entry;
95
96  while (mounts >> entry)
97    {
98      // Ensure entry has a leading / to prevent security hole where
99      // mountpoint might be outside the chroot.
100      std::string d = entry.directory;
101      if (d.empty() || d[0] != '/')
102        d = std::string("/") + d;
103
104      std::string directory(opts->mountpoint + entry.directory);
105
106      if (!boost::filesystem::is_directory(directory))
107        {
108          sbuild::log_debug(sbuild::DEBUG_INFO)
109            << boost::format("Creating '%1%' in '%2%'")
110            % entry.directory
111            % opts->mountpoint
112            << std::endl;
113
114          if (!opts->dry_run)
115            {
116              try
117                {
118                  boost::filesystem::create_directories(directory);
119                }
120              catch (std::exception const& e)
121                {
122                  sbuild::log_exception_error(e);
123                  exit(EXIT_FAILURE);
124                }
125              catch (...)
126                {
127                  sbuild::log_error()
128                    << _("An unknown exception occurred") << std::endl;
129                  exit(EXIT_FAILURE);
130                }
131            }
132        }
133
134      sbuild::log_debug(sbuild::DEBUG_INFO)
135        << boost::format("Mounting '%1%' on '%2%'")
136        % entry.filesystem_name
137        % directory
138        << std::endl;
139
140      if (!opts->dry_run)
141        {
142          sbuild::string_list command;
143          command.push_back("/bin/mount");
144          if (opts->verbose)
145            command.push_back("-v");
146          command.push_back("-t");
147          command.push_back(entry.type);
148          command.push_back("-o");
149          command.push_back(entry.options);
150          command.push_back(entry.filesystem_name);
151          command.push_back(directory);
152
153          int status = run_child(command[0], command, sbuild::environment());
154
155          if (status)
156            exit(status);
157        }
158    }
159}
160
161int
162main::run_child (std::string const& file,
163                 sbuild::string_list const& command,
164                 sbuild::environment const& env)
165{
166  int exit_status = 0;
167  pid_t pid;
168
169  if ((pid = fork()) == -1)
170    {
171      throw error(CHILD_FORK, strerror(errno));
172    }
173  else if (pid == 0)
174    {
175      try
176        {
177          sbuild::log_debug(sbuild::DEBUG_INFO)
178            << "mount_main: executing "
179            << sbuild::string_list_to_string(command, ", ")
180            << std::endl;
181          exec(file, command, env);
182          error e(file, EXEC, strerror(errno));
183          sbuild::log_exception_error(e);
184        }
185      catch (std::exception const& e)
186        {
187          sbuild::log_exception_error(e);
188        }
189      catch (...)
190        {
191          sbuild::log_error()
192            << _("An unknown exception occurred") << std::endl;
193        }
194      _exit(EXIT_FAILURE);
195    }
196  else
197    {
198      wait_for_child(pid, exit_status);
199    }
200
201  if (exit_status)
202    sbuild::log_debug(sbuild::DEBUG_INFO)
203      << "mount_main: " << file
204      << " failed with status " << exit_status
205      << std::endl;
206  else
207    sbuild::log_debug(sbuild::DEBUG_INFO)
208      << "mount_main: " << file
209      << " succeeded"
210      << std::endl;
211
212  return exit_status;
213}
214
215void
216main::wait_for_child (pid_t pid,
217                      int&  child_status)
218{
219  child_status = EXIT_FAILURE; // Default exit status
220
221  int status;
222
223  while (1)
224    {
225      if (waitpid(pid, &status, 0) == -1)
226        {
227          if (errno == EINTR)
228            continue; // Wait again.
229          else
230            throw error(CHILD_WAIT, strerror(errno));
231        }
232      else
233        break;
234    }
235
236  if (WIFEXITED(status))
237    child_status = WEXITSTATUS(status);
238}
239
240int
241main::run_impl ()
242{
243  if (this->opts->action == options::ACTION_HELP)
244    action_help(std::cerr);
245  else if (this->opts->action == options::ACTION_VERSION)
246    action_version(std::cerr);
247  else if (this->opts->action == options::ACTION_MOUNT)
248    action_mount();
249  else
250    assert(0); // Invalid action.
251
252  return EXIT_SUCCESS;
253}
Note: See TracBrowser for help on using the repository browser.