]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/fileutl.cc
* French manpage translation update
[apt.git] / apt-pkg / contrib / fileutl.cc
index 0ce0c9b9da55a4f5f48542c3191fbed63475d40c..cce8a451284b6fb1277e56d0f9f3071d1b87ab10 100644 (file)
@@ -8,21 +8,25 @@
    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/types.h>
 #include <sys/time.h>
 #include <sys/wait.h>
+#include <dirent.h>
 #include <signal.h>
 #include <errno.h>
+#include <set>
+#include <algorithm>
                                                                        /*}}}*/
 
 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 */
@@ -71,7 +140,9 @@ bool CopyFile(FileFd &From,FileFd &To)
    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.
@@ -126,6 +197,54 @@ bool FileExists(string File)
    return true;
 }
                                                                        /*}}}*/
+// GetListOfFilesInDir - returns a vector of files in the given dir    /*{{{*/
+// ---------------------------------------------------------------------
+/* If an extension is given only files with this extension are included
+   in the returned vector, otherwise every "normal" file is included. */
+std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
+                                       bool const &SortList) 
+{
+   std::vector<string> List;
+   DIR *D = opendir(Dir.c_str());
+   if (D == 0) 
+   {
+      _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
+      return List;
+   }
+
+   for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) 
+   {
+      if (Ent->d_name[0] == '.')
+        continue;
+
+      if (Ext.empty() == false && flExtension(Ent->d_name) != Ext)
+        continue;
+
+      // Skip bad file names ala run-parts
+      const char *C = Ent->d_name;
+      for (; *C != 0; ++C)
+        if (isalpha(*C) == 0 && isdigit(*C) == 0
+            && *C != '_' && *C != '-' && *C != '.')
+           break;
+
+      if (*C != 0)
+        continue;
+
+      // Make sure it is a file and not something else
+      string const File = flCombine(Dir,Ent->d_name);
+      struct stat St;
+      if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0)
+        continue;
+
+      List.push_back(File);
+   }
+   closedir(D);
+
+   if (SortList == true)
+      std::sort(List.begin(),List.end());
+   return List;
+}
+                                                                       /*}}}*/
 // SafeGetCWD - This is a safer getcwd that returns a dynamic string   /*{{{*/
 // ---------------------------------------------------------------------
 /* We return / on failure. */
@@ -306,7 +425,7 @@ bool WaitFd(int Fd,bool write,unsigned long timeout)
 /* 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();
@@ -326,11 +445,27 @@ pid_t ExecFork(int dontCloseThisFd)
       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;
@@ -365,8 +500,13 @@ bool ExecWait(pid_t Pid,const char *Name,bool Reap)
    {
       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));