]> git.saurik.com Git - apt-legacy.git/blame_incremental - apt-pkg/deb/dpkgpm.cc
Upgraded to APT 0.7.
[apt-legacy.git] / apt-pkg / deb / dpkgpm.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: dpkgpm.cc,v 1.28 2004/01/27 02:25:01 mdz Exp $
4/* ######################################################################
5
6 DPKG Package Manager - Provide an interface to dpkg
7
8 ##################################################################### */
9 /*}}}*/
10// Includes /*{{{*/
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>
16#include <apti18n.h>
17#include <apt-pkg/fileutl.h>
18
19#include <unistd.h>
20#include <stdlib.h>
21#include <fcntl.h>
22#include <sys/select.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <signal.h>
26#include <errno.h>
27#include <stdio.h>
28#include <string.h>
29#include <algorithm>
30#include <sstream>
31#include <map>
32
33#include <termios.h>
34#include <unistd.h>
35#include <sys/ioctl.h>
36#include <sys/stat.h>
37#include <util.h>
38
39#include <config.h>
40#include <apti18n.h>
41 /*}}}*/
42
43using namespace std;
44
45namespace
46{
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"))
54 };
55
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]);
58
59 // Predicate to test whether an entry in the PackageProcessingOps
60 // array matches a string.
61 class MatchProcessingOp
62 {
63 const char *target;
64
65 public:
66 MatchProcessingOp(const char *the_target)
67 : target(the_target)
68 {
69 }
70
71 bool operator()(const std::pair<const char *, const char *> &pair) const
72 {
73 return strcmp(pair.first, target) == 0;
74 }
75 };
76}
77
78// DPkgPM::pkgDPkgPM - Constructor /*{{{*/
79// ---------------------------------------------------------------------
80/* */
81pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache)
82 : pkgPackageManager(Cache), dpkgbuf_pos(0),
83 term_out(NULL), PackagesDone(0), PackagesTotal(0)
84{
85}
86 /*}}}*/
87// DPkgPM::pkgDPkgPM - Destructor /*{{{*/
88// ---------------------------------------------------------------------
89/* */
90pkgDPkgPM::~pkgDPkgPM()
91{
92}
93 /*}}}*/
94// DPkgPM::Install - Install a package /*{{{*/
95// ---------------------------------------------------------------------
96/* Add an install operation to the sequence list */
97bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
98{
99 if (File.empty() == true || Pkg.end() == true)
100 return _error->Error("Internal Error, No file name for %s",Pkg.Name());
101
102 List.push_back(Item(Item::Install,Pkg,File));
103 return true;
104}
105 /*}}}*/
106// DPkgPM::Configure - Configure a package /*{{{*/
107// ---------------------------------------------------------------------
108/* Add a configure operation to the sequence list */
109bool pkgDPkgPM::Configure(PkgIterator Pkg)
110{
111 if (Pkg.end() == true)
112 return false;
113
114 List.push_back(Item(Item::Configure,Pkg));
115 return true;
116}
117 /*}}}*/
118// DPkgPM::Remove - Remove a package /*{{{*/
119// ---------------------------------------------------------------------
120/* Add a remove operation to the sequence list */
121bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
122{
123 if (Pkg.end() == true)
124 return false;
125
126 if (Purge == true)
127 List.push_back(Item(Item::Purge,Pkg));
128 else
129 List.push_back(Item(Item::Remove,Pkg));
130 return true;
131}
132 /*}}}*/
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.*/
137bool pkgDPkgPM::SendV2Pkgs(FILE *F)
138{
139 fprintf(F,"VERSION 2\n");
140
141 /* Write out all of the configuration directives by walking the
142 configuration tree */
143 const Configuration::Item *Top = _config->Tree(0);
144 for (; Top != 0;)
145 {
146 if (Top->Value.empty() == false)
147 {
148 fprintf(F,"%s=%s\n",
149 QuoteString(Top->FullTag(),"=\"\n").c_str(),
150 QuoteString(Top->Value,"\n").c_str());
151 }
152
153 if (Top->Child != 0)
154 {
155 Top = Top->Child;
156 continue;
157 }
158
159 while (Top != 0 && Top->Next == 0)
160 Top = Top->Parent;
161 if (Top != 0)
162 Top = Top->Next;
163 }
164 fprintf(F,"\n");
165
166 // Write out the package actions in order.
167 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
168 {
169 pkgDepCache::StateCache &S = Cache[I->Pkg];
170
171 fprintf(F,"%s ",I->Pkg.Name());
172 // Current version
173 if (I->Pkg->CurrentVer == 0)
174 fprintf(F,"- ");
175 else
176 fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr());
177
178 // Show the compare operator
179 // Target version
180 if (S.InstallVer != 0)
181 {
182 int Comp = 2;
183 if (I->Pkg->CurrentVer != 0)
184 Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer());
185 if (Comp < 0)
186 fprintf(F,"> ");
187 if (Comp == 0)
188 fprintf(F,"= ");
189 if (Comp > 0)
190 fprintf(F,"< ");
191 fprintf(F,"%s ",S.InstVerIter(Cache).VerStr());
192 }
193 else
194 fprintf(F,"> - ");
195
196 // Show the filename/operation
197 if (I->Op == Item::Install)
198 {
199 // No errors here..
200 if (I->File[0] != '/')
201 fprintf(F,"**ERROR**\n");
202 else
203 fprintf(F,"%s\n",I->File.c_str());
204 }
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");
210
211 if (ferror(F) != 0)
212 return false;
213 }
214 return true;
215}
216 /*}}}*/
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. */
222bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
223{
224 Configuration::Item const *Opts = _config->Tree(Cnf);
225 if (Opts == 0 || Opts->Child == 0)
226 return true;
227 Opts = Opts->Child;
228
229 unsigned int Count = 1;
230 for (; Opts != 0; Opts = Opts->Next, Count++)
231 {
232 if (Opts->Value.empty() == true)
233 continue;
234
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);
241
242 unsigned int Version = _config->FindI(OptSec+"::Version",1);
243
244 // Create the pipes
245 int Pipes[2];
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);
250
251 // Purified Fork for running the script
252 pid_t Process = ExecFork();
253 if (Process == 0)
254 {
255 // Setup the FDs
256 dup2(Pipes[0],STDIN_FILENO);
257 SetCloseExec(STDOUT_FILENO,false);
258 SetCloseExec(STDIN_FILENO,false);
259 SetCloseExec(STDERR_FILENO,false);
260
261 const char *Args[4];
262 Args[0] = "/bin/sh";
263 Args[1] = "-c";
264 Args[2] = Opts->Value.c_str();
265 Args[3] = 0;
266 execv(Args[0],(char **)Args);
267 _exit(100);
268 }
269 close(Pipes[0]);
270 FILE *F = fdopen(Pipes[1],"w");
271 if (F == 0)
272 return _error->Errno("fdopen","Faild to open new FD");
273
274 // Feed it the filenames.
275 bool Die = false;
276 if (Version <= 1)
277 {
278 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
279 {
280 // Only deal with packages to be installed from .deb
281 if (I->Op != Item::Install)
282 continue;
283
284 // No errors here..
285 if (I->File[0] != '/')
286 continue;
287
288 /* Feed the filename of each package that is pending install
289 into the pipe. */
290 fprintf(F,"%s\n",I->File.c_str());
291 if (ferror(F) != 0)
292 {
293 Die = true;
294 break;
295 }
296 }
297 }
298 else
299 Die = !SendV2Pkgs(F);
300
301 fclose(F);
302
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());
306 }
307
308 return true;
309}
310
311 /*}}}*/
312// DPkgPM::DoStdin - Read stdin and pass to slave pty /*{{{*/
313// ---------------------------------------------------------------------
314/*
315*/
316void pkgDPkgPM::DoStdin(int master)
317{
318 unsigned char input_buf[256] = {0,};
319 ssize_t len = read(0, input_buf, sizeof(input_buf));
320 if (len)
321 write(master, input_buf, len);
322 else
323 stdin_is_dev_null = true;
324}
325 /*}}}*/
326// DPkgPM::DoTerminalPty - Read the terminal pty and write log /*{{{*/
327// ---------------------------------------------------------------------
328/*
329 * read the terminal pty and write log
330 */
331void pkgDPkgPM::DoTerminalPty(int master)
332{
333 unsigned char term_buf[1024] = {0,0, };
334
335 ssize_t len=read(master, term_buf, sizeof(term_buf));
336 if(len == -1 && errno == EIO)
337 {
338 // this happens when the child is about to exit, we
339 // give it time to actually exit, otherwise we run
340 // into a race
341 usleep(500000);
342 return;
343 }
344 if(len <= 0)
345 return;
346 write(1, term_buf, len);
347 if(term_out)
348 fwrite(term_buf, len, sizeof(char), term_out);
349}
350 /*}}}*/
351// DPkgPM::ProcessDpkgStatusBuf /*{{{*/
352// ---------------------------------------------------------------------
353/*
354 */
355void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
356{
357 // the status we output
358 ostringstream status;
359
360 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
361 std::clog << "got from dpkg '" << line << "'" << std::endl;
362
363
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
370
371 Newer versions of dpkg sent also:
372 'processing: install: pkg'
373 'processing: configure: pkg'
374 'processing: remove: pkg'
375 'processing: trigproc: trigger'
376
377 */
378 char* list[5];
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)
386 {
387 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
388 std::clog << "ignoring line: not enough ':'" << std::endl;
389 return;
390 }
391 char *pkg = list[1];
392 char *action = _strstrip(list[2]);
393
394 // 'processing' from dpkg looks like
395 // 'processing: action: pkg'
396 if(strncmp(list[0], "processing", strlen("processing")) == 0)
397 {
398 char s[200];
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)
406 {
407 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
408 std::clog << "ignoring unknwon action: " << action << std::endl;
409 return;
410 }
411 snprintf(s, sizeof(s), _(iter->second), pkg_or_trigger);
412
413 status << "pmstatus:" << pkg_or_trigger
414 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
415 << ":" << s
416 << endl;
417 if(OutStatusFd > 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;
421 return;
422 }
423
424 if(strncmp(action,"error",strlen("error")) == 0)
425 {
426 status << "pmerror:" << list[1]
427 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
428 << ":" << list[3]
429 << endl;
430 if(OutStatusFd > 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;
434 return;
435 }
436 if(strncmp(action,"conffile",strlen("conffile")) == 0)
437 {
438 status << "pmconffile:" << list[1]
439 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
440 << ":" << list[3]
441 << endl;
442 if(OutStatusFd > 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;
446 return;
447 }
448
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))
455 {
456 // only read the translation if there is actually a next
457 // action
458 const char *translation = _(states[PackageOpsDone[pkg]].str);
459 char s[200];
460 snprintf(s, sizeof(s), translation, pkg);
461
462 // we moved from one dpkg state to a new one, report that
463 PackageOpsDone[pkg]++;
464 PackagesDone++;
465 // build the status str
466 status << "pmstatus:" << pkg
467 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
468 << ":" << s
469 << endl;
470 if(OutStatusFd > 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;
474 }
475 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
476 std::clog << "(parsed from dpkg) pkg: " << pkg
477 << " action: " << action << endl;
478}
479
480// DPkgPM::DoDpkgStatusFd /*{{{*/
481// ---------------------------------------------------------------------
482/*
483 */
484void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd)
485{
486 char *p, *q;
487 int len;
488
489 len=read(statusfd, &dpkgbuf[dpkgbuf_pos], sizeof(dpkgbuf)-dpkgbuf_pos);
490 dpkgbuf_pos += len;
491 if(len <= 0)
492 return;
493
494 // process line by line if we have a buffer
495 p = q = dpkgbuf;
496 while((q=(char*)memchr(p, '\n', dpkgbuf+dpkgbuf_pos-p)) != NULL)
497 {
498 *q = 0;
499 ProcessDpkgStatusLine(OutStatusFd, p);
500 p=q+1; // continue with next line
501 }
502
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);
507 if(p == NULL)
508 return;
509
510 // we are interessted in the first char *after* 0x0
511 p++;
512
513 // move the unprocessed tail to the start and update pos
514 memmove(dpkgbuf, p, p-dpkgbuf);
515 dpkgbuf_pos = dpkgbuf+dpkgbuf_pos-p;
516}
517 /*}}}*/
518
519bool pkgDPkgPM::OpenLog()
520{
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())
527 {
528 term_out = fopen(logfile_name.c_str(),"a");
529 chmod(logfile_name.c_str(), 0600);
530 // output current time
531 char outstr[200];
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");
538 }
539 return true;
540}
541
542bool pkgDPkgPM::CloseLog()
543{
544 if(term_out)
545 {
546 char outstr[200];
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");
553 fclose(term_out);
554 }
555 term_out = NULL;
556 return true;
557}
558
559/*{{{*/
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
563static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds,
564 fd_set *exceptfds, const struct timespec *timeout,
565 const sigset_t *sigmask)
566{
567 sigset_t origmask;
568 struct timeval tv;
569 int retval;
570
571 tv.tv_sec = timeout->tv_sec;
572 tv.tv_usec = timeout->tv_nsec/1000;
573
574 sigprocmask(SIG_SETMASK, sigmask, &origmask);
575 retval = select(nfds, readfds, writefds, exceptfds, &tv);
576 sigprocmask(SIG_SETMASK, &origmask, 0);
577 return retval;
578}
579/*}}}*/
580
581// DPkgPM::Go - Run the sequence /*{{{*/
582// ---------------------------------------------------------------------
583/* This globs the operations and calls dpkg
584 *
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.
589*/
590bool pkgDPkgPM::Go(int OutStatusFd)
591{
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);
595
596 if (RunScripts("DPkg::Pre-Invoke") == false)
597 return false;
598
599 if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
600 return false;
601
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] = {
605 // Install operation
606 {
607 {"half-installed", N_("Preparing %s")},
608 {"unpacked", N_("Unpacking %s") },
609 {NULL, NULL}
610 },
611 // Configure operation
612 {
613 {"unpacked",N_("Preparing to configure %s") },
614 {"half-configured", N_("Configuring %s") },
615#if 0
616 {"triggers-awaited", N_("Processing triggers for %s") },
617 {"triggers-pending", N_("Processing triggers for %s") },
618#endif
619 { "installed", N_("Installed %s")},
620 {NULL, NULL}
621 },
622 // Remove operation
623 {
624 {"half-configured", N_("Preparing for removal of %s")},
625#if 0
626 {"triggers-awaited", N_("Preparing for removal of %s")},
627 {"triggers-pending", N_("Preparing for removal of %s")},
628#endif
629 {"half-installed", N_("Removing %s")},
630 {"config-files", N_("Removed %s")},
631 {NULL, NULL}
632 },
633 // Purge operation
634 {
635 {"config-files", N_("Preparing to completely remove %s")},
636 {"not-installed", N_("Completely removed %s")},
637 {NULL, NULL}
638 },
639 };
640
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++)
646 {
647 string name = (*I).Pkg.Name();
648 PackageOpsDone[name] = 0;
649 for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; i++)
650 {
651 PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
652 PackagesTotal++;
653 }
654 }
655
656 stdin_is_dev_null = false;
657
658 // create log
659 OpenLog();
660
661 // this loop is runs once per operation
662 for (vector<Item>::iterator I = List.begin(); I != List.end();)
663 {
664 vector<Item>::iterator J = I;
665 for (; J != List.end() && J->Op == I->Op; J++);
666
667 // Generate the argument list
668 const char *Args[MaxArgs + 50];
669 if (J - I > (signed)MaxArgs)
670 J = I + MaxArgs;
671
672 unsigned int n = 0;
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]);
677
678 // Stick in any custom dpkg options
679 Configuration::Item const *Opts = _config->Tree("DPkg::Options");
680 if (Opts != 0)
681 {
682 Opts = Opts->Child;
683 for (; Opts != 0; Opts = Opts->Next)
684 {
685 if (Opts->Value.empty() == true)
686 continue;
687 Args[n++] = Opts->Value.c_str();
688 Size += Opts->Value.length();
689 }
690 }
691
692 char status_fd_buf[20];
693 int fd[2];
694 pipe(fd);
695
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]);
701
702 switch (I->Op)
703 {
704 case Item::Remove:
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]);
713 break;
714
715 case Item::Purge:
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]);
724 break;
725
726 case Item::Configure:
727 Args[n++] = "--configure";
728 if (NoTriggers)
729 Args[n++] = "--no-triggers";
730 Size += strlen(Args[n-1]);
731 break;
732
733 case Item::Install:
734 Args[n++] = "--unpack";
735 Size += strlen(Args[n-1]);
736 Args[n++] = "--auto-deconfigure";
737 Size += strlen(Args[n-1]);
738 break;
739 }
740
741 // Write in the file or package names
742 if (I->Op == Item::Install)
743 {
744 for (;I != J && Size < MaxArgBytes; I++)
745 {
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]);
750 }
751 }
752 else
753 {
754 for (;I != J && Size < MaxArgBytes; I++)
755 {
756 Args[n++] = I->Pkg.Name();
757 Size += strlen(Args[n-1]);
758 }
759 }
760 Args[n] = 0;
761 J = I;
762
763 if (_config->FindB("Debug::pkgDPkgPM",false) == true)
764 {
765 for (unsigned int k = 0; k != n; k++)
766 clog << Args[k] << ' ';
767 clog << endl;
768 continue;
769 }
770
771 cout << flush;
772 clog << flush;
773 cerr << flush;
774
775 typedef void (*sighandler_t)(int);
776
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);
783
784 // ignore SIGHUP as well (debian #463030)
785 sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
786
787 struct termios tt;
788 struct termios tt_out;
789 struct winsize win;
790 int master;
791 int slave;
792
793 // FIXME: setup sensible signal handling (*ick*)
794 tcgetattr(0, &tt);
795 tcgetattr(1, &tt_out);
796 ioctl(0, TIOCGWINSZ, (char *)&win);
797 if (openpty(&master, &slave, NULL, &tt_out, &win) < 0)
798 {
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);
803 master = slave = -1;
804 } else {
805 struct termios rtt;
806 rtt = tt;
807 cfmakeraw(&rtt);
808 rtt.c_lflag &= ~ECHO;
809 tcsetattr(0, TCSAFLUSH, &rtt);
810 }
811
812 // Fork dpkg
813 pid_t Child;
814 _config->Set("APT::Keep-Fds::",fd[1]);
815 Child = ExecFork();
816
817 // This is the child
818 if (Child == 0)
819 {
820 if(slave >= 0 && master >= 0)
821 {
822 setsid();
823 ioctl(slave, TIOCSCTTY, 0);
824 close(master);
825 dup2(slave, 0);
826 dup2(slave, 1);
827 dup2(slave, 2);
828 close(slave);
829 }
830 close(fd[0]); // close the read end of the pipe
831
832 if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
833 _exit(100);
834
835 if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO))
836 {
837 int Flags,dummy;
838 if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
839 _exit(100);
840
841 // Discard everything in stdin before forking dpkg
842 if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
843 _exit(100);
844
845 while (read(STDIN_FILENO,&dummy,1) == 1);
846
847 if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
848 _exit(100);
849 }
850
851
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;
857 _exit(100);
858 }
859
860 // clear the Keep-Fd again
861 _config->Clear("APT::Keep-Fds",fd[1]);
862
863 // Wait for dpkg
864 int Status = 0;
865
866 // we read from dpkg here
867 int _dpkgin = fd[0];
868 close(fd[1]); // close the write end of the pipe
869
870 // the result of the waitpid call
871 int res;
872 if(slave > 0)
873 close(slave);
874
875 // setups fds
876 fd_set rfds;
877 struct timespec tv;
878 sigset_t sigmask;
879 sigset_t original_sigmask;
880 sigemptyset(&sigmask);
881 sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask);
882
883 int select_ret;
884 while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
885 if(res < 0) {
886 // FIXME: move this to a function or something, looks ugly here
887 // error handling, waitpid returned -1
888 if (errno == EINTR)
889 continue;
890 RunScripts("DPkg::Post-Invoke");
891
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");
897 }
898
899 // wait for input or output here
900 FD_ZERO(&rfds);
901 if (!stdin_is_dev_null)
902 FD_SET(0, &rfds);
903 FD_SET(_dpkgin, &rfds);
904 if(master >= 0)
905 FD_SET(master, &rfds);
906 tv.tv_sec = 1;
907 tv.tv_nsec = 0;
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);
913 if (select_ret == 0)
914 continue;
915 else if (select_ret < 0 && errno == EINTR)
916 continue;
917 else if (select_ret < 0)
918 {
919 perror("select() returned error");
920 continue;
921 }
922
923 if(master >= 0 && FD_ISSET(master, &rfds))
924 DoTerminalPty(master);
925 if(master >= 0 && FD_ISSET(0, &rfds))
926 DoStdin(master);
927 if(FD_ISSET(_dpkgin, &rfds))
928 DoDpkgStatusFd(_dpkgin, OutStatusFd);
929 }
930 close(_dpkgin);
931
932 // Restore sig int/quit
933 signal(SIGQUIT,old_SIGQUIT);
934 signal(SIGINT,old_SIGINT);
935 signal(SIGHUP,old_SIGHUP);
936
937 if(master >= 0)
938 {
939 tcsetattr(0, TCSAFLUSH, &tt);
940 close(master);
941 }
942
943 // Check for an error code.
944 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
945 {
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
948 // for later
949 bool stopOnError = _config->FindB("Dpkg::StopOnError",true);
950
951 if(stopOnError)
952 RunScripts("DPkg::Post-Invoke");
953
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));
958 else
959 _error->Error("Sub-process %s exited unexpectedly",Args[0]);
960
961 if(stopOnError)
962 {
963 CloseLog();
964 return false;
965 }
966 }
967 }
968 CloseLog();
969
970 if (RunScripts("DPkg::Post-Invoke") == false)
971 return false;
972
973 Cache.writeStateFile(NULL);
974 return true;
975}
976 /*}}}*/
977// pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
978// ---------------------------------------------------------------------
979/* */
980void pkgDPkgPM::Reset()
981{
982 List.erase(List.begin(),List.end());
983}
984 /*}}}*/
985
986/* memrchr -- find the last occurrence of a byte in a memory block
987
988 Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2005,
989 2006, 2007, 2008 Free Software Foundation, Inc.
990
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).
996
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.
1001
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.
1006
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/>. */
1009
1010#if defined _LIBC
1011# include <memcopy.h>
1012#else
1013# include <config.h>
1014# define reg_char char
1015#endif
1016
1017#include <string.h>
1018#include <limits.h>
1019
1020#undef __memrchr
1021#ifdef _LIBC
1022# undef memrchr
1023#endif
1024
1025#ifndef weak_alias
1026# define __memrchr memrchr
1027#endif
1028
1029/* Search no more than N bytes of S for C. */
1030void *
1031__memrchr (void const *s, int c_in, size_t n)
1032{
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
1037 performance. */
1038 typedef unsigned long int longword;
1039
1040 const unsigned char *char_ptr;
1041 const longword *longword_ptr;
1042 longword repeated_one;
1043 longword repeated_c;
1044 unsigned reg_char c;
1045
1046 c = (unsigned char) c_in;
1047
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;
1052 --n)
1053 if (*--char_ptr == c)
1054 return (void *) char_ptr;
1055
1056 longword_ptr = (const longword *) char_ptr;
1057
1058 /* All these elucidatory comments refer to 4-byte longwords,
1059 but the theory applies equally well to any size longwords. */
1060
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)
1068 {
1069 repeated_one |= repeated_one << 31 << 1;
1070 repeated_c |= repeated_c << 31 << 1;
1071 if (8 < sizeof (longword))
1072 {
1073 size_t i;
1074
1075 for (i = 64; i < sizeof (longword) * 8; i *= 2)
1076 {
1077 repeated_one |= repeated_one << i;
1078 repeated_c |= repeated_c << i;
1079 }
1080 }
1081 }
1082
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.
1088
1089 We compute tmp =
1090 ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
1091 That is, we perform the following operations:
1092 1. Subtract repeated_one.
1093 2. & ~longword1.
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.
1110
1111 So, the test whether any byte in longword1 is zero is equivalent to
1112 testing whether tmp is nonzero. */
1113
1114 while (n >= sizeof (longword))
1115 {
1116 longword longword1 = *--longword_ptr ^ repeated_c;
1117
1118 if ((((longword1 - repeated_one) & ~longword1)
1119 & (repeated_one << 7)) != 0)
1120 {
1121 longword_ptr++;
1122 break;
1123 }
1124 n -= sizeof (longword);
1125 }
1126
1127 char_ptr = (const unsigned char *) longword_ptr;
1128
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. */
1135
1136 while (n-- > 0)
1137 {
1138 if (*--char_ptr == c)
1139 return (void *) char_ptr;
1140 }
1141
1142 return NULL;
1143}
1144#ifdef weak_alias
1145weak_alias (__memrchr, memrchr)
1146#endif