]>
Commit | Line | Data |
---|---|---|
7939f6d1 RC |
1 | /* |
2 | * Copyright (c) 2001, Robert Collins. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by Robert Collins <rbtcollins@hotmail.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | #if 0 | |
7e8fc33c | 17 | static const char *cvsid = "\n%%% $Id$\n"; |
7939f6d1 RC |
18 | #endif |
19 | ||
20 | #include <stdio.h> | |
21 | #include <stdlib.h> | |
22 | #include <unistd.h> | |
23 | #include <strings.h> | |
7939f6d1 RC |
24 | |
25 | #include "io_stream.h" | |
26 | #include "compress.h" | |
27 | ||
28 | #include "filemanip.h" | |
fa0c0d10 RC |
29 | #include "hash.h" |
30 | #include "log.h" | |
31 | /* io_stream needs a bit of tweaking to get rid of this. TODO */ | |
32 | #include "mount.h" | |
33 | /* this goes at the same time */ | |
34 | #include "win32.h" | |
7939f6d1 | 35 | |
bb849dbd RC |
36 | |
37 | #include "category.h" | |
8e9aa511 | 38 | #include "script.h" |
bb849dbd | 39 | |
fa0c0d10 | 40 | #include "package_version.h" |
7939f6d1 RC |
41 | #include "cygpackage.h" |
42 | #include "package_meta.h" | |
cbfc4215 | 43 | #include "package_db.h" |
7939f6d1 | 44 | |
fa0c0d10 | 45 | static const char *standard_dirs[] = { |
204315f9 RC |
46 | "bin", |
47 | "etc", | |
48 | "lib", | |
49 | "tmp", | |
50 | "usr", | |
51 | "usr/bin", | |
52 | "usr/lib", | |
53 | "usr/src", | |
54 | "usr/local", | |
55 | "usr/local/bin", | |
56 | "usr/local/etc", | |
57 | "usr/local/lib", | |
58 | "usr/tmp", | |
59 | "var/run", | |
60 | "var/tmp", | |
fa0c0d10 RC |
61 | 0 |
62 | }; | |
63 | ||
64 | void | |
3c054baf | 65 | hash::add_subdirs (String const &tpath) |
fa0c0d10 RC |
66 | { |
67 | char *nonp, *pp; | |
3c054baf | 68 | char *path = tpath.cstr(); |
fa0c0d10 RC |
69 | for (nonp = path; *nonp == '\\' || *nonp == '/'; nonp++); |
70 | for (pp = path + strlen (path) - 1; pp > nonp; pp--) | |
71 | if (*pp == '/' || *pp == '\\') | |
72 | { | |
73 | int i, s = 0; | |
74 | char c = *pp; | |
75 | *pp = 0; | |
76 | for (i = 0; standard_dirs[i]; i++) | |
77 | if (strcmp (standard_dirs[i] + 1, path) == 0) | |
78 | { | |
79 | s = 1; | |
80 | break; | |
81 | } | |
82 | if (s == 0) | |
83 | add (path); | |
84 | *pp = c; | |
85 | } | |
86 | } | |
87 | ||
7c6ef2c3 RC |
88 | /*****************/ |
89 | ||
90 | CategoryPackage::~CategoryPackage() | |
91 | { | |
92 | CategoryPackage **temp = &key.packages; | |
93 | while (*temp != this) | |
94 | temp = &((*temp)->next); | |
95 | *temp = next; | |
96 | } | |
97 | ||
98 | /*****************/ | |
99 | ||
7e8fc33c RC |
100 | const |
101 | packagemeta::_actions | |
102 | packagemeta::Default_action (0); | |
103 | const | |
104 | packagemeta::_actions | |
105 | packagemeta::Install_action (1); | |
106 | const | |
107 | packagemeta::_actions | |
108 | packagemeta::Reinstall_action (2); | |
109 | const | |
110 | packagemeta::_actions | |
111 | packagemeta::Uninstall_action (3); | |
112 | ||
113 | char const * | |
114 | packagemeta::_actions::caption () | |
115 | { | |
116 | switch (_value) | |
117 | { | |
118 | case 0: | |
119 | return "Default"; | |
120 | case 1: | |
121 | return "Install"; | |
122 | case 2: | |
123 | return "Reinstall"; | |
124 | case 3: | |
125 | return "Uninstall"; | |
126 | } | |
127 | // Pacify GCC: (all case options are checked above) | |
128 | return 0; | |
129 | } | |
130 | ||
131 | packagemeta::_actions & packagemeta::_actions::operator++ () | |
132 | { | |
133 | ++_value; | |
134 | if (_value > 3) | |
135 | _value = 0; | |
136 | return *this; | |
137 | } | |
138 | ||
7c6ef2c3 RC |
139 | packagemeta::~packagemeta() |
140 | { | |
141 | while (Categories.number ()) | |
142 | { | |
143 | CategoryPackage *catpkg = Categories.removebyindex (1); | |
144 | delete catpkg; | |
145 | } | |
146 | while (versions.number ()) | |
147 | { | |
148 | packageversion *pv = versions.removebyindex(1); | |
149 | delete pv; | |
150 | } | |
151 | } | |
152 | ||
7939f6d1 | 153 | void |
fa0c0d10 | 154 | packagemeta::add_version (packageversion & thepkg) |
7939f6d1 | 155 | { |
bb849dbd | 156 | versions.registerbyobject (thepkg); |
7939f6d1 RC |
157 | } |
158 | ||
159 | /* assumption: package thepkg is already in the metadata list. */ | |
160 | void | |
fa0c0d10 | 161 | packagemeta::set_installed (packageversion & thepkg) |
7939f6d1 | 162 | { |
bb849dbd RC |
163 | packageversion *temp = versions.getbykey (thepkg.key); |
164 | if (temp == &thepkg) | |
165 | installed = &thepkg; | |
7939f6d1 | 166 | } |
fa0c0d10 RC |
167 | |
168 | /* uninstall a package if it's installed */ | |
169 | void | |
170 | packagemeta::uninstall () | |
171 | { | |
172 | if (installed) | |
173 | { | |
174 | /* this will need to be pushed down to the version, or even the source level | |
175 | * to allow differences between formats to be seamlessly managed | |
176 | * but for now: here is ok | |
177 | */ | |
178 | hash dirs; | |
3c054baf | 179 | String line = installed->getfirstfile (); |
8e9aa511 RC |
180 | |
181 | try_run_script ("/etc/preremove/", name); | |
3c054baf | 182 | while (line.size()) |
fa0c0d10 RC |
183 | { |
184 | dirs.add_subdirs (line); | |
185 | ||
1ac649ed | 186 | String d = cygpath (String ("/") + line); |
3c054baf | 187 | DWORD dw = GetFileAttributes (d.cstr_oneuse()); |
7e8fc33c RC |
188 | if (dw != INVALID_FILE_ATTRIBUTES |
189 | && !(dw & FILE_ATTRIBUTE_DIRECTORY)) | |
fa0c0d10 | 190 | { |
3c054baf RC |
191 | log (LOG_BABBLE, String("unlink ")+ d); |
192 | SetFileAttributes (d.cstr_oneuse(), dw & ~FILE_ATTRIBUTE_READONLY); | |
193 | DeleteFile (d.cstr_oneuse()); | |
edef4f57 CV |
194 | } |
195 | /* Check for Windows shortcut of same name. */ | |
3c054baf RC |
196 | d += ".lnk"; |
197 | dw = GetFileAttributes (d.cstr_oneuse()); | |
7e8fc33c RC |
198 | if (dw != INVALID_FILE_ATTRIBUTES |
199 | && !(dw & FILE_ATTRIBUTE_DIRECTORY)) | |
edef4f57 | 200 | { |
3c054baf | 201 | log (LOG_BABBLE, String("unlink ") + d); |
1ac649ed RC |
202 | SetFileAttributes (d.cstr_oneuse(), |
203 | dw & ~FILE_ATTRIBUTE_READONLY); | |
3c054baf | 204 | DeleteFile (d.cstr_oneuse()); |
fa0c0d10 RC |
205 | } |
206 | line = installed->getnextfile (); | |
207 | } | |
208 | installed->uninstall (); | |
209 | ||
210 | dirs.reverse_sort (); | |
211 | char *subdir = 0; | |
212 | while ((subdir = dirs.enumerate (subdir)) != 0) | |
213 | { | |
1ac649ed | 214 | String d = cygpath (String ("/") + subdir); |
3c054baf | 215 | if (RemoveDirectory (d.cstr_oneuse())) |
1ac649ed | 216 | log (LOG_BABBLE, String("rmdir ") + d); |
fa0c0d10 | 217 | } |
8e9aa511 | 218 | try_run_script ("/etc/postremove/", name); |
fa0c0d10 RC |
219 | } |
220 | installed = 0; | |
221 | } | |
bb849dbd RC |
222 | |
223 | ||
224 | void | |
225 | packagemeta::add_category (Category & cat) | |
226 | { | |
227 | /* add a new record for the package list */ | |
4fe323f9 RC |
228 | CategoryPackage & catpack = Categories.registerbykey (cat); |
229 | catpack.pkg = this; | |
bb849dbd RC |
230 | } |
231 | ||
3c054baf | 232 | String const |
df62e023 | 233 | packagemeta::SDesc () const |
bb849dbd | 234 | { |
7e8fc33c | 235 | for (size_t n = 1; n <= versions.number (); ++n) |
3c054baf | 236 | if (versions[n]->SDesc ().size()) |
bcf20115 | 237 | return versions[n]->SDesc (); |
076654e7 | 238 | return String(); |
bb849dbd | 239 | }; |
cbfc4215 RC |
240 | |
241 | /* Return an appropriate caption given the current action. */ | |
3c054baf | 242 | String |
cbfc4215 RC |
243 | packagemeta::action_caption () |
244 | { | |
245 | if (!desired && installed) | |
246 | return "Uninstall"; | |
247 | else if (!desired) | |
248 | return "Skip"; | |
249 | else if (desired == installed && desired->binpicked) | |
250 | { | |
251 | packagedb db; | |
252 | return db.task == PackageDB_Install ? "Reinstall" : "Retrieve"; | |
253 | } | |
254 | else if (desired == installed && desired->srcpicked) | |
255 | /* FIXME: Redo source should come up if the tarball is already present locally */ | |
256 | return "Source"; | |
257 | else if (desired == installed) /* and neither src nor bin */ | |
258 | return "Keep"; | |
259 | else | |
260 | return desired->Canonical_version (); | |
261 | } | |
262 | ||
263 | /* Set the next action given a current action. */ | |
264 | void | |
265 | packagemeta::set_action (packageversion * default_version) | |
266 | { | |
267 | /* actions are the following: | |
268 | ||
269 | for install modes (from net/local) | |
270 | for each version: | |
271 | install this version | |
272 | install the source for this version | |
273 | and a boolean flag - force install to allow reinstallation, or bypassing requirements | |
274 | globally: | |
275 | install the source for the current version. | |
276 | ||
277 | to uninstall a package, the desired version is set to NULL; | |
278 | ||
279 | for mirroring modes (download only) | |
280 | for each version | |
281 | download this version | |
282 | download source for this version | |
283 | ||
284 | these are represented by the following: | |
285 | the desired pointer in the packagemetadata indicated which version we are operating on. | |
286 | if we are operating on the installed version, reinstall is a valid option. | |
287 | for the selected version, forceinstall means Do an install no matter what, and | |
288 | srcpicked means download the source. | |
289 | ||
290 | The default action for any installed package is to install the 'curr version' | |
291 | if it is not already installed. | |
292 | ||
293 | The default action for any non-installed package is to do nothing. | |
294 | ||
295 | To achieve a no-op, set desired==installed, and if (installed) set forceinstall=0 and | |
296 | srcpicked = 0; | |
297 | ||
298 | Iteration through versions should follow the following rules: | |
299 | selected radio button (prev/curr/test) (show as reinstall if that is the | |
300 | current version) ->source only (only if the package is installed) ->oldest version....s | |
301 | kip version of radio button... | |
302 | newest version->uninstall->no-op->selected radio button. | |
303 | ||
304 | If any state cannot be set (ie because (say) no prev entry exists for a package | |
305 | simply progress to the next option. | |
306 | ||
307 | */ | |
308 | ||
309 | /* We were set to uninstall the package */ | |
310 | if (!desired && installed) | |
311 | { | |
312 | /* No-op - keep whatever we've got */ | |
313 | desired = installed; | |
314 | if (desired) | |
315 | { | |
316 | desired->binpicked = 0; | |
317 | desired->srcpicked = 0; | |
318 | } | |
319 | return; | |
320 | } | |
a828d772 RC |
321 | else if (desired == installed && |
322 | (!installed || | |
323 | // neither bin nor source are being installed | |
324 | (!(installed->binpicked || installed->srcpicked) && | |
325 | // bin or source are available | |
326 | ((installed->bin.sites.number() || desired->bin.Cached()) || | |
327 | (installed->src.sites.number() || desired->src.Cached())))) | |
328 | ) | |
cbfc4215 RC |
329 | /* Install the default trust version - this is a 'reinstall' for installed |
330 | * packages */ | |
331 | { | |
332 | desired = NULL; | |
333 | /* No-op */ | |
334 | desired = default_version; | |
335 | if (desired) | |
336 | { | |
a828d772 RC |
337 | if (desired->bin.sites.number() || desired->bin.Cached()) |
338 | desired->binpicked = 1; | |
339 | else | |
340 | desired->srcpicked = 1; | |
cbfc4215 RC |
341 | return; |
342 | } | |
343 | } | |
344 | /* are we currently on the radio button selection and installed */ | |
345 | if (desired == default_version && installed && | |
346 | (!desired || desired->binpicked) | |
347 | && (desired && | |
348 | (desired->src.Cached () || desired->src.sites.number ()))) | |
349 | { | |
350 | /* source only this file */ | |
351 | desired = installed; | |
352 | desired->binpicked = 0; | |
353 | desired->srcpicked = 1; | |
354 | return; | |
355 | } | |
356 | /* are we currently on source only or on the radio button but not installed */ | |
357 | else if ((desired == installed && installed | |
358 | && installed->srcpicked) || desired == default_version) | |
359 | { | |
360 | /* move onto the loop through versions */ | |
361 | desired = versions[1]; | |
362 | if (desired == default_version) | |
363 | desired = versions.number () > 1 ? versions[2] : NULL; | |
364 | if (desired) | |
365 | { | |
366 | desired->binpicked = 1; | |
367 | desired->srcpicked = 0; | |
368 | } | |
369 | return; | |
370 | } | |
371 | else | |
372 | { | |
373 | /* preserve the src tick box */ | |
374 | int source = desired->srcpicked; | |
375 | /* bump the version selected, skipping the radio button trust along the way */ | |
376 | size_t n; | |
7e8fc33c | 377 | for (n = 1; n <= versions.number () && desired != versions[n]; n++); |
cbfc4215 RC |
378 | /* n points at pkg->desired */ |
379 | n++; | |
380 | if (n <= versions.number ()) | |
381 | { | |
382 | if (default_version == versions[n]) | |
383 | n++; | |
384 | if (n <= versions.number ()) | |
385 | { | |
386 | desired = versions[n]; | |
a828d772 RC |
387 | if (desired->src.sites.number() || desired->src.Cached()) |
388 | desired->srcpicked = source; | |
389 | else | |
390 | desired->srcpicked = 0; | |
cbfc4215 RC |
391 | return; |
392 | } | |
393 | } | |
394 | /* went past the end - uninstall the package */ | |
395 | desired = NULL; | |
396 | } | |
397 | } | |
97647369 RC |
398 | |
399 | int | |
400 | packagemeta::set_requirements (trusts deftrust = TRUST_CURR, size_t depth = 0) | |
401 | { | |
402 | Dependency *dp; | |
403 | packagemeta *required; | |
404 | int changed = 0; | |
7e8fc33c | 405 | if (!desired || (desired != installed && !desired->binpicked)) |
97647369 RC |
406 | /* uninstall || source only */ |
407 | return 0; | |
408 | ||
409 | dp = desired->required; | |
410 | packagedb db; | |
411 | /* cheap test for too much recursion */ | |
412 | if (depth > 5) | |
413 | return 0; | |
414 | while (dp) | |
415 | { | |
416 | if ((required = db.packages.getbykey (dp->package)) == NULL) | |
7e8fc33c RC |
417 | { |
418 | dp = dp->next; | |
419 | changed++; | |
420 | continue; | |
421 | } | |
97647369 | 422 | if (!required->desired) |
7e8fc33c RC |
423 | { |
424 | /* it's set to uninstall */ | |
425 | required->set_action (required->trustp (deftrust)); | |
426 | } | |
97647369 | 427 | else if (required->desired != required->installed |
7e8fc33c RC |
428 | && !required->desired->binpicked) |
429 | { | |
430 | /* it's set to change to a different version source only */ | |
431 | required->desired->binpicked = 1; | |
432 | } | |
97647369 RC |
433 | /* does this requirement have requirements? */ |
434 | changed += required->set_requirements (deftrust, depth + 1); | |
435 | dp = dp->next; | |
436 | } | |
437 | return changed; | |
438 | } | |
7e8fc33c RC |
439 | |
440 | ||
441 | // Set a particular type of action. | |
442 | void | |
443 | packagemeta::set_action (_actions action, packageversion * default_version) | |
444 | { | |
445 | packagedb db; | |
446 | if (action == Default_action) | |
447 | { | |
448 | // XXX fix the list use to allow const ref usage. | |
449 | Category tempCategory("Misc"); | |
450 | if (installed | |
451 | || Categories.getbykey (db.categories.registerbykey ("Base")) | |
452 | || Categories.getbykey (tempCategory)) | |
453 | { | |
454 | desired = default_version; | |
455 | if (desired) | |
456 | { | |
457 | desired->binpicked = desired == installed ? 0 : 1; | |
458 | desired->srcpicked = 0; | |
459 | } | |
460 | } | |
461 | else | |
462 | desired = 0; | |
463 | return; | |
464 | } | |
465 | else if (action == Install_action) | |
466 | { | |
467 | desired = default_version; | |
468 | if (desired) | |
469 | { | |
470 | if (desired != installed) | |
ceff7035 RC |
471 | if (desired->bin.sites.number()) |
472 | { | |
473 | desired->binpicked = 1; | |
474 | desired->srcpicked = 0; | |
475 | } | |
476 | else | |
477 | { | |
478 | desired->binpicked = 0; | |
479 | desired->srcpicked = 1; | |
480 | } | |
7e8fc33c | 481 | else |
ceff7035 RC |
482 | { |
483 | desired->binpicked = 0; | |
484 | desired->srcpicked = 0; | |
485 | } | |
7e8fc33c RC |
486 | } |
487 | return; | |
488 | } | |
489 | else if (action == Reinstall_action) | |
490 | { | |
491 | desired = installed; | |
492 | if (desired) | |
493 | { | |
494 | desired->binpicked = 1; | |
495 | desired->srcpicked = 0; | |
496 | } | |
497 | } | |
498 | else if (action == Uninstall_action) | |
499 | { | |
500 | desired = 0; | |
501 | } | |
502 | } |