00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include "sbuild-chroot.h"
00023 #include "sbuild-chroot-source.h"
00024 #include "sbuild-chroot-config.h"
00025 #include "sbuild-lock.h"
00026
00027 #include <cerrno>
00028 #include <cstdlib>
00029 #include <cstring>
00030 #include <iostream>
00031
00032 #include <ext/stdio_filebuf.h>
00033
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <dirent.h>
00037 #include <fcntl.h>
00038 #include <unistd.h>
00039
00040 #include <boost/format.hpp>
00041
00042 using std::endl;
00043 using boost::format;
00044 using namespace sbuild;
00045
00046 namespace
00047 {
00048
00049 typedef std::pair<chroot_config::error_code,const char *> emap;
00050
00055 emap init_errors[] =
00056 {
00057
00058
00059 emap(chroot_config::ALIAS_EXIST, N_("Alias '%1%' already associated with '%4%' chroot")),
00060 emap(chroot_config::CHROOT_NOTFOUND, N_("No such chroot")),
00061
00062 emap(chroot_config::CHROOT_EXIST, N_("A chroot or alias '%1%' already exists by this name")),
00063 emap(chroot_config::DIR_OPEN, N_("Failed to open directory")),
00064 emap(chroot_config::FILE_NOTREG, N_("File is not a regular file")),
00065 emap(chroot_config::FILE_OPEN, N_("Failed to open file")),
00066 emap(chroot_config::FILE_OWNER, N_("File is not owned by user root")),
00067 emap(chroot_config::FILE_PERMS, N_("File has write permissions for others")),
00068 emap(chroot_config::FILE_STAT, N_("Failed to stat file"))
00069 };
00070
00071 bool chroot_alphasort (sbuild::chroot::ptr const& c1,
00072 sbuild::chroot::ptr const& c2)
00073 {
00074 return c1->get_name() < c2->get_name();
00075 }
00076
00077 }
00078
00079 template<>
00080 error<chroot_config::error_code>::map_type
00081 error<chroot_config::error_code>::error_strings
00082 (init_errors,
00083 init_errors + (sizeof(init_errors) / sizeof(init_errors[0])));
00084
00085 chroot_config::chroot_config ():
00086 chroots()
00087 {
00088 }
00089
00090 chroot_config::chroot_config (std::string const& file,
00091 bool active):
00092 chroots()
00093 {
00094 add(file, active);
00095 }
00096
00097 chroot_config::~chroot_config ()
00098 {
00099 }
00100
00101 void
00102 chroot_config::add (std::string const& location,
00103 bool active)
00104 {
00105 struct stat statbuf;
00106 if (stat(location.c_str(), &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
00107 add_config_directory(location, active);
00108 else
00109 add_config_file(location, active);
00110 }
00111
00112 void
00113 chroot_config::add_config_file (std::string const& file,
00114 bool active)
00115 {
00116 log_debug(DEBUG_NOTICE) << "Loading config file: " << file << endl;
00117
00118 load_data(file, active);
00119 }
00120
00121 void
00122 chroot_config::add_config_directory (std::string const& dir,
00123 bool active)
00124 {
00125 log_debug(DEBUG_NOTICE) << "Loading config directory: " << dir << endl;
00126
00127 if (dir.empty())
00128 return;
00129
00130 DIR *d = opendir(dir.c_str());
00131 if (d == 0)
00132 {
00133 throw error(dir, DIR_OPEN, strerror(errno));
00134 }
00135
00136 struct dirent *de = 0;
00137 while ((de = readdir(d)) != 0)
00138 {
00139 std::string filename = dir + "/" + de->d_name;
00140
00141 struct stat statbuf;
00142 if (stat(filename.c_str(), &statbuf) < 0)
00143 {
00144 error e(filename, FILE_STAT, strerror(errno));
00145 log_exception_warning(e);
00146 continue;
00147 }
00148
00149 if (!S_ISREG(statbuf.st_mode))
00150 {
00151 if (!(strcmp(de->d_name, ".") == 0 ||
00152 strcmp(de->d_name, "..") == 0))
00153 {
00154 error e (filename, FILE_NOTREG);
00155 log_exception_warning(e);
00156 }
00157 continue;
00158 }
00159
00160 load_data(filename, active);
00161 }
00162 }
00163
00164 void
00165 chroot_config::add (chroot::ptr& chroot,
00166 keyfile const& kconfig)
00167 {
00168 std::string const& name = chroot->get_name();
00169
00170
00171 if (this->chroots.find(name) == this->chroots.end() &&
00172 this->aliases.find(name) == this->aliases.end())
00173 {
00174
00175 this->chroots.insert(std::make_pair(name, chroot));
00176 this->aliases.insert(std::make_pair(name, name));
00177
00178
00179 string_list const& aliases = chroot->get_aliases();
00180 for (string_list::const_iterator pos = aliases.begin();
00181 pos != aliases.end();
00182 ++pos)
00183 {
00184 try
00185 {
00186 if (this->aliases.insert(std::make_pair(*pos, name))
00187 .second == false)
00188 {
00189 string_map::const_iterator dup = this->aliases.find(*pos);
00190
00191 if (dup == this->aliases.end() ||
00192 name != dup->first)
00193 {
00194 const char *const key("aliases");
00195 unsigned int line = kconfig.get_line(name, key);
00196
00197 if (dup == this->aliases.end())
00198 {
00199 error e(*pos, ALIAS_EXIST);
00200 if (line)
00201 throw keyfile::error(line, name, key,
00202 keyfile::PASSTHROUGH_LGK, e);
00203 else
00204 throw keyfile::error(name, key,
00205 keyfile::PASSTHROUGH_GK, e);
00206 }
00207 else
00208 {
00209 error e(dup->first, ALIAS_EXIST, dup->second);
00210 if (line)
00211 throw keyfile::error(line, name, key,
00212 keyfile::PASSTHROUGH_LGK, e);
00213 else
00214 throw keyfile::error(name, key,
00215 keyfile::PASSTHROUGH_GK, e);
00216 }
00217 }
00218 }
00219 }
00220 catch (std::runtime_error const& e)
00221 {
00222 log_exception_warning(e);
00223 }
00224 }
00225 }
00226 else
00227 {
00228 unsigned int line = kconfig.get_line(name);
00229
00230 error e(name, CHROOT_EXIST);
00231
00232 if (line)
00233 {
00234 keyfile::error ke(line, name, keyfile::PASSTHROUGH_LG, e);
00235 ke.set_reason(_("Duplicate names are not allowed"));
00236 throw ke;
00237 }
00238 else
00239 {
00240 keyfile::error ke(name, keyfile::PASSTHROUGH_G, e);
00241 ke.set_reason(_("Duplicate names are not allowed"));
00242 throw ke;
00243 }
00244 }
00245 }
00246
00247 chroot_config::chroot_list
00248 chroot_config::get_chroots () const
00249 {
00250 chroot_list ret;
00251
00252 for (chroot_map::const_iterator pos = this->chroots.begin();
00253 pos != this->chroots.end();
00254 ++pos)
00255 ret.push_back(pos->second);
00256
00257 std::sort(ret.begin(), ret.end(), chroot_alphasort);
00258
00259 return ret;
00260 }
00261
00262 const sbuild::chroot::ptr
00263 chroot_config::find_chroot (std::string const& name) const
00264 {
00265 chroot_map::const_iterator pos = this->chroots.find(name);
00266
00267 if (pos != this->chroots.end())
00268 return pos->second;
00269 else
00270 {
00271 chroot *null_chroot = 0;
00272 return chroot::ptr(null_chroot);
00273 }
00274 }
00275
00276 const sbuild::chroot::ptr
00277 chroot_config::find_alias (std::string const& name) const
00278 {
00279 string_map::const_iterator pos = this->aliases.find(name);
00280
00281 if (pos != this->aliases.end())
00282 return find_chroot(pos->second);
00283 else
00284 {
00285 chroot *null_chroot = 0;
00286 return chroot::ptr(null_chroot);
00287 }
00288 }
00289
00290 string_list
00291 chroot_config::get_chroot_list () const
00292 {
00293 string_list ret;
00294
00295 for (string_map::const_iterator pos = this->aliases.begin();
00296 pos != this->aliases.end();
00297 ++pos)
00298 ret.push_back(pos->first);
00299
00300 std::sort(ret.begin(), ret.end());
00301
00302 return ret;
00303 }
00304
00305 void
00306 chroot_config::print_chroot_list (std::ostream& stream) const
00307 {
00308 string_list chroots = get_chroot_list();
00309
00310 for (string_list::const_iterator pos = chroots.begin();
00311 pos != chroots.end();
00312 ++pos)
00313 stream << *pos << "\n";
00314 stream << std::flush;
00315 }
00316
00317 void
00318 chroot_config::print_chroot_list_simple (std::ostream& stream) const
00319 {
00320 stream << _("Available chroots: ");
00321
00322 for (chroot_map::const_iterator pos = this->chroots.begin();
00323 pos != this->chroots.end();
00324 ++pos)
00325 {
00326 stream << pos->second->get_name();
00327 string_list const& aliases = pos->second->get_aliases();
00328 if (!aliases.empty())
00329 {
00330 stream << " [";
00331 for (string_list::const_iterator alias = aliases.begin();
00332 alias != aliases.end();
00333 ++alias)
00334 {
00335 stream << *alias;
00336 if (alias + 1 != aliases.end())
00337 stream << ", ";
00338 }
00339 stream << ']';
00340 }
00341 chroot_map::const_iterator is_end(pos);
00342 if ((++is_end) != chroots.end())
00343 stream << ", ";
00344 }
00345
00346 stream << endl;
00347 }
00348
00349 void
00350 chroot_config::print_chroot_info (string_list const& chroots,
00351 std::ostream& stream) const
00352 {
00353 for (string_list::const_iterator pos = chroots.begin();
00354 pos != chroots.end();
00355 ++pos)
00356 {
00357 const chroot::ptr chroot = find_alias(*pos);
00358 if (chroot)
00359 {
00360 stream << chroot;
00361 if (pos + 1 != chroots.end())
00362 stream << '\n';
00363 }
00364 else
00365 {
00366 error e(*pos, CHROOT_NOTFOUND);
00367 log_exception_error(e);
00368 }
00369 }
00370 }
00371
00372 void
00373 chroot_config::print_chroot_location (string_list const& chroots,
00374 std::ostream& stream) const
00375 {
00376 for (string_list::const_iterator pos = chroots.begin();
00377 pos != chroots.end();
00378 ++pos)
00379 {
00380 const chroot::ptr chroot = find_alias(*pos);
00381 if (chroot)
00382 {
00383 stream << chroot->get_path() << '\n';
00384 }
00385 else
00386 {
00387 error e(*pos, CHROOT_NOTFOUND);
00388 log_exception_error(e);
00389 }
00390 }
00391
00392 stream << std::flush;
00393 }
00394
00395 void
00396 chroot_config::print_chroot_config (string_list const& chroots,
00397 std::ostream& stream) const
00398 {
00399 keyfile info;
00400
00401 for (string_list::const_iterator pos = chroots.begin();
00402 pos != chroots.end();
00403 ++pos)
00404 {
00405 const chroot::ptr chroot = find_alias(*pos);
00406
00407
00408 if (chroot)
00409 {
00410 if (chroot->get_original())
00411 info << chroot;
00412 }
00413 else
00414 {
00415 error e(*pos, CHROOT_NOTFOUND);
00416 log_exception_error(e);
00417 }
00418 }
00419
00420 stream << info;
00421 }
00422
00423 string_list
00424 chroot_config::validate_chroots (string_list const& chroots) const
00425 {
00426 string_list bad_chroots;
00427
00428 for (string_list::const_iterator pos = chroots.begin();
00429 pos != chroots.end();
00430 ++pos)
00431 {
00432 const chroot::ptr chroot = find_alias(*pos);
00433 if (!chroot)
00434 bad_chroots.push_back(*pos);
00435 }
00436
00437 return bad_chroots;
00438 }
00439
00440 void
00441 chroot_config::load_data (std::string const& file,
00442 bool active)
00443 {
00444 log_debug(DEBUG_NOTICE) << "Loading data file: " << file << endl;
00445
00446
00447 int fd = open(file.c_str(), O_RDONLY|O_NOFOLLOW);
00448 if (fd < 0)
00449 throw error(file, FILE_OPEN, strerror(errno));
00450
00451
00452
00453 #ifdef SCHROOT_FILEBUF_OLD
00454 __gnu_cxx::stdio_filebuf<char> fdbuf(fd, std::ios::in, true, BUFSIZ);
00455 #else
00456 __gnu_cxx::stdio_filebuf<char> fdbuf(fd, std::ios::in);
00457 #endif
00458 std::istream input(&fdbuf);
00459 input.imbue(std::locale::classic());
00460
00461 sbuild::file_lock lock(fd);
00462 try
00463 {
00464 lock.set_lock(lock::LOCK_SHARED, 2);
00465 }
00466 catch (lock::error const& e)
00467 {
00468 throw error(file, e);
00469 }
00470
00471 struct stat statbuf;
00472 if (fstat(fd, &statbuf) < 0)
00473 throw error(file, FILE_STAT, strerror(errno));
00474
00475 if (statbuf.st_uid != 0)
00476 throw error(file, FILE_OWNER);
00477 if (statbuf.st_mode & S_IWOTH)
00478 throw error(file, FILE_PERMS);
00479 if (!S_ISREG(statbuf.st_mode))
00480 throw error(file, FILE_NOTREG);
00481
00482 try
00483 {
00484 parse_data(input, active);
00485 }
00486 catch (std::runtime_error const& e)
00487 {
00488 throw error(file, e);
00489 }
00490 try
00491 {
00492 lock.unset_lock();
00493 }
00494 catch (lock::error const& e)
00495 {
00496 throw error(file, e);
00497 }
00498 }
00499
00500 void
00501 chroot_config::parse_data (std::istream& stream,
00502 bool active)
00503 {
00504
00505 keyfile kconfig(stream);
00506
00507 load_keyfile(kconfig, active);
00508 }
00509
00510 void
00511 chroot_config::load_keyfile (keyfile& kconfig,
00512 bool active)
00513 {
00514
00515 string_list const& groups = kconfig.get_groups();
00516 for (string_list::const_iterator group = groups.begin();
00517 group != groups.end();
00518 ++group)
00519 {
00520
00521
00522 kconfig.set_value(*group, "active", active);
00523 std::string type = "plain";
00524 kconfig.get_value(*group, "type", type);
00525 chroot::ptr chroot = chroot::create(type);
00526 chroot->set_name(*group);
00527
00528 kconfig >> chroot;
00529
00530 add(chroot, kconfig);
00531
00532 {
00533 chroot_source *source = dynamic_cast<chroot_source *>(chroot.get());
00534 if (source != 0 && !chroot->get_active())
00535 {
00536 chroot::ptr source_chroot = source->clone_source();
00537 if (source_chroot)
00538 add(source_chroot, kconfig);
00539 }
00540 }
00541 }
00542 }