1 : // -*- C++ -*-
2 :
3 : #include <string>
4 : #include <wibble/test.h>
5 :
6 : #include <ept/token.h>
7 : #include <ept/core/source.h>
8 :
9 : #include <iostream>
10 : #include <wibble/exception.h>
11 :
12 : #include <apt-pkg/pkgcache.h>
13 : #include <apt-pkg/sourcelist.h>
14 : #include <apt-pkg/error.h>
15 : #include <apt-pkg/policy.h>
16 : #include <apt-pkg/cachefile.h>
17 : #include <apt-pkg/progress.h>
18 : #include <apt-pkg/pkgcachegen.h>
19 : #include <apt-pkg/init.h>
20 :
21 : #ifndef EPT_APT_H
22 : #define EPT_APT_H
23 :
24 : namespace ept {
25 : namespace core {
26 :
27 0 : struct AptException : wibble::exception::Generic {
28 0 : std::string desc() const throw () {
29 0 : return "APT Error";
30 : }
31 :
32 0 : AptException( const std::string &ctx ) : Generic( ctx ) {
33 0 : while ( !_error->empty() ) {
34 0 : std::string err;
35 0 : _error->PopMessage( err );
36 0 : std::cerr << err << std::endl;
37 0 : addContext( err );
38 : }
39 0 : }
40 : };
41 :
42 : struct PackageState {
43 : enum Query {
44 : Install = 1 << 0,
45 : Upgrade = 1 << 1,
46 : Keep = 1 << 2,
47 : Remove = 1 << 3,
48 : Installed = 1 << 4,
49 : Upgradable = 1 << 5,
50 : NowBroken = 1 << 6,
51 : WillBreak = 1 << 7,
52 : ReInstall = 1 << 8,
53 : Purge = 1 << 9,
54 : Hold = 1 << 10,
55 : Valid = 1 << 11
56 : };
57 :
58 : typedef unsigned state;
59 :
60 3786 : operator unsigned() { return m_state; };
61 :
62 : PackageState &operator=( unsigned i ) {
63 : m_state = i;
64 : return *this;
65 : }
66 :
67 5218 : PackageState &operator|=( const PackageState &s ) {
68 5218 : m_state |= s.m_state;
69 5218 : return *this;
70 : }
71 :
72 9003 : PackageState( unsigned a ) {
73 9003 : m_state = a;
74 9003 : }
75 :
76 1 : PackageState() : m_state( 0 ) {}
77 :
78 : // FIXME this probably needs to be used consistently in core and out of core
79 2 : bool isValid() const { return m_state & Valid; }
80 : // FIXME compatibility API for non-core apt
81 1 : bool isInstalled() const { return installed(); }
82 :
83 2 : bool install() const { return m_state & Install; }
84 : // reinstall() implies install()
85 : bool reinstall() const { return m_state & ReInstall; }
86 : bool remove() const { return m_state & Remove; }
87 : // purge() implies remove()
88 3775 : bool purge() const { return m_state & Purge; }
89 3780 : bool keep() const { return m_state & Keep; }
90 : bool willBreak() const { return m_state & WillBreak; }
91 : // upgrade() implies install()
92 : bool upgrade() const { return hasNewVersion() && install(); }
93 : // newInsstal() implies install()
94 : bool newInstall() const { return !installed() && install(); }
95 : bool hold() const { return m_state & Hold; }
96 :
97 1 : bool installed() const { return m_state & Installed; }
98 : bool hasNewVersion() const { return m_state & Upgradable; }
99 : bool upgradable() const { return hasNewVersion() && !hold(); }
100 : bool held() const { return hasNewVersion() && hold(); }
101 : bool nowBroken() const { return m_state & NowBroken; }
102 :
103 : bool modify() const { return install() || remove(); }
104 :
105 : protected:
106 : unsigned m_state;
107 : };
108 :
109 : time_t aptTimestamp();
110 :
111 : // wrap the apt's database
112 : struct AptDatabase {
113 5093 : pkgCache &cache() {
114 5093 : if ( !m_cache )
115 20 : openCache();
116 5093 : return *m_cache;
117 : }
118 :
119 3793 : pkgDepCache &state() {
120 3793 : if ( !m_state )
121 5 : openState();
122 3793 : return *m_state;
123 : }
124 :
125 1436 : pkgPolicy &policy() {
126 1436 : if ( !m_policy )
127 0 : openCache();
128 1436 : return *m_policy;
129 : }
130 :
131 : OpProgress *m_progress;
132 : bool m_tryWriteable;
133 : bool m_writeable;
134 :
135 : time_t timestamp() {
136 : return aptTimestamp();
137 : }
138 :
139 73 : AptDatabase() {
140 73 : m_cache = 0;
141 73 : m_state = 0;
142 73 : m_policy = 0;
143 73 : m_progress = new OpProgress();
144 73 : m_tryWriteable = true;
145 73 : m_writeable = false;
146 73 : }
147 :
148 : void setProgress( OpProgress *p ) {
149 : m_progress = p;
150 : }
151 :
152 : bool writeable() {
153 : if ( !m_cache )
154 : openCache();
155 : return m_writeable;
156 : }
157 :
158 5 : void openState() {
159 5 : m_state = new pkgDepCache( &cache(), m_policy );
160 5 : m_state->Init( m_progress );
161 5 : m_progress->Done();
162 5 : }
163 :
164 20 : void openCache() {
165 20 : if ( !_config->FindB("Initialized") ) {
166 0 : pkgInitConfig(*_config);
167 0 : _config->Set("Initialized", 1);
168 0 : pkgInitSystem(*_config, _system);
169 : }
170 :
171 20 : m_writeable = m_tryWriteable;
172 :
173 20 : if ( m_tryWriteable ) {
174 : try {
175 20 : _system->Lock();
176 0 : } catch ( std::exception e ) {
177 0 : m_tryWriteable = false;
178 0 : openCache();
179 0 : m_tryWriteable = true;
180 0 : throw;
181 : }
182 : }
183 :
184 20 : pkgSourceList list;
185 20 : if ( list.ReadMainList() == false ) {
186 0 : _error->DumpErrors();
187 : throw wibble::exception::System(
188 0 : "The list of sources could not be read." );
189 : }
190 :
191 20 : MMap *m = 0;
192 20 : bool Res = pkgMakeStatusCache( list, *m_progress, &m, !m_writeable );
193 :
194 20 : if ( !Res ) {
195 : std::cerr << "The package lists or status file "
196 0 : "could not be parsed or opened." << std::endl;
197 : throw AptException(
198 : "The package lists or status file "
199 0 : "could not be parsed or opened." );
200 : }
201 :
202 20 : m_cache = new pkgCache( m, true );
203 40 : m_policy = new pkgPolicy( m_cache );
204 40 : if ( ReadPinFile( *m_policy ) == false )
205 0 : throw wibble::exception::System( "error reading pin file" );
206 20 : m_progress->Done();
207 20 : }
208 :
209 74 : void invalidate() {
210 74 : if ( _config->FindB("Initialized") ) {
211 74 : _system->UnLock();
212 : }
213 :
214 74 : delete m_state;
215 74 : m_state = 0;
216 74 : delete m_policy;
217 74 : m_policy = 0;
218 74 : delete m_cache;
219 74 : m_cache = 0;
220 74 : }
221 :
222 : pkgCache::VerIterator anyVersion( pkgCache::PkgIterator pi ) {
223 : if ( pi.end() ) return pkgCache::VerIterator();
224 : return pi.VersionList();
225 : }
226 :
227 5 : Token candidateVersion( Token p ) {
228 5 : pkgCache::PkgIterator pi = cache().FindPkg( p.package() );
229 6 : if ( pi.end() ) return Token();
230 4 : pkgCache::VerIterator vi = policy().GetCandidateVer( pi );
231 4 : if ( vi.end() ) return Token();
232 :
233 4 : Token t; t._id = p.package() + "_" + vi.VerStr();
234 4 : return t;
235 : }
236 :
237 1432 : pkgCache::VerIterator candidateVersion( pkgCache::PkgIterator pi ) {
238 1432 : if ( pi.end() ) return pkgCache::VerIterator();
239 1432 : pkgCache::VerIterator vi = policy().GetCandidateVer( pi );
240 1432 : if ( vi.end() ) return pkgCache::VerIterator();
241 1432 : return vi;
242 : }
243 :
244 1432 : pkgCache::VerIterator installedVersion( pkgCache::PkgIterator pi ) {
245 1432 : if ( pi.end() ) return pkgCache::VerIterator();
246 : pkgCache::VerIterator vi = pkgCache::VerIterator( cache(),
247 1432 : cache().VerP + pi->CurrentVer );
248 1432 : if ( vi.end() ) return pkgCache::VerIterator();
249 1432 : return vi;
250 : }
251 :
252 27 : pkgCache::PkgIterator lookupPackage( Token t ) {
253 27 : return cache().FindPkg( t.package() );
254 : }
255 :
256 5 : pkgCache::VerIterator lookupVersion( Token t ) {
257 5 : if ( !t.hasVersion() )
258 5 : t = candidateVersion( t );
259 5 : pkgCache::PkgIterator pi = lookupPackage( t );
260 5 : if ( pi.end() )
261 1 : return pkgCache::VerIterator();
262 4 : for (pkgCache::VerIterator vi = pi.VersionList(); !vi.end(); ++vi)
263 4 : if ( t.version() == vi.VerStr() )
264 4 : return vi;
265 0 : return pkgCache::VerIterator();
266 : }
267 :
268 : static pkgCache::VerFileIterator lookupVersionFile(
269 5 : pkgCache::VerIterator vi )
270 : {
271 5 : if ( vi.end() )
272 1 : return pkgCache::VerFileIterator();
273 4 : pkgCache::VerFileIterator vfi = vi.FileList();
274 4 : for ( ; !vfi.end(); vfi++ )
275 4 : if ( ( vfi.File()->Flags & pkgCache::Flag::NotSource ) == 0)
276 4 : break;
277 4 : if ( vfi.end() )
278 0 : vfi = vi.FileList();
279 4 : return vfi;
280 : }
281 :
282 0 : PackageState invalidState() {
283 0 : return PackageState( PackageState::NowBroken | PackageState::Keep );
284 : }
285 :
286 3784 : PackageState packageState( pkgCache::PkgIterator P )
287 : {
288 3784 : PackageState s = 0;
289 3784 : if ( P.end() )
290 0 : return invalidState();
291 3784 : if ( ! ( P->CurrentState == pkgCache::State::ConfigFiles
292 : || P->CurrentState == pkgCache::State::NotInstalled ) )
293 1432 : s |= PackageState::Installed;
294 3784 : if ( s & PackageState::Installed &&
295 : candidateVersion( P ) != installedVersion( P ) )
296 1 : s |= PackageState::Upgradable;
297 3784 : pkgDepCache::StateCache S = state()[ P ];
298 3784 : if ( S.Install() )
299 3 : s |= PackageState::Install;
300 3784 : if ( ( S.iFlags & pkgDepCache::ReInstall )
301 : == pkgDepCache::ReInstall )
302 0 : s |= PackageState::ReInstall;
303 3784 : if ( S.Keep() )
304 3780 : s |= PackageState::Keep;
305 3784 : if ( S.Delete() )
306 1 : s |= PackageState::Remove;
307 3784 : if ( ( S.iFlags & pkgDepCache::Purge ) == pkgDepCache::Purge )
308 0 : s |= PackageState::Purge;
309 3784 : if ( S.NowBroken() )
310 1 : s |= PackageState::NowBroken;
311 3784 : if ( S.InstBroken() )
312 0 : s |= PackageState::WillBreak;
313 3784 : if ( P->SelectedState == pkgCache::State::Hold )
314 0 : s |= PackageState::Hold;
315 3784 : return s;
316 : }
317 :
318 1 : PackageState packageState( Token t ) {
319 1 : t = validate( t );
320 1 : if ( t.valid() )
321 1 : return packageState( lookupPackage( t ) );
322 0 : return invalidState();
323 : }
324 :
325 4 : Token validate( Token t ) {
326 4 : if ( t.hasVersion() )
327 0 : return lookupVersion( t ).end() ? Token() : t;
328 4 : return lookupPackage( t ).end() ? Token() : t;
329 : }
330 :
331 73 : ~AptDatabase() {
332 73 : invalidate();
333 73 : }
334 :
335 : protected:
336 : pkgCache *m_cache;
337 : pkgDepCache *m_state;
338 : pkgPolicy *m_policy;
339 : };
340 :
341 : template< typename Internal >
342 : struct AptInternalList {
343 : Internal m_head;
344 : typedef Internal Type;
345 11331 : AptInternalList tail() const {
346 11331 : AptInternalList t = *this;
347 11331 : t.m_head++;
348 : return t;
349 : }
350 7554 : const Internal &head() const { return m_head; }
351 3781 : Internal &head() { return m_head; }
352 11334 : bool empty() const { return m_head.end(); }
353 3 : AptInternalList( Internal head ) : m_head( head ) {}
354 : AptInternalList() {}
355 : };
356 :
357 : namespace version {
358 :
359 : typedef enum { Package, VersionString, Section, Architecture,
360 : Depends, Recommends, Record } PropertyId;
361 :
362 : typedef pkgCache::VerIterator Internal;
363 : template< PropertyId > struct PropertyType {};
364 :
365 : }
366 :
367 : namespace package {
368 :
369 : typedef enum { Name, Versions, AnyVersion, State, CandidateVersion,
370 : InstalledVersion } PropertyId;
371 : typedef pkgCache::PkgIterator Internal;
372 : template< PropertyId > struct PropertyType {};
373 :
374 : struct VersionList {
375 : version::Internal m_head;
376 : VersionList tail() const;
377 : const version::Internal &head() const { return m_head; }
378 : version::Internal &head() { return m_head; }
379 : };
380 :
381 : typedef AptInternalList< Internal > InternalList;
382 :
383 : }
384 :
385 : namespace record {
386 :
387 : typedef enum { Record, Name, Priority, Section, InstalledSize, Maintainer,
388 : Architecture, SourcePackage, Version, Description,
389 : ShortDescription, LongDescription, PackageSize } PropertyId;
390 :
391 : extern const char *fields[];
392 :
393 : typedef pkgCache::VerFileIterator Internal;
394 :
395 : template< PropertyId > struct PropertyType {
396 : typedef std::string T;
397 : };
398 :
399 : }
400 : }
401 : }
402 :
403 : #include <ept/core/apt/package.h>
404 : #include <ept/core/apt/version.h>
405 : #include <ept/core/apt/record.h>
406 :
407 : #endif
|