sbuild-chroot.cc

Go to the documentation of this file.
00001 /* Copyright © 2005-2006  Roger Leigh <rleigh@debian.org>
00002  *
00003  * schroot is free software; you can redistribute it and/or modify it
00004  * under the terms of the GNU General Public License as published by
00005  * the Free Software Foundation; either version 2 of the License, or
00006  * (at your option) any later version.
00007  *
00008  * schroot is distributed in the hope that it will be useful, but
00009  * WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  * General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00016  * MA  02111-1307  USA
00017  *
00018  *********************************************************************/
00019 
00020 #include <config.h>
00021 
00022 #include "sbuild-chroot.h"
00023 #include "sbuild-chroot-directory.h"
00024 #include "sbuild-chroot-plain.h"
00025 #include "sbuild-chroot-file.h"
00026 #include "sbuild-chroot-block-device.h"
00027 #include "sbuild-chroot-lvm-snapshot.h"
00028 #include "sbuild-lock.h"
00029 
00030 #include <algorithm>
00031 #include <cerrno>
00032 #include <map>
00033 #include <set>
00034 #include <utility>
00035 
00036 #include <ext/stdio_filebuf.h>
00037 
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #include <fcntl.h>
00041 
00042 #include <boost/format.hpp>
00043 
00044 using boost::format;
00045 using namespace sbuild;
00046 
00047 namespace
00048 {
00049 
00050   typedef std::pair<sbuild::chroot::error_code,const char *> emap;
00051 
00056   emap init_errors[] =
00057     {
00058       emap(sbuild::chroot::CHROOT_CREATE,   N_("Chroot creation failed")),
00059       emap(sbuild::chroot::CHROOT_DEVICE,   N_("Device name not set")),
00060       // TRANSLATORS: %1% = chroot type name
00061       emap(sbuild::chroot::CHROOT_TYPE,     N_("Unknown chroot type '%1%'")),
00062       emap(sbuild::chroot::DEVICE_ABS,      N_("Device must have an absolute path")),
00063       emap(sbuild::chroot::DEVICE_LOCK,     N_("Failed to lock device")),
00064       emap(sbuild::chroot::DEVICE_NOTBLOCK, N_("File is not a block device")),
00065       emap(sbuild::chroot::DEVICE_STAT,     N_("Failed to stat device")),
00066       emap(sbuild::chroot::DEVICE_UNLOCK,   N_("Failed to unlock device")),
00067       emap(sbuild::chroot::FILE_ABS,        N_("File must have an absolute path")),
00068       emap(sbuild::chroot::FILE_LOCK,       N_("Failed to acquire file lock")),
00069       emap(sbuild::chroot::FILE_NOTREG,     N_("File is not a regular file")),
00070       emap(sbuild::chroot::FILE_OWNER,      N_("File is not owned by user root")),
00071       emap(sbuild::chroot::FILE_PERMS,      N_("File has write permissions for others")),
00072       emap(sbuild::chroot::FILE_STAT,       N_("Failed to stat file")),
00073       emap(sbuild::chroot::FILE_UNLOCK,     N_("Failed to discard file lock")),
00074       emap(sbuild::chroot::LOCATION_ABS,    N_("Location must have an absolute path")),
00075       // TRANSLATORS: unlink refers to the C function which removes a file
00076       emap(sbuild::chroot::SESSION_UNLINK,  N_("Failed to unlink session file")),
00077       emap(sbuild::chroot::SESSION_WRITE,   N_("Failed to write session file"))
00078     };
00079 
00080 }
00081 
00082 template<>
00083 error<sbuild::chroot::error_code>::map_type
00084 error<sbuild::chroot::error_code>::error_strings
00085 (init_errors,
00086  init_errors + (sizeof(init_errors) / sizeof(init_errors[0])));
00087 
00088 sbuild::chroot::chroot ():
00089   name(),
00090   description(),
00091   priority(0),
00092   users(),
00093   groups(),
00094   root_users(),
00095   root_groups(),
00096   aliases(),
00097   mount_location(),
00098   location(),
00099   mount_device(),
00100   active(false),
00101   original(true),
00102   run_setup_scripts(false),
00103   run_exec_scripts(false),
00104   command_prefix(),
00105   persona(
00106 #ifdef __linux__
00107           personality("linux")
00108 #else
00109           personality("undefined")
00110 #endif
00111           )
00112 {
00113 }
00114 
00115 sbuild::chroot::~chroot ()
00116 {
00117 }
00118 
00119 sbuild::chroot::ptr
00120 sbuild::chroot::create (std::string const& type)
00121 {
00122   chroot *new_chroot = 0;
00123 
00124   if (type == "directory")
00125     new_chroot = new chroot_directory();
00126   else if (type == "plain")
00127     new_chroot = new chroot_plain();
00128   else if (type == "file")
00129     new_chroot = new chroot_file();
00130   else if (type == "block-device")
00131     new_chroot = new chroot_block_device();
00132   else if (type == "lvm-snapshot")
00133     new_chroot = new chroot_lvm_snapshot();
00134   else
00135     throw error(type, CHROOT_TYPE);
00136 
00137   if (new_chroot == 0)
00138     throw error(CHROOT_CREATE);
00139 
00140   return ptr(new_chroot);
00141 }
00142 
00143 std::string const&
00144 sbuild::chroot::get_name () const
00145 {
00146   return this->name;
00147 }
00148 
00149 void
00150 sbuild::chroot::set_name (std::string const& name)
00151 {
00152   this->name = name;
00153 }
00154 
00155 std::string const&
00156 sbuild::chroot::get_description () const
00157 {
00158   return this->description;
00159 }
00160 
00161 void
00162 sbuild::chroot::set_description (std::string const& description)
00163 {
00164   this->description = description;
00165 }
00166 
00167 std::string const&
00168 sbuild::chroot::get_mount_location () const
00169 {
00170   return this->mount_location;
00171 }
00172 
00173 void
00174 sbuild::chroot::set_mount_location (std::string const& location)
00175 {
00176   if (!location.empty() && !is_absname(location))
00177     throw error(location, LOCATION_ABS);
00178   this->mount_location = location;
00179 }
00180 
00181 std::string const&
00182 sbuild::chroot::get_location () const
00183 {
00184   return this->location;
00185 }
00186 
00187 void
00188 sbuild::chroot::set_location (std::string const& location)
00189 {
00190   if (!location.empty() && !is_absname(location))
00191     throw error(location, LOCATION_ABS);
00192 
00193   this->location = location;
00194 }
00195 
00196 std::string
00197 sbuild::chroot::get_path () const
00198 {
00199   return get_mount_location() + get_location();
00200 }
00201 
00202 std::string const&
00203 sbuild::chroot::get_mount_device () const
00204 {
00205   return this->mount_device;
00206 }
00207 
00208 void
00209 sbuild::chroot::set_mount_device (std::string const& device)
00210 {
00211   if (!device.empty() && !is_absname(device))
00212     throw error(device, DEVICE_ABS);
00213   this->mount_device = device;
00214 }
00215 
00216 unsigned int
00217 sbuild::chroot::get_priority () const
00218 {
00219   return this->priority;
00220 }
00221 
00222 void
00223 sbuild::chroot::set_priority (unsigned int priority)
00224 {
00225   this->priority = priority;
00226 }
00227 
00228 string_list const&
00229 sbuild::chroot::get_users () const
00230 {
00231   return this->users;
00232 }
00233 
00234 void
00235 sbuild::chroot::set_users (string_list const& users)
00236 {
00237   this->users = users;
00238 }
00239 
00240 string_list const&
00241 sbuild::chroot::get_groups () const
00242 {
00243   return this->groups;
00244 }
00245 
00246 void
00247 sbuild::chroot::set_groups (string_list const& groups)
00248 {
00249   this->groups = groups;
00250 }
00251 
00252 string_list const&
00253 sbuild::chroot::get_root_users () const
00254 {
00255   return this->root_users;
00256 }
00257 
00258 void
00259 sbuild::chroot::set_root_users (string_list const& users)
00260 {
00261   this->root_users = users;
00262 }
00263 
00264 string_list const&
00265 sbuild::chroot::get_root_groups () const
00266 {
00267   return this->root_groups;
00268 }
00269 
00270 void
00271 sbuild::chroot::set_root_groups (string_list const& groups)
00272 {
00273   this->root_groups = groups;
00274 }
00275 
00276 string_list const&
00277 sbuild::chroot::get_aliases () const
00278 {
00279   return this->aliases;
00280 }
00281 
00282 void
00283 sbuild::chroot::set_aliases (string_list const& aliases)
00284 {
00285   this->aliases = aliases;
00286 }
00287 
00288 bool
00289 sbuild::chroot::get_active () const
00290 {
00291   return this->active;
00292 }
00293 
00294 void
00295 sbuild::chroot::set_active (bool active)
00296 {
00297   this->active = active;
00298 }
00299 
00300 bool
00301 sbuild::chroot::get_original () const
00302 {
00303   return this->original;
00304 }
00305 
00306 void
00307 sbuild::chroot::set_original (bool original)
00308 {
00309   this->original = original;
00310 }
00311 
00312 bool
00313 sbuild::chroot::get_run_setup_scripts () const
00314 {
00315   return this->run_setup_scripts;
00316 }
00317 
00318 void
00319 sbuild::chroot::set_run_setup_scripts (bool run_setup_scripts)
00320 {
00321   this->run_setup_scripts = run_setup_scripts;
00322 }
00323 
00324 bool
00325 sbuild::chroot::get_run_exec_scripts () const
00326 {
00327   return this->run_exec_scripts;
00328 }
00329 
00330 void
00331 sbuild::chroot::set_run_exec_scripts (bool run_exec_scripts)
00332 {
00333   this->run_exec_scripts = run_exec_scripts;
00334 }
00335 
00336 string_list const&
00337 sbuild::chroot::get_command_prefix () const
00338 {
00339   return this->command_prefix;
00340 }
00341 
00342 void
00343 sbuild::chroot::set_command_prefix (string_list const& command_prefix)
00344 {
00345   this->command_prefix = command_prefix;
00346 }
00347 
00348 personality const&
00349 sbuild::chroot::get_persona () const
00350 {
00351   return this->persona;
00352 }
00353 
00354 void
00355 sbuild::chroot::set_persona (personality const& persona)
00356 {
00357   this->persona = persona;
00358 }
00359 
00360 void
00361 sbuild::chroot::setup_env (environment& env)
00362 {
00363   env.add("CHROOT_TYPE", get_chroot_type());
00364   env.add("CHROOT_NAME", get_name());
00365   env.add("CHROOT_DESCRIPTION", get_description());
00366   env.add("CHROOT_LOCATION", get_location());
00367   env.add("CHROOT_MOUNT_LOCATION", get_mount_location());
00368   env.add("CHROOT_PATH", get_path());
00369   env.add("CHROOT_MOUNT_DEVICE", get_mount_device());
00370 }
00371 
00372 void
00373 sbuild::chroot::setup_session_info (bool start)
00374 {
00375   /* Create or unlink session information. */
00376   std::string file = std::string(SCHROOT_SESSION_DIR) + "/" + get_name();
00377 
00378   if (start)
00379     {
00380       int fd = open(file.c_str(), O_CREAT|O_EXCL|O_WRONLY, 0664);
00381       if (fd < 0)
00382         throw error(file, SESSION_WRITE, strerror(errno));
00383 
00384       // Create a stream buffer from the file descriptor.  The fd will
00385       // be closed when the buffer is destroyed.
00386 #ifdef SCHROOT_FILEBUF_OLD
00387       __gnu_cxx::stdio_filebuf<char> fdbuf(fd, std::ios::out, true, BUFSIZ);
00388 #else
00389       __gnu_cxx::stdio_filebuf<char> fdbuf(fd, std::ios::out);
00390 #endif
00391       std::ostream output(&fdbuf);
00392       output.imbue(std::locale::classic());
00393 
00394       sbuild::file_lock lock(fd);
00395       try
00396         {
00397           lock.set_lock(lock::LOCK_EXCLUSIVE, 2);
00398         }
00399       catch (lock::error const& e)
00400         {
00401           throw error(file, FILE_LOCK, e);
00402         }
00403 
00404       keyfile details;
00405       get_keyfile(details);
00406       output << details;
00407 
00408       try
00409         {
00410           lock.unset_lock();
00411         }
00412       catch (lock::error const& e)
00413         {
00414           throw error(file, FILE_UNLOCK, e);
00415         }
00416     }
00417   else /* start == false */
00418     {
00419       if (unlink(file.c_str()) != 0)
00420         throw error(file, SESSION_UNLINK, strerror(errno));
00421     }
00422 }
00423 
00424 void
00425 sbuild::chroot::lock (setup_type type)
00426 {
00427   setup_lock(type, true, 0);
00428 }
00429 
00430 void
00431 sbuild::chroot::unlock (setup_type type,
00432                         int        status)
00433 {
00434   setup_lock(type, false, status);
00435 }
00436 
00437 
00438 void
00439 sbuild::chroot::get_details (format_detail& detail) const
00440 {
00441   detail
00442     .add(_("Name"), get_name())
00443     .add(_("Description"), get_description())
00444     .add(_("Type"), get_chroot_type())
00445     .add(_("Priority"), get_priority())
00446     .add(_("Users"), get_users())
00447     .add(_("Groups"), get_groups())
00448     .add(_("Root Users"), get_root_users())
00449     .add(_("Root Groups"), get_root_groups())
00450     .add(_("Aliases"), get_aliases())
00451     .add(_("Run Setup Scripts"), get_run_setup_scripts())
00452     .add(_("Run Execution Scripts"),
00453          get_run_exec_scripts())
00454     .add(_("Session Managed"),
00455          static_cast<bool>(get_session_flags() & chroot::SESSION_CREATE));
00456 
00457   if (!get_command_prefix().empty())
00458     detail.add(_("Command Prefix"), get_command_prefix());
00459 
00460   detail.add(_("Personality"), get_persona().get_name());
00461 
00462   /* Non user-settable properties are listed last. */
00463   if (!get_location().empty())
00464     detail.add(_("Location"), get_location());
00465   if (!get_mount_location().empty())
00466     detail.add(_("Mount Location"), get_mount_location());
00467   if (!get_path().empty())
00468     detail.add(_("Path"), get_path());
00469   if (!get_mount_device().empty())
00470     // TRANSLATORS: The system device node to mount containing the chroot
00471     detail.add(_("Mount Device"), get_mount_device());
00472 }
00473 
00474 void
00475 sbuild::chroot::print_details (std::ostream& stream) const
00476 {
00477   format_detail fmt((this->active == true ? _("Session") : _("Chroot")),
00478                     stream.getloc());
00479 
00480   get_details(fmt);
00481 
00482   stream << fmt;
00483 }
00484 
00485 void
00486 sbuild::chroot::get_keyfile (keyfile& keyfile) const
00487 {
00488   keyfile.remove_group(get_name());
00489 
00490   keyfile::set_object_value(*this, &chroot::get_chroot_type,
00491                             keyfile, get_name(), "type");
00492 
00493   keyfile::set_object_value(*this, &chroot::get_active,
00494                             keyfile, get_name(), "active");
00495 
00496   keyfile::set_object_value(*this, &chroot::get_run_setup_scripts,
00497                             keyfile, get_name(), "run-setup-scripts");
00498 
00499   keyfile::set_object_value(*this, &chroot::get_run_exec_scripts,
00500                             keyfile, get_name(), "run-exec-scripts");
00501 
00502   keyfile::set_object_value(*this, &chroot::get_priority,
00503                             keyfile, get_name(), "priority");
00504 
00505   keyfile::set_object_list_value(*this, &chroot::get_aliases,
00506                                  keyfile, get_name(), "aliases");
00507 
00508   keyfile::set_object_value(*this, &chroot::get_description,
00509                             keyfile, get_name(), "description");
00510 
00511   keyfile::set_object_list_value(*this, &chroot::get_users,
00512                                  keyfile, get_name(), "users");
00513 
00514   keyfile::set_object_list_value(*this, &chroot::get_groups,
00515                                  keyfile, get_name(), "groups");
00516 
00517   keyfile::set_object_list_value(*this, &chroot::get_root_users,
00518                                  keyfile, get_name(), "root-users");
00519 
00520   keyfile::set_object_list_value(*this, &chroot::get_root_groups,
00521                                  keyfile, get_name(), "root-groups");
00522 
00523   if (get_active())
00524     keyfile::set_object_value(*this, &chroot::get_mount_location,
00525                               keyfile, get_name(), "mount-location");
00526 
00527   if (get_active())
00528     keyfile::set_object_value(*this, &chroot::get_mount_device,
00529                               keyfile, get_name(), "mount-device");
00530 
00531   keyfile::set_object_list_value(*this, &chroot::get_command_prefix,
00532                                  keyfile, get_name(), "command-prefix");
00533 
00534   keyfile::set_object_value(*this, &chroot::get_persona,
00535                             keyfile, get_name(), "personality");
00536 }
00537 
00538 void
00539 sbuild::chroot::set_keyfile (keyfile const& keyfile)
00540 {
00541   // This is set not in the configuration file, but set in the keyfile
00542   // manually.  The user must not have the ability to set this option.
00543   keyfile::get_object_value(*this, &chroot::set_active,
00544                             keyfile, get_name(), "active",
00545                             keyfile::PRIORITY_REQUIRED);
00546 
00547   keyfile::get_object_value(*this, &chroot::set_run_setup_scripts,
00548                             keyfile, get_name(), "run-setup-scripts",
00549                             keyfile::PRIORITY_OPTIONAL);
00550 
00551   keyfile::get_object_value(*this, &chroot::set_run_exec_scripts,
00552                             keyfile, get_name(), "run-session-scripts",
00553                             keyfile::PRIORITY_DEPRECATED);
00554   keyfile::get_object_value(*this, &chroot::set_run_exec_scripts,
00555                             keyfile, get_name(), "run-exec-scripts",
00556                             keyfile::PRIORITY_OPTIONAL);
00557 
00558   keyfile::get_object_value(*this, &chroot::set_priority,
00559                             keyfile, get_name(), "priority",
00560                             keyfile::PRIORITY_OPTIONAL);
00561 
00562   keyfile::get_object_list_value(*this, &chroot::set_aliases,
00563                                  keyfile, get_name(), "aliases",
00564                                  keyfile::PRIORITY_OPTIONAL);
00565 
00566   keyfile::get_object_value(*this, &chroot::set_description,
00567                             keyfile, get_name(), "description",
00568                             keyfile::PRIORITY_OPTIONAL);
00569 
00570   keyfile::get_object_list_value(*this, &chroot::set_users,
00571                                  keyfile, get_name(), "users",
00572                                  keyfile::PRIORITY_OPTIONAL);
00573 
00574   keyfile::get_object_list_value(*this, &chroot::set_groups,
00575                                  keyfile, get_name(), "groups",
00576                                  keyfile::PRIORITY_OPTIONAL);
00577 
00578   keyfile::get_object_list_value(*this, &chroot::set_root_users,
00579                                  keyfile, get_name(), "root-users",
00580                                  keyfile::PRIORITY_OPTIONAL);
00581 
00582   keyfile::get_object_list_value(*this, &chroot::set_root_groups,
00583                                  keyfile, get_name(), "root-groups",
00584                                  keyfile::PRIORITY_OPTIONAL);
00585 
00586   keyfile::get_object_value(*this, &chroot::set_mount_location,
00587                             keyfile, get_name(), "mount-location",
00588                             get_active() ?
00589                             keyfile::PRIORITY_REQUIRED :
00590                             keyfile::PRIORITY_DISALLOWED);
00591 
00592   keyfile::get_object_value(*this, &chroot::set_mount_device,
00593                             keyfile, get_name(), "mount-device",
00594                             get_active() ?
00595                             keyfile::PRIORITY_OPTIONAL :
00596                             keyfile::PRIORITY_DISALLOWED);
00597 
00598   keyfile::get_object_list_value(*this, &chroot::set_command_prefix,
00599                                  keyfile, get_name(), "command-prefix",
00600                                  keyfile::PRIORITY_OPTIONAL);
00601 
00602   keyfile::get_object_value(*this, &chroot::set_persona,
00603                             keyfile, get_name(), "personality",
00604                             keyfile::PRIORITY_OPTIONAL);
00605 }

Generated on Sat Jan 27 16:11:03 2007 for schroot by  doxygen 1.5.1