]> git.saurik.com Git - apt-legacy.git/blame - apt-pkg/deb/dpkgpm.cc.orig
I feel... vindicated?
[apt-legacy.git] / apt-pkg / deb / dpkgpm.cc.orig
CommitLineData
00ec24d0
JF
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-essential";
708 Size += strlen(Args[n-1]);
709 Args[n++] = "--remove";
710 Size += strlen(Args[n-1]);
711 break;
712
713 case Item::Purge:
714 Args[n++] = "--force-depends";
715 Size += strlen(Args[n-1]);
716 Args[n++] = "--force-remove-essential";
717 Size += strlen(Args[n-1]);
718 Args[n++] = "--purge";
719 Size += strlen(Args[n-1]);
720 break;
721
722 case Item::Configure:
723 Args[n++] = "--configure";
724 if (NoTriggers)
725 Args[n++] = "--no-triggers";
726 Size += strlen(Args[n-1]);
727 break;
728
729 case Item::Install:
730 Args[n++] = "--unpack";
731 Size += strlen(Args[n-1]);
732 Args[n++] = "--auto-deconfigure";
733 Size += strlen(Args[n-1]);
734 break;
735 }
736
737 // Write in the file or package names
738 if (I->Op == Item::Install)
739 {
740 for (;I != J && Size < MaxArgBytes; I++)
741 {
742 if (I->File[0] != '/')
743 return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
744 Args[n++] = I->File.c_str();
745 Size += strlen(Args[n-1]);
746 }
747 }
748 else
749 {
750 for (;I != J && Size < MaxArgBytes; I++)
751 {
752 Args[n++] = I->Pkg.Name();
753 Size += strlen(Args[n-1]);
754 }
755 }
756 Args[n] = 0;
757 J = I;
758
759 if (_config->FindB("Debug::pkgDPkgPM",false) == true)
760 {
761 for (unsigned int k = 0; k != n; k++)
762 clog << Args[k] << ' ';
763 clog << endl;
764 continue;
765 }
766
767 cout << flush;
768 clog << flush;
769 cerr << flush;
770
771 typedef void (*sighandler_t)(int);
772
773 /* Mask off sig int/quit. We do this because dpkg also does when
774 it forks scripts. What happens is that when you hit ctrl-c it sends
775 it to all processes in the group. Since dpkg ignores the signal
776 it doesn't die but we do! So we must also ignore it */
777 sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
778 sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN);
779
780 // ignore SIGHUP as well (debian #463030)
781 sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
782
783 struct termios tt;
784 struct termios tt_out;
785 struct winsize win;
786 int master;
787 int slave;
788
789 // FIXME: setup sensible signal handling (*ick*)
790 tcgetattr(0, &tt);
791 tcgetattr(1, &tt_out);
792 ioctl(0, TIOCGWINSZ, (char *)&win);
793 if (openpty(&master, &slave, NULL, &tt_out, &win) < 0)
794 {
795 const char *s = _("Can not write log, openpty() "
796 "failed (/dev/pts not mounted?)\n");
797 fprintf(stderr, "%s",s);
798 fprintf(term_out, "%s",s);
799 master = slave = -1;
800 } else {
801 struct termios rtt;
802 rtt = tt;
803 cfmakeraw(&rtt);
804 rtt.c_lflag &= ~ECHO;
805 tcsetattr(0, TCSAFLUSH, &rtt);
806 }
807
808 // Fork dpkg
809 pid_t Child;
810 _config->Set("APT::Keep-Fds::",fd[1]);
811 Child = ExecFork();
812
813 // This is the child
814 if (Child == 0)
815 {
816 if(slave >= 0 && master >= 0)
817 {
818 setsid();
819 ioctl(slave, TIOCSCTTY, 0);
820 close(master);
821 dup2(slave, 0);
822 dup2(slave, 1);
823 dup2(slave, 2);
824 close(slave);
825 }
826 close(fd[0]); // close the read end of the pipe
827
828 if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
829 _exit(100);
830
831 if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO))
832 {
833 int Flags,dummy;
834 if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
835 _exit(100);
836
837 // Discard everything in stdin before forking dpkg
838 if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
839 _exit(100);
840
841 while (read(STDIN_FILENO,&dummy,1) == 1);
842
843 if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
844 _exit(100);
845 }
846
847
848 /* No Job Control Stop Env is a magic dpkg var that prevents it
849 from using sigstop */
850 putenv((char *)"DPKG_NO_TSTP=yes");
851 execvp(Args[0],(char **)Args);
852 cerr << "Could not exec dpkg!" << endl;
853 _exit(100);
854 }
855
856 // clear the Keep-Fd again
857 _config->Clear("APT::Keep-Fds",fd[1]);
858
859 // Wait for dpkg
860 int Status = 0;
861
862 // we read from dpkg here
863 int _dpkgin = fd[0];
864 close(fd[1]); // close the write end of the pipe
865
866 // the result of the waitpid call
867 int res;
868 if(slave > 0)
869 close(slave);
870
871 // setups fds
872 fd_set rfds;
873 struct timespec tv;
874 sigset_t sigmask;
875 sigset_t original_sigmask;
876 sigemptyset(&sigmask);
877 sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask);
878
879 int select_ret;
880 while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
881 if(res < 0) {
882 // FIXME: move this to a function or something, looks ugly here
883 // error handling, waitpid returned -1
884 if (errno == EINTR)
885 continue;
886 RunScripts("DPkg::Post-Invoke");
887
888 // Restore sig int/quit
889 signal(SIGQUIT,old_SIGQUIT);
890 signal(SIGINT,old_SIGINT);
891 signal(SIGHUP,old_SIGHUP);
892 return _error->Errno("waitpid","Couldn't wait for subprocess");
893 }
894
895 // wait for input or output here
896 FD_ZERO(&rfds);
897 if (!stdin_is_dev_null)
898 FD_SET(0, &rfds);
899 FD_SET(_dpkgin, &rfds);
900 if(master >= 0)
901 FD_SET(master, &rfds);
902 tv.tv_sec = 1;
903 tv.tv_nsec = 0;
904 select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL,
905 &tv, &original_sigmask);
906 if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS))
907 select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL,
908 NULL, &tv, &original_sigmask);
909 if (select_ret == 0)
910 continue;
911 else if (select_ret < 0 && errno == EINTR)
912 continue;
913 else if (select_ret < 0)
914 {
915 perror("select() returned error");
916 continue;
917 }
918
919 if(master >= 0 && FD_ISSET(master, &rfds))
920 DoTerminalPty(master);
921 if(master >= 0 && FD_ISSET(0, &rfds))
922 DoStdin(master);
923 if(FD_ISSET(_dpkgin, &rfds))
924 DoDpkgStatusFd(_dpkgin, OutStatusFd);
925 }
926 close(_dpkgin);
927
928 // Restore sig int/quit
929 signal(SIGQUIT,old_SIGQUIT);
930 signal(SIGINT,old_SIGINT);
931 signal(SIGHUP,old_SIGHUP);
932
933 if(master >= 0)
934 {
935 tcsetattr(0, TCSAFLUSH, &tt);
936 close(master);
937 }
938
939 // Check for an error code.
940 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
941 {
942 // if it was set to "keep-dpkg-runing" then we won't return
943 // here but keep the loop going and just report it as a error
944 // for later
945 bool stopOnError = _config->FindB("Dpkg::StopOnError",true);
946
947 if(stopOnError)
948 RunScripts("DPkg::Post-Invoke");
949
950 if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
951 _error->Error("Sub-process %s received a segmentation fault.",Args[0]);
952 else if (WIFEXITED(Status) != 0)
953 _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
954 else
955 _error->Error("Sub-process %s exited unexpectedly",Args[0]);
956
957 if(stopOnError)
958 {
959 CloseLog();
960 return false;
961 }
962 }
963 }
964 CloseLog();
965
966 if (RunScripts("DPkg::Post-Invoke") == false)
967 return false;
968
969 Cache.writeStateFile(NULL);
970 return true;
971}
972 /*}}}*/
973// pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
974// ---------------------------------------------------------------------
975/* */
976void pkgDPkgPM::Reset()
977{
978 List.erase(List.begin(),List.end());
979}
980 /*}}}*/
981
982/* memrchr -- find the last occurrence of a byte in a memory block
983
984 Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2005,
985 2006, 2007, 2008 Free Software Foundation, Inc.
986
987 Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
988 with help from Dan Sahlin (dan@sics.se) and
989 commentary by Jim Blandy (jimb@ai.mit.edu);
990 adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
991 and implemented by Roland McGrath (roland@ai.mit.edu).
992
993 This program is free software: you can redistribute it and/or modify
994 it under the terms of the GNU General Public License as published by
995 the Free Software Foundation; either version 3 of the License, or
996 (at your option) any later version.
997
998 This program is distributed in the hope that it will be useful,
999 but WITHOUT ANY WARRANTY; without even the implied warranty of
1000 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1001 GNU General Public License for more details.
1002
1003 You should have received a copy of the GNU General Public License
1004 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1005
1006#if defined _LIBC
1007# include <memcopy.h>
1008#else
1009# include <config.h>
1010# define reg_char char
1011#endif
1012
1013#include <string.h>
1014#include <limits.h>
1015
1016#undef __memrchr
1017#ifdef _LIBC
1018# undef memrchr
1019#endif
1020
1021#ifndef weak_alias
1022# define __memrchr memrchr
1023#endif
1024
1025/* Search no more than N bytes of S for C. */
1026void *
1027__memrchr (void const *s, int c_in, size_t n)
1028{
1029 /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
1030 long instead of a 64-bit uintmax_t tends to give better
1031 performance. On 64-bit hardware, unsigned long is generally 64
1032 bits already. Change this typedef to experiment with
1033 performance. */
1034 typedef unsigned long int longword;
1035
1036 const unsigned char *char_ptr;
1037 const longword *longword_ptr;
1038 longword repeated_one;
1039 longword repeated_c;
1040 unsigned reg_char c;
1041
1042 c = (unsigned char) c_in;
1043
1044 /* Handle the last few bytes by reading one byte at a time.
1045 Do this until CHAR_PTR is aligned on a longword boundary. */
1046 for (char_ptr = (const unsigned char *) s + n;
1047 n > 0 && (size_t) char_ptr % sizeof (longword) != 0;
1048 --n)
1049 if (*--char_ptr == c)
1050 return (void *) char_ptr;
1051
1052 longword_ptr = (const longword *) char_ptr;
1053
1054 /* All these elucidatory comments refer to 4-byte longwords,
1055 but the theory applies equally well to any size longwords. */
1056
1057 /* Compute auxiliary longword values:
1058 repeated_one is a value which has a 1 in every byte.
1059 repeated_c has c in every byte. */
1060 repeated_one = 0x01010101;
1061 repeated_c = c | (c << 8);
1062 repeated_c |= repeated_c << 16;
1063 if (0xffffffffU < (longword) -1)
1064 {
1065 repeated_one |= repeated_one << 31 << 1;
1066 repeated_c |= repeated_c << 31 << 1;
1067 if (8 < sizeof (longword))
1068 {
1069 size_t i;
1070
1071 for (i = 64; i < sizeof (longword) * 8; i *= 2)
1072 {
1073 repeated_one |= repeated_one << i;
1074 repeated_c |= repeated_c << i;
1075 }
1076 }
1077 }
1078
1079 /* Instead of the traditional loop which tests each byte, we will test a
1080 longword at a time. The tricky part is testing if *any of the four*
1081 bytes in the longword in question are equal to c. We first use an xor
1082 with repeated_c. This reduces the task to testing whether *any of the
1083 four* bytes in longword1 is zero.
1084
1085 We compute tmp =
1086 ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
1087 That is, we perform the following operations:
1088 1. Subtract repeated_one.
1089 2. & ~longword1.
1090 3. & a mask consisting of 0x80 in every byte.
1091 Consider what happens in each byte:
1092 - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
1093 and step 3 transforms it into 0x80. A carry can also be propagated
1094 to more significant bytes.
1095 - If a byte of longword1 is nonzero, let its lowest 1 bit be at
1096 position k (0 <= k <= 7); so the lowest k bits are 0. After step 1,
1097 the byte ends in a single bit of value 0 and k bits of value 1.
1098 After step 2, the result is just k bits of value 1: 2^k - 1. After
1099 step 3, the result is 0. And no carry is produced.
1100 So, if longword1 has only non-zero bytes, tmp is zero.
1101 Whereas if longword1 has a zero byte, call j the position of the least
1102 significant zero byte. Then the result has a zero at positions 0, ...,
1103 j-1 and a 0x80 at position j. We cannot predict the result at the more
1104 significant bytes (positions j+1..3), but it does not matter since we
1105 already have a non-zero bit at position 8*j+7.
1106
1107 So, the test whether any byte in longword1 is zero is equivalent to
1108 testing whether tmp is nonzero. */
1109
1110 while (n >= sizeof (longword))
1111 {
1112 longword longword1 = *--longword_ptr ^ repeated_c;
1113
1114 if ((((longword1 - repeated_one) & ~longword1)
1115 & (repeated_one << 7)) != 0)
1116 {
1117 longword_ptr++;
1118 break;
1119 }
1120 n -= sizeof (longword);
1121 }
1122
1123 char_ptr = (const unsigned char *) longword_ptr;
1124
1125 /* At this point, we know that either n < sizeof (longword), or one of the
1126 sizeof (longword) bytes starting at char_ptr is == c. On little-endian
1127 machines, we could determine the first such byte without any further
1128 memory accesses, just by looking at the tmp result from the last loop
1129 iteration. But this does not work on big-endian machines. Choose code
1130 that works in both cases. */
1131
1132 while (n-- > 0)
1133 {
1134 if (*--char_ptr == c)
1135 return (void *) char_ptr;
1136 }
1137
1138 return NULL;
1139}
1140#ifdef weak_alias
1141weak_alias (__memrchr, memrchr)
1142#endif