CopyFile - Buffered copy of a single file
GetLock - dpkg compatible lock file manipulation (fcntl)
- This source is placed in the Public Domain, do with it what you will
+ Most of this source is placed in the Public Domain, do with it what
+ you will
It was originally written by Jason Gunthorpe <jgg@debian.org>.
+ The exception is RunScripts() it is under the GPLv2
+
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/fileutl.h"
-#endif
#include <apt-pkg/fileutl.h>
#include <apt-pkg/error.h>
#include <apt-pkg/sptr.h>
+#include <apt-pkg/configuration.h>
#include <apti18n.h>
+#include <cstdlib>
+#include <cstring>
+
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
+#include <set>
/*}}}*/
using namespace std;
+// RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool RunScripts(const char *Cnf)
+{
+ Configuration::Item const *Opts = _config->Tree(Cnf);
+ if (Opts == 0 || Opts->Child == 0)
+ return true;
+ Opts = Opts->Child;
+
+ // Fork for running the system calls
+ pid_t Child = ExecFork();
+
+ // This is the child
+ if (Child == 0)
+ {
+ if (chdir("/tmp/") != 0)
+ _exit(100);
+
+ unsigned int Count = 1;
+ for (; Opts != 0; Opts = Opts->Next, Count++)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+
+ if (system(Opts->Value.c_str()) != 0)
+ _exit(100+Count);
+ }
+ _exit(0);
+ }
+
+ // Wait for the child
+ int Status = 0;
+ while (waitpid(Child,&Status,0) != Child)
+ {
+ if (errno == EINTR)
+ continue;
+ return _error->Errno("waitpid","Couldn't wait for subprocess");
+ }
+
+ // Restore sig int/quit
+ signal(SIGQUIT,SIG_DFL);
+ signal(SIGINT,SIG_DFL);
+
+ // Check for an error code.
+ if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
+ {
+ unsigned int Count = WEXITSTATUS(Status);
+ if (Count > 100)
+ {
+ Count -= 100;
+ for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
+ _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
+ }
+
+ return _error->Error("Sub-process returned an error code");
+ }
+
+ return true;
+}
+ /*}}}*/
+
// CopyFile - Buffered copy of a file /*{{{*/
// ---------------------------------------------------------------------
/* The caller is expected to set things so that failure causes erasure */
close at some time. */
int GetLock(string File,bool Errors)
{
- int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
+ // GetLock() is used in aptitude on directories with public-write access
+ // Use O_NOFOLLOW here to prevent symlink traversal attacks
+ int FD = open(File.c_str(),O_RDWR | O_CREAT | O_NOFOLLOW,0640);
if (FD < 0)
{
// Read only .. cant have locking problems there.
/* This is used if you want to cleanse the environment for the forked
child, it fixes up the important signals and nukes all of the fds,
otherwise acts like normal fork. */
-pid_t ExecFork(int dontCloseThisFd)
+pid_t ExecFork()
{
// Fork off the process
pid_t Process = fork();
signal(SIGWINCH,SIG_DFL);
signal(SIGCONT,SIG_DFL);
signal(SIGTSTP,SIG_DFL);
-
+
+ set<int> KeepFDs;
+ Configuration::Item const *Opts = _config->Tree("APT::Keep-Fds");
+ if (Opts != 0 && Opts->Child != 0)
+ {
+ Opts = Opts->Child;
+ for (; Opts != 0; Opts = Opts->Next)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+ int fd = atoi(Opts->Value.c_str());
+ KeepFDs.insert(fd);
+ }
+ }
+
// Close all of our FDs - just in case
for (int K = 3; K != 40; K++)
- if(K != dontCloseThisFd)
+ {
+ if(KeepFDs.find(K) == KeepFDs.end())
fcntl(K,F_SETFD,FD_CLOEXEC);
+ }
}
return Process;
if (Reap == true)
return false;
- return _error->Error(_("Waited, for %s but it wasn't there"),Name);
+ return _error->Error(_("Waited for %s but it wasn't there"),Name);
}
{
if (Reap == true)
return false;
- if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
- return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
+ if (WIFSIGNALED(Status) != 0)
+ {
+ if( WTERMSIG(Status) == SIGSEGV)
+ return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
+ else
+ return _error->Error(_("Sub-process %s received signal %u."),Name, WTERMSIG(Status));
+ }
if (WIFEXITED(Status) != 0)
return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));