close leaking slave fd after setting up pty magic
[ntk/apt.git] / apt-pkg / deb / debsystem.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: debsystem.cc,v 1.4 2004/01/26 17:01:53 mdz Exp $
4 /* ######################################################################
5
6 System - Abstraction for running on different systems.
7
8 Basic general structure..
9
10 ##################################################################### */
11 /*}}}*/
12 // Include Files /*{{{*/
13 #include <config.h>
14
15 #include <apt-pkg/debsystem.h>
16 #include <apt-pkg/debversion.h>
17 #include <apt-pkg/debindexfile.h>
18 #include <apt-pkg/dpkgpm.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/error.h>
21 #include <apt-pkg/fileutl.h>
22 #include <apt-pkg/pkgcache.h>
23 #include <apt-pkg/cacheiterators.h>
24
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <string>
29 #include <vector>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <errno.h>
33
34 #include <apti18n.h>
35 /*}}}*/
36
37 using std::string;
38
39 debSystem debSys;
40
41 class debSystemPrivate {
42 public:
43 debSystemPrivate() : LockFD(-1), LockCount(0), StatusFile(0)
44 {
45 }
46 // For locking support
47 int LockFD;
48 unsigned LockCount;
49
50 debStatusIndex *StatusFile;
51 };
52
53 // System::debSystem - Constructor /*{{{*/
54 // ---------------------------------------------------------------------
55 /* */
56 debSystem::debSystem()
57 {
58 d = new debSystemPrivate();
59 Label = "Debian dpkg interface";
60 VS = &debVS;
61 }
62 /*}}}*/
63 // System::~debSystem - Destructor /*{{{*/
64 // ---------------------------------------------------------------------
65 /* */
66 debSystem::~debSystem()
67 {
68 delete d->StatusFile;
69 delete d;
70 }
71 /*}}}*/
72 // System::Lock - Get the lock /*{{{*/
73 // ---------------------------------------------------------------------
74 /* This mirrors the operations dpkg does when it starts up. Note the
75 checking of the updates directory. */
76 bool debSystem::Lock()
77 {
78 // Disable file locking
79 if (_config->FindB("Debug::NoLocking",false) == true || d->LockCount > 1)
80 {
81 d->LockCount++;
82 return true;
83 }
84
85 // Create the lockfile
86 string AdminDir = flNotFile(_config->Find("Dir::State::status"));
87 d->LockFD = GetLock(AdminDir + "lock");
88 if (d->LockFD == -1)
89 {
90 if (errno == EACCES || errno == EAGAIN)
91 return _error->Error(_("Unable to lock the administration directory (%s), "
92 "is another process using it?"),AdminDir.c_str());
93 else
94 return _error->Error(_("Unable to lock the administration directory (%s), "
95 "are you root?"),AdminDir.c_str());
96 }
97
98 // See if we need to abort with a dirty journal
99 if (CheckUpdates() == true)
100 {
101 close(d->LockFD);
102 d->LockFD = -1;
103 const char *cmd;
104 if (getenv("SUDO_USER") != NULL)
105 cmd = "sudo dpkg --configure -a";
106 else
107 cmd = "dpkg --configure -a";
108 // TRANSLATORS: the %s contains the recovery command, usually
109 // dpkg --configure -a
110 return _error->Error(_("dpkg was interrupted, you must manually "
111 "run '%s' to correct the problem. "), cmd);
112 }
113
114 d->LockCount++;
115
116 return true;
117 }
118 /*}}}*/
119 // System::UnLock - Drop a lock /*{{{*/
120 // ---------------------------------------------------------------------
121 /* */
122 bool debSystem::UnLock(bool NoErrors)
123 {
124 if (d->LockCount == 0 && NoErrors == true)
125 return false;
126
127 if (d->LockCount < 1)
128 return _error->Error(_("Not locked"));
129 if (--d->LockCount == 0)
130 {
131 close(d->LockFD);
132 d->LockCount = 0;
133 }
134
135 return true;
136 }
137 /*}}}*/
138 // System::CheckUpdates - Check if the updates dir is dirty /*{{{*/
139 // ---------------------------------------------------------------------
140 /* This does a check of the updates directory (dpkg journal) to see if it has
141 any entries in it. */
142 bool debSystem::CheckUpdates()
143 {
144 // Check for updates.. (dirty)
145 string File = flNotFile(_config->Find("Dir::State::status")) + "updates/";
146 DIR *DirP = opendir(File.c_str());
147 if (DirP == 0)
148 return false;
149
150 /* We ignore any files that are not all digits, this skips .,.. and
151 some tmp files dpkg will leave behind.. */
152 bool Damaged = false;
153 for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP))
154 {
155 Damaged = true;
156 for (unsigned int I = 0; Ent->d_name[I] != 0; I++)
157 {
158 // Check if its not a digit..
159 if (isdigit(Ent->d_name[I]) == 0)
160 {
161 Damaged = false;
162 break;
163 }
164 }
165 if (Damaged == true)
166 break;
167 }
168 closedir(DirP);
169
170 return Damaged;
171 }
172 /*}}}*/
173 // System::CreatePM - Create the underlying package manager /*{{{*/
174 // ---------------------------------------------------------------------
175 /* */
176 pkgPackageManager *debSystem::CreatePM(pkgDepCache *Cache) const
177 {
178 return new pkgDPkgPM(Cache);
179 }
180 /*}}}*/
181 // System::Initialize - Setup the configuration space.. /*{{{*/
182 // ---------------------------------------------------------------------
183 /* These are the Debian specific configuration variables.. */
184 bool debSystem::Initialize(Configuration &Cnf)
185 {
186 /* These really should be jammed into a generic 'Local Database' engine
187 which is yet to be determined. The functions in pkgcachegen should
188 be the only users of these */
189 Cnf.CndSet("Dir::State::extended_states", "extended_states");
190 Cnf.CndSet("Dir::State::status","/var/lib/dpkg/status");
191 Cnf.CndSet("Dir::Bin::dpkg","/usr/bin/dpkg");
192
193 if (d->StatusFile) {
194 delete d->StatusFile;
195 d->StatusFile = 0;
196 }
197
198 return true;
199 }
200 /*}}}*/
201 // System::ArchiveSupported - Is a file format supported /*{{{*/
202 // ---------------------------------------------------------------------
203 /* The standard name for a deb is 'deb'.. There are no separate versions
204 of .deb to worry about.. */
205 APT_PURE bool debSystem::ArchiveSupported(const char *Type)
206 {
207 if (strcmp(Type,"deb") == 0)
208 return true;
209 return false;
210 }
211 /*}}}*/
212 // System::Score - Determine how 'Debiany' this sys is.. /*{{{*/
213 // ---------------------------------------------------------------------
214 /* We check some files that are sure tell signs of this being a Debian
215 System.. */
216 signed debSystem::Score(Configuration const &Cnf)
217 {
218 signed Score = 0;
219 if (FileExists(Cnf.FindFile("Dir::State::status","/var/lib/dpkg/status")) == true)
220 Score += 10;
221 if (FileExists(Cnf.FindFile("Dir::Bin::dpkg","/usr/bin/dpkg")) == true)
222 Score += 10;
223 if (FileExists("/etc/debian_version") == true)
224 Score += 10;
225 return Score;
226 }
227 /*}}}*/
228 // System::AddStatusFiles - Register the status files /*{{{*/
229 // ---------------------------------------------------------------------
230 /* */
231 bool debSystem::AddStatusFiles(std::vector<pkgIndexFile *> &List)
232 {
233 if (d->StatusFile == 0)
234 d->StatusFile = new debStatusIndex(_config->FindFile("Dir::State::status"));
235 List.push_back(d->StatusFile);
236 return true;
237 }
238 /*}}}*/
239 // System::FindIndex - Get an index file for status files /*{{{*/
240 // ---------------------------------------------------------------------
241 /* */
242 bool debSystem::FindIndex(pkgCache::PkgFileIterator File,
243 pkgIndexFile *&Found) const
244 {
245 if (d->StatusFile == 0)
246 return false;
247 if (d->StatusFile->FindInCache(*File.Cache()) == File)
248 {
249 Found = d->StatusFile;
250 return true;
251 }
252
253 return false;
254 }
255 /*}}}*/