1 // -*- mode: cpp; mode: fold -*-
3 // $Id: dpkgpm.cc,v 1.28 2004/01/27 02:25:01 mdz Exp $
4 /* ######################################################################
6 DPKG Package Manager - Provide an interface to dpkg
8 ##################################################################### */
11 #include <apt-pkg/dpkgpm.h>
12 #include <apt-pkg/error.h>
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/depcache.h>
15 #include <apt-pkg/strutl.h>
17 #include <apt-pkg/fileutl.h>
22 #include <sys/select.h>
23 #include <sys/types.h>
35 #include <sys/ioctl.h>
47 // Maps the dpkg "processing" info to human readable names. Entry 0
48 // of each array is the key, entry 1 is the value.
49 const std::pair
<const char *, const char *> PackageProcessingOps
[] = {
50 std::make_pair("install", N_("Installing %s")),
51 std::make_pair("configure", N_("Configuring %s")),
52 std::make_pair("remove", N_("Removing %s")),
53 std::make_pair("trigproc", N_("Running post-installation trigger %s"))
56 const std::pair
<const char *, const char *> * const PackageProcessingOpsBegin
= PackageProcessingOps
;
57 const std::pair
<const char *, const char *> * const PackageProcessingOpsEnd
= PackageProcessingOps
+ sizeof(PackageProcessingOps
) / sizeof(PackageProcessingOps
[0]);
59 // Predicate to test whether an entry in the PackageProcessingOps
60 // array matches a string.
61 class MatchProcessingOp
66 MatchProcessingOp(const char *the_target
)
71 bool operator()(const std::pair
<const char *, const char *> &pair
) const
73 return strcmp(pair
.first
, target
) == 0;
78 // DPkgPM::pkgDPkgPM - Constructor /*{{{*/
79 // ---------------------------------------------------------------------
81 pkgDPkgPM::pkgDPkgPM(pkgDepCache
*Cache
)
82 : pkgPackageManager(Cache
), dpkgbuf_pos(0),
83 term_out(NULL
), PackagesDone(0), PackagesTotal(0)
87 // DPkgPM::pkgDPkgPM - Destructor /*{{{*/
88 // ---------------------------------------------------------------------
90 pkgDPkgPM::~pkgDPkgPM()
94 // DPkgPM::Install - Install a package /*{{{*/
95 // ---------------------------------------------------------------------
96 /* Add an install operation to the sequence list */
97 bool pkgDPkgPM::Install(PkgIterator Pkg
,string File
)
99 if (File
.empty() == true || Pkg
.end() == true)
100 return _error
->Error("Internal Error, No file name for %s",Pkg
.Name());
102 List
.push_back(Item(Item::Install
,Pkg
,File
));
106 // DPkgPM::Configure - Configure a package /*{{{*/
107 // ---------------------------------------------------------------------
108 /* Add a configure operation to the sequence list */
109 bool pkgDPkgPM::Configure(PkgIterator Pkg
)
111 if (Pkg
.end() == true)
114 List
.push_back(Item(Item::Configure
,Pkg
));
118 // DPkgPM::Remove - Remove a package /*{{{*/
119 // ---------------------------------------------------------------------
120 /* Add a remove operation to the sequence list */
121 bool pkgDPkgPM::Remove(PkgIterator Pkg
,bool Purge
)
123 if (Pkg
.end() == true)
127 List
.push_back(Item(Item::Purge
,Pkg
));
129 List
.push_back(Item(Item::Remove
,Pkg
));
133 // DPkgPM::SendV2Pkgs - Send version 2 package info /*{{{*/
134 // ---------------------------------------------------------------------
135 /* This is part of the helper script communication interface, it sends
136 very complete information down to the other end of the pipe.*/
137 bool pkgDPkgPM::SendV2Pkgs(FILE *F
)
139 fprintf(F
,"VERSION 2\n");
141 /* Write out all of the configuration directives by walking the
142 configuration tree */
143 const Configuration::Item
*Top
= _config
->Tree(0);
146 if (Top
->Value
.empty() == false)
149 QuoteString(Top
->FullTag(),"=\"\n").c_str(),
150 QuoteString(Top
->Value
,"\n").c_str());
159 while (Top
!= 0 && Top
->Next
== 0)
166 // Write out the package actions in order.
167 for (vector
<Item
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
169 pkgDepCache::StateCache
&S
= Cache
[I
->Pkg
];
171 fprintf(F
,"%s ",I
->Pkg
.Name());
173 if (I
->Pkg
->CurrentVer
== 0)
176 fprintf(F
,"%s ",I
->Pkg
.CurrentVer().VerStr());
178 // Show the compare operator
180 if (S
.InstallVer
!= 0)
183 if (I
->Pkg
->CurrentVer
!= 0)
184 Comp
= S
.InstVerIter(Cache
).CompareVer(I
->Pkg
.CurrentVer());
191 fprintf(F
,"%s ",S
.InstVerIter(Cache
).VerStr());
196 // Show the filename/operation
197 if (I
->Op
== Item::Install
)
200 if (I
->File
[0] != '/')
201 fprintf(F
,"**ERROR**\n");
203 fprintf(F
,"%s\n",I
->File
.c_str());
205 if (I
->Op
== Item::Configure
)
206 fprintf(F
,"**CONFIGURE**\n");
207 if (I
->Op
== Item::Remove
||
208 I
->Op
== Item::Purge
)
209 fprintf(F
,"**REMOVE**\n");
217 // DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/
218 // ---------------------------------------------------------------------
219 /* This looks for a list of scripts to run from the configuration file
220 each one is run and is fed on standard input a list of all .deb files
221 that are due to be installed. */
222 bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf
)
224 Configuration::Item
const *Opts
= _config
->Tree(Cnf
);
225 if (Opts
== 0 || Opts
->Child
== 0)
229 unsigned int Count
= 1;
230 for (; Opts
!= 0; Opts
= Opts
->Next
, Count
++)
232 if (Opts
->Value
.empty() == true)
235 // Determine the protocol version
236 string OptSec
= Opts
->Value
;
237 string::size_type Pos
;
238 if ((Pos
= OptSec
.find(' ')) == string::npos
|| Pos
== 0)
239 Pos
= OptSec
.length();
240 OptSec
= "DPkg::Tools::Options::" + string(Opts
->Value
.c_str(),Pos
);
242 unsigned int Version
= _config
->FindI(OptSec
+"::Version",1);
246 if (pipe(Pipes
) != 0)
247 return _error
->Errno("pipe","Failed to create IPC pipe to subprocess");
248 SetCloseExec(Pipes
[0],true);
249 SetCloseExec(Pipes
[1],true);
251 // Purified Fork for running the script
252 pid_t Process
= ExecFork();
256 dup2(Pipes
[0],STDIN_FILENO
);
257 SetCloseExec(STDOUT_FILENO
,false);
258 SetCloseExec(STDIN_FILENO
,false);
259 SetCloseExec(STDERR_FILENO
,false);
264 Args
[2] = Opts
->Value
.c_str();
266 execv(Args
[0],(char **)Args
);
270 FILE *F
= fdopen(Pipes
[1],"w");
272 return _error
->Errno("fdopen","Faild to open new FD");
274 // Feed it the filenames.
278 for (vector
<Item
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
280 // Only deal with packages to be installed from .deb
281 if (I
->Op
!= Item::Install
)
285 if (I
->File
[0] != '/')
288 /* Feed the filename of each package that is pending install
290 fprintf(F
,"%s\n",I
->File
.c_str());
299 Die
= !SendV2Pkgs(F
);
303 // Clean up the sub process
304 if (ExecWait(Process
,Opts
->Value
.c_str()) == false)
305 return _error
->Error("Failure running script %s",Opts
->Value
.c_str());
312 // DPkgPM::DoStdin - Read stdin and pass to slave pty /*{{{*/
313 // ---------------------------------------------------------------------
316 void pkgDPkgPM::DoStdin(int master
)
318 unsigned char input_buf
[256] = {0,};
319 ssize_t len
= read(0, input_buf
, sizeof(input_buf
));
321 write(master
, input_buf
, len
);
323 stdin_is_dev_null
= true;
326 // DPkgPM::DoTerminalPty - Read the terminal pty and write log /*{{{*/
327 // ---------------------------------------------------------------------
329 * read the terminal pty and write log
331 void pkgDPkgPM::DoTerminalPty(int master
)
333 unsigned char term_buf
[1024] = {0,0, };
335 ssize_t len
=read(master
, term_buf
, sizeof(term_buf
));
336 if(len
== -1 && errno
== EIO
)
338 // this happens when the child is about to exit, we
339 // give it time to actually exit, otherwise we run
346 write(1, term_buf
, len
);
348 fwrite(term_buf
, len
, sizeof(char), term_out
);
351 // DPkgPM::ProcessDpkgStatusBuf /*{{{*/
352 // ---------------------------------------------------------------------
355 void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd
, char *line
)
357 // the status we output
358 ostringstream status
;
360 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
361 std::clog
<< "got from dpkg '" << line
<< "'" << std::endl
;
364 /* dpkg sends strings like this:
365 'status: <pkg>: <pkg qstate>'
366 errors look like this:
367 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data
368 and conffile-prompt like this
369 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited
371 Newer versions of dpkg sent also:
372 'processing: install: pkg'
373 'processing: configure: pkg'
374 'processing: remove: pkg'
375 'processing: trigproc: trigger'
379 // dpkg sends multiline error messages sometimes (see
380 // #374195 for a example. we should support this by
381 // either patching dpkg to not send multiline over the
382 // statusfd or by rewriting the code here to deal with
383 // it. for now we just ignore it and not crash
384 TokSplitString(':', line
, list
, sizeof(list
)/sizeof(list
[0]));
385 if( list
[0] == NULL
|| list
[1] == NULL
|| list
[2] == NULL
)
387 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
388 std::clog
<< "ignoring line: not enough ':'" << std::endl
;
392 char *action
= _strstrip(list
[2]);
394 // 'processing' from dpkg looks like
395 // 'processing: action: pkg'
396 if(strncmp(list
[0], "processing", strlen("processing")) == 0)
399 char *pkg_or_trigger
= _strstrip(list
[2]);
400 action
=_strstrip( list
[1]);
401 const std::pair
<const char *, const char *> * const iter
=
402 std::find_if(PackageProcessingOpsBegin
,
403 PackageProcessingOpsEnd
,
404 MatchProcessingOp(action
));
405 if(iter
== PackageProcessingOpsEnd
)
407 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
408 std::clog
<< "ignoring unknwon action: " << action
<< std::endl
;
411 snprintf(s
, sizeof(s
), _(iter
->second
), pkg_or_trigger
);
413 status
<< "pmstatus:" << pkg_or_trigger
414 << ":" << (PackagesDone
/float(PackagesTotal
)*100.0)
418 write(OutStatusFd
, status
.str().c_str(), status
.str().size());
419 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
420 std::clog
<< "send: '" << status
.str() << "'" << endl
;
424 if(strncmp(action
,"error",strlen("error")) == 0)
426 status
<< "pmerror:" << list
[1]
427 << ":" << (PackagesDone
/float(PackagesTotal
)*100.0)
431 write(OutStatusFd
, status
.str().c_str(), status
.str().size());
432 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
433 std::clog
<< "send: '" << status
.str() << "'" << endl
;
436 if(strncmp(action
,"conffile",strlen("conffile")) == 0)
438 status
<< "pmconffile:" << list
[1]
439 << ":" << (PackagesDone
/float(PackagesTotal
)*100.0)
443 write(OutStatusFd
, status
.str().c_str(), status
.str().size());
444 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
445 std::clog
<< "send: '" << status
.str() << "'" << endl
;
449 vector
<struct DpkgState
> &states
= PackageOps
[pkg
];
450 const char *next_action
= NULL
;
451 if(PackageOpsDone
[pkg
] < states
.size())
452 next_action
= states
[PackageOpsDone
[pkg
]].state
;
453 // check if the package moved to the next dpkg state
454 if(next_action
&& (strcmp(action
, next_action
) == 0))
456 // only read the translation if there is actually a next
458 const char *translation
= _(states
[PackageOpsDone
[pkg
]].str
);
460 snprintf(s
, sizeof(s
), translation
, pkg
);
462 // we moved from one dpkg state to a new one, report that
463 PackageOpsDone
[pkg
]++;
465 // build the status str
466 status
<< "pmstatus:" << pkg
467 << ":" << (PackagesDone
/float(PackagesTotal
)*100.0)
471 write(OutStatusFd
, status
.str().c_str(), status
.str().size());
472 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
473 std::clog
<< "send: '" << status
.str() << "'" << endl
;
475 if (_config
->FindB("Debug::pkgDPkgProgressReporting",false) == true)
476 std::clog
<< "(parsed from dpkg) pkg: " << pkg
477 << " action: " << action
<< endl
;
480 // DPkgPM::DoDpkgStatusFd /*{{{*/
481 // ---------------------------------------------------------------------
484 void pkgDPkgPM::DoDpkgStatusFd(int statusfd
, int OutStatusFd
)
489 len
=read(statusfd
, &dpkgbuf
[dpkgbuf_pos
], sizeof(dpkgbuf
)-dpkgbuf_pos
);
494 // process line by line if we have a buffer
496 while((q
=(char*)memchr(p
, '\n', dpkgbuf
+dpkgbuf_pos
-p
)) != NULL
)
499 ProcessDpkgStatusLine(OutStatusFd
, p
);
500 p
=q
+1; // continue with next line
503 // now move the unprocessed bits (after the final \n that is now a 0x0)
504 // to the start and update dpkgbuf_pos
505 void *memrchr(void const *, int, size_t);
506 p
= (char*)memrchr(dpkgbuf
, 0, dpkgbuf_pos
);
510 // we are interessted in the first char *after* 0x0
513 // move the unprocessed tail to the start and update pos
514 memmove(dpkgbuf
, p
, p
-dpkgbuf
);
515 dpkgbuf_pos
= dpkgbuf
+dpkgbuf_pos
-p
;
519 bool pkgDPkgPM::OpenLog()
521 string logdir
= _config
->FindDir("Dir::Log");
522 if(not FileExists(logdir
))
523 return _error
->Error(_("Directory '%s' missing"), logdir
.c_str());
524 string logfile_name
= flCombine(logdir
,
525 _config
->Find("Dir::Log::Terminal"));
526 if (!logfile_name
.empty())
528 term_out
= fopen(logfile_name
.c_str(),"a");
529 chmod(logfile_name
.c_str(), 0600);
530 // output current time
532 time_t t
= time(NULL
);
533 struct tm
*tmp
= localtime(&t
);
534 strftime(outstr
, sizeof(outstr
), "%F %T", tmp
);
535 fprintf(term_out
, "\nLog started: ");
536 fprintf(term_out
, "%s", outstr
);
537 fprintf(term_out
, "\n");
542 bool pkgDPkgPM::CloseLog()
547 time_t t
= time(NULL
);
548 struct tm
*tmp
= localtime(&t
);
549 strftime(outstr
, sizeof(outstr
), "%F %T", tmp
);
550 fprintf(term_out
, "Log ended: ");
551 fprintf(term_out
, "%s", outstr
);
552 fprintf(term_out
, "\n");
560 // This implements a racy version of pselect for those architectures
561 // that don't have a working implementation.
562 // FIXME: Probably can be removed on Lenny+1
563 static int racy_pselect(int nfds
, fd_set
*readfds
, fd_set
*writefds
,
564 fd_set
*exceptfds
, const struct timespec
*timeout
,
565 const sigset_t
*sigmask
)
571 tv
.tv_sec
= timeout
->tv_sec
;
572 tv
.tv_usec
= timeout
->tv_nsec
/1000;
574 sigprocmask(SIG_SETMASK
, sigmask
, &origmask
);
575 retval
= select(nfds
, readfds
, writefds
, exceptfds
, &tv
);
576 sigprocmask(SIG_SETMASK
, &origmask
, 0);
581 // DPkgPM::Go - Run the sequence /*{{{*/
582 // ---------------------------------------------------------------------
583 /* This globs the operations and calls dpkg
585 * If it is called with "OutStatusFd" set to a valid file descriptor
586 * apt will report the install progress over this fd. It maps the
587 * dpkg states a package goes through to human readable (and i10n-able)
588 * names and calculates a percentage for each step.
590 bool pkgDPkgPM::Go(int OutStatusFd
)
592 unsigned int MaxArgs
= _config
->FindI("Dpkg::MaxArgs",8*1024);
593 unsigned int MaxArgBytes
= _config
->FindI("Dpkg::MaxArgBytes",32*1024);
594 bool NoTriggers
= _config
->FindB("DPkg::NoTriggers",false);
596 if (RunScripts("DPkg::Pre-Invoke") == false)
599 if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
602 // map the dpkg states to the operations that are performed
603 // (this is sorted in the same way as Item::Ops)
604 static const struct DpkgState DpkgStatesOpMap
[][7] = {
607 {"half-installed", N_("Preparing %s")},
608 {"unpacked", N_("Unpacking %s") },
611 // Configure operation
613 {"unpacked",N_("Preparing to configure %s") },
614 {"half-configured", N_("Configuring %s") },
616 {"triggers-awaited", N_("Processing triggers for %s") },
617 {"triggers-pending", N_("Processing triggers for %s") },
619 { "installed", N_("Installed %s")},
624 {"half-configured", N_("Preparing for removal of %s")},
626 {"triggers-awaited", N_("Preparing for removal of %s")},
627 {"triggers-pending", N_("Preparing for removal of %s")},
629 {"half-installed", N_("Removing %s")},
630 {"config-files", N_("Removed %s")},
635 {"config-files", N_("Preparing to completely remove %s")},
636 {"not-installed", N_("Completely removed %s")},
641 // init the PackageOps map, go over the list of packages that
642 // that will be [installed|configured|removed|purged] and add
643 // them to the PackageOps map (the dpkg states it goes through)
644 // and the PackageOpsTranslations (human readable strings)
645 for (vector
<Item
>::iterator I
= List
.begin(); I
!= List
.end();I
++)
647 string name
= (*I
).Pkg
.Name();
648 PackageOpsDone
[name
] = 0;
649 for(int i
=0; (DpkgStatesOpMap
[(*I
).Op
][i
]).state
!= NULL
; i
++)
651 PackageOps
[name
].push_back(DpkgStatesOpMap
[(*I
).Op
][i
]);
656 stdin_is_dev_null
= false;
661 // this loop is runs once per operation
662 for (vector
<Item
>::iterator I
= List
.begin(); I
!= List
.end();)
664 vector
<Item
>::iterator J
= I
;
665 for (; J
!= List
.end() && J
->Op
== I
->Op
; J
++);
667 // Generate the argument list
668 const char *Args
[MaxArgs
+ 50];
669 if (J
- I
> (signed)MaxArgs
)
673 unsigned long Size
= 0;
674 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
675 Args
[n
++] = Tmp
.c_str();
676 Size
+= strlen(Args
[n
-1]);
678 // Stick in any custom dpkg options
679 Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
683 for (; Opts
!= 0; Opts
= Opts
->Next
)
685 if (Opts
->Value
.empty() == true)
687 Args
[n
++] = Opts
->Value
.c_str();
688 Size
+= Opts
->Value
.length();
692 char status_fd_buf
[20];
696 Args
[n
++] = "--status-fd";
697 Size
+= strlen(Args
[n
-1]);
698 snprintf(status_fd_buf
,sizeof(status_fd_buf
),"%i", fd
[1]);
699 Args
[n
++] = status_fd_buf
;
700 Size
+= strlen(Args
[n
-1]);
705 Args
[n
++] = "--force-depends";
706 Size
+= strlen(Args
[n
-1]);
707 Args
[n
++] = "--force-remove-reinstreq";
708 Size
+= strlen(Args
[n
-1]);
709 Args
[n
++] = "--force-remove-essential";
710 Size
+= strlen(Args
[n
-1]);
711 Args
[n
++] = "--remove";
712 Size
+= strlen(Args
[n
-1]);
716 Args
[n
++] = "--force-depends";
717 Size
+= strlen(Args
[n
-1]);
718 Args
[n
++] = "--force-remove-reinstreq";
719 Size
+= strlen(Args
[n
-1]);
720 Args
[n
++] = "--force-remove-essential";
721 Size
+= strlen(Args
[n
-1]);
722 Args
[n
++] = "--purge";
723 Size
+= strlen(Args
[n
-1]);
726 case Item::Configure
:
727 Args
[n
++] = "--configure";
729 Args
[n
++] = "--no-triggers";
730 Size
+= strlen(Args
[n
-1]);
734 Args
[n
++] = "--unpack";
735 Size
+= strlen(Args
[n
-1]);
736 Args
[n
++] = "--auto-deconfigure";
737 Size
+= strlen(Args
[n
-1]);
741 // Write in the file or package names
742 if (I
->Op
== Item::Install
)
744 for (;I
!= J
&& Size
< MaxArgBytes
; I
++)
746 if (I
->File
[0] != '/')
747 return _error
->Error("Internal Error, Pathname to install is not absolute '%s'",I
->File
.c_str());
748 Args
[n
++] = I
->File
.c_str();
749 Size
+= strlen(Args
[n
-1]);
754 for (;I
!= J
&& Size
< MaxArgBytes
; I
++)
756 Args
[n
++] = I
->Pkg
.Name();
757 Size
+= strlen(Args
[n
-1]);
763 if (_config
->FindB("Debug::pkgDPkgPM",false) == true)
765 for (unsigned int k
= 0; k
!= n
; k
++)
766 clog
<< Args
[k
] << ' ';
775 typedef void (*sighandler_t
)(int);
777 /* Mask off sig int/quit. We do this because dpkg also does when
778 it forks scripts. What happens is that when you hit ctrl-c it sends
779 it to all processes in the group. Since dpkg ignores the signal
780 it doesn't die but we do! So we must also ignore it */
781 sighandler_t old_SIGQUIT
= signal(SIGQUIT
,SIG_IGN
);
782 sighandler_t old_SIGINT
= signal(SIGINT
,SIG_IGN
);
784 // ignore SIGHUP as well (debian #463030)
785 sighandler_t old_SIGHUP
= signal(SIGHUP
,SIG_IGN
);
788 struct termios tt_out
;
793 // FIXME: setup sensible signal handling (*ick*)
795 tcgetattr(1, &tt_out
);
796 ioctl(0, TIOCGWINSZ
, (char *)&win
);
797 if (openpty(&master
, &slave
, NULL
, &tt_out
, &win
) < 0)
799 const char *s
= _("Can not write log, openpty() "
800 "failed (/dev/pts not mounted?)\n");
801 fprintf(stderr
, "%s",s
);
802 fprintf(term_out
, "%s",s
);
808 rtt
.c_lflag
&= ~ECHO
;
809 tcsetattr(0, TCSAFLUSH
, &rtt
);
814 _config
->Set("APT::Keep-Fds::",fd
[1]);
820 if(slave
>= 0 && master
>= 0)
823 ioctl(slave
, TIOCSCTTY
, 0);
830 close(fd
[0]); // close the read end of the pipe
832 if (chdir(_config
->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
835 if (_config
->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO
))
838 if ((Flags
= fcntl(STDIN_FILENO
,F_GETFL
,dummy
)) < 0)
841 // Discard everything in stdin before forking dpkg
842 if (fcntl(STDIN_FILENO
,F_SETFL
,Flags
| O_NONBLOCK
) < 0)
845 while (read(STDIN_FILENO
,&dummy
,1) == 1);
847 if (fcntl(STDIN_FILENO
,F_SETFL
,Flags
& (~(long)O_NONBLOCK
)) < 0)
852 /* No Job Control Stop Env is a magic dpkg var that prevents it
853 from using sigstop */
854 putenv((char *)"DPKG_NO_TSTP=yes");
855 execvp(Args
[0],(char **)Args
);
856 cerr
<< "Could not exec dpkg!" << endl
;
860 // clear the Keep-Fd again
861 _config
->Clear("APT::Keep-Fds",fd
[1]);
866 // we read from dpkg here
868 close(fd
[1]); // close the write end of the pipe
870 // the result of the waitpid call
879 sigset_t original_sigmask
;
880 sigemptyset(&sigmask
);
881 sigprocmask(SIG_BLOCK
,&sigmask
,&original_sigmask
);
884 while ((res
=waitpid(Child
,&Status
, WNOHANG
)) != Child
) {
886 // FIXME: move this to a function or something, looks ugly here
887 // error handling, waitpid returned -1
890 RunScripts("DPkg::Post-Invoke");
892 // Restore sig int/quit
893 signal(SIGQUIT
,old_SIGQUIT
);
894 signal(SIGINT
,old_SIGINT
);
895 signal(SIGHUP
,old_SIGHUP
);
896 return _error
->Errno("waitpid","Couldn't wait for subprocess");
899 // wait for input or output here
901 if (!stdin_is_dev_null
)
903 FD_SET(_dpkgin
, &rfds
);
905 FD_SET(master
, &rfds
);
908 select_ret
= pselect(max(master
, _dpkgin
)+1, &rfds
, NULL
, NULL
,
909 &tv
, &original_sigmask
);
910 if (select_ret
< 0 && (errno
== EINVAL
|| errno
== ENOSYS
))
911 select_ret
= racy_pselect(max(master
, _dpkgin
)+1, &rfds
, NULL
,
912 NULL
, &tv
, &original_sigmask
);
915 else if (select_ret
< 0 && errno
== EINTR
)
917 else if (select_ret
< 0)
919 perror("select() returned error");
923 if(master
>= 0 && FD_ISSET(master
, &rfds
))
924 DoTerminalPty(master
);
925 if(master
>= 0 && FD_ISSET(0, &rfds
))
927 if(FD_ISSET(_dpkgin
, &rfds
))
928 DoDpkgStatusFd(_dpkgin
, OutStatusFd
);
932 // Restore sig int/quit
933 signal(SIGQUIT
,old_SIGQUIT
);
934 signal(SIGINT
,old_SIGINT
);
935 signal(SIGHUP
,old_SIGHUP
);
939 tcsetattr(0, TCSAFLUSH
, &tt
);
943 // Check for an error code.
944 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
946 // if it was set to "keep-dpkg-runing" then we won't return
947 // here but keep the loop going and just report it as a error
949 bool stopOnError
= _config
->FindB("Dpkg::StopOnError",true);
952 RunScripts("DPkg::Post-Invoke");
954 if (WIFSIGNALED(Status
) != 0 && WTERMSIG(Status
) == SIGSEGV
)
955 _error
->Error("Sub-process %s received a segmentation fault.",Args
[0]);
956 else if (WIFEXITED(Status
) != 0)
957 _error
->Error("Sub-process %s returned an error code (%u)",Args
[0],WEXITSTATUS(Status
));
959 _error
->Error("Sub-process %s exited unexpectedly",Args
[0]);
970 if (RunScripts("DPkg::Post-Invoke") == false)
973 Cache
.writeStateFile(NULL
);
977 // pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
978 // ---------------------------------------------------------------------
980 void pkgDPkgPM::Reset()
982 List
.erase(List
.begin(),List
.end());
986 /* memrchr -- find the last occurrence of a byte in a memory block
988 Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2005,
989 2006, 2007, 2008 Free Software Foundation, Inc.
991 Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
992 with help from Dan Sahlin (dan@sics.se) and
993 commentary by Jim Blandy (jimb@ai.mit.edu);
994 adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
995 and implemented by Roland McGrath (roland@ai.mit.edu).
997 This program is free software: you can redistribute it and/or modify
998 it under the terms of the GNU General Public License as published by
999 the Free Software Foundation; either version 3 of the License, or
1000 (at your option) any later version.
1002 This program is distributed in the hope that it will be useful,
1003 but WITHOUT ANY WARRANTY; without even the implied warranty of
1004 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1005 GNU General Public License for more details.
1007 You should have received a copy of the GNU General Public License
1008 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1011 # include <memcopy.h>
1013 # include <config.h>
1014 # define reg_char char
1026 # define __memrchr memrchr
1029 /* Search no more than N bytes of S for C. */
1031 __memrchr (void const *s
, int c_in
, size_t n
)
1033 /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
1034 long instead of a 64-bit uintmax_t tends to give better
1035 performance. On 64-bit hardware, unsigned long is generally 64
1036 bits already. Change this typedef to experiment with
1038 typedef unsigned long int longword
;
1040 const unsigned char *char_ptr
;
1041 const longword
*longword_ptr
;
1042 longword repeated_one
;
1043 longword repeated_c
;
1044 unsigned reg_char c
;
1046 c
= (unsigned char) c_in
;
1048 /* Handle the last few bytes by reading one byte at a time.
1049 Do this until CHAR_PTR is aligned on a longword boundary. */
1050 for (char_ptr
= (const unsigned char *) s
+ n
;
1051 n
> 0 && (size_t) char_ptr
% sizeof (longword
) != 0;
1053 if (*--char_ptr
== c
)
1054 return (void *) char_ptr
;
1056 longword_ptr
= (const longword
*) char_ptr
;
1058 /* All these elucidatory comments refer to 4-byte longwords,
1059 but the theory applies equally well to any size longwords. */
1061 /* Compute auxiliary longword values:
1062 repeated_one is a value which has a 1 in every byte.
1063 repeated_c has c in every byte. */
1064 repeated_one
= 0x01010101;
1065 repeated_c
= c
| (c
<< 8);
1066 repeated_c
|= repeated_c
<< 16;
1067 if (0xffffffffU
< (longword
) -1)
1069 repeated_one
|= repeated_one
<< 31 << 1;
1070 repeated_c
|= repeated_c
<< 31 << 1;
1071 if (8 < sizeof (longword
))
1075 for (i
= 64; i
< sizeof (longword
) * 8; i
*= 2)
1077 repeated_one
|= repeated_one
<< i
;
1078 repeated_c
|= repeated_c
<< i
;
1083 /* Instead of the traditional loop which tests each byte, we will test a
1084 longword at a time. The tricky part is testing if *any of the four*
1085 bytes in the longword in question are equal to c. We first use an xor
1086 with repeated_c. This reduces the task to testing whether *any of the
1087 four* bytes in longword1 is zero.
1090 ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
1091 That is, we perform the following operations:
1092 1. Subtract repeated_one.
1094 3. & a mask consisting of 0x80 in every byte.
1095 Consider what happens in each byte:
1096 - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
1097 and step 3 transforms it into 0x80. A carry can also be propagated
1098 to more significant bytes.
1099 - If a byte of longword1 is nonzero, let its lowest 1 bit be at
1100 position k (0 <= k <= 7); so the lowest k bits are 0. After step 1,
1101 the byte ends in a single bit of value 0 and k bits of value 1.
1102 After step 2, the result is just k bits of value 1: 2^k - 1. After
1103 step 3, the result is 0. And no carry is produced.
1104 So, if longword1 has only non-zero bytes, tmp is zero.
1105 Whereas if longword1 has a zero byte, call j the position of the least
1106 significant zero byte. Then the result has a zero at positions 0, ...,
1107 j-1 and a 0x80 at position j. We cannot predict the result at the more
1108 significant bytes (positions j+1..3), but it does not matter since we
1109 already have a non-zero bit at position 8*j+7.
1111 So, the test whether any byte in longword1 is zero is equivalent to
1112 testing whether tmp is nonzero. */
1114 while (n
>= sizeof (longword
))
1116 longword longword1
= *--longword_ptr
^ repeated_c
;
1118 if ((((longword1
- repeated_one
) & ~longword1
)
1119 & (repeated_one
<< 7)) != 0)
1124 n
-= sizeof (longword
);
1127 char_ptr
= (const unsigned char *) longword_ptr
;
1129 /* At this point, we know that either n < sizeof (longword), or one of the
1130 sizeof (longword) bytes starting at char_ptr is == c. On little-endian
1131 machines, we could determine the first such byte without any further
1132 memory accesses, just by looking at the tmp result from the last loop
1133 iteration. But this does not work on big-endian machines. Choose code
1134 that works in both cases. */
1138 if (*--char_ptr
== c
)
1139 return (void *) char_ptr
;
1145 weak_alias (__memrchr
, memrchr
)