]>
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 RC |
45 | static const char *standard_dirs[] = { |
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", | |
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 | ||
7e8fc33c RC |
88 | const |
89 | packagemeta::_actions | |
90 | packagemeta::Default_action (0); | |
91 | const | |
92 | packagemeta::_actions | |
93 | packagemeta::Install_action (1); | |
94 | const | |
95 | packagemeta::_actions | |
96 | packagemeta::Reinstall_action (2); | |
97 | const | |
98 | packagemeta::_actions | |
99 | packagemeta::Uninstall_action (3); | |
100 | ||
101 | char const * | |
102 | packagemeta::_actions::caption () | |
103 | { | |
104 | switch (_value) | |
105 | { | |
106 | case 0: | |
107 | return "Default"; | |
108 | case 1: | |
109 | return "Install"; | |
110 | case 2: | |
111 | return "Reinstall"; | |
112 | case 3: | |
113 | return "Uninstall"; | |
114 | } | |
115 | // Pacify GCC: (all case options are checked above) | |
116 | return 0; | |
117 | } | |
118 | ||
119 | packagemeta::_actions & packagemeta::_actions::operator++ () | |
120 | { | |
121 | ++_value; | |
122 | if (_value > 3) | |
123 | _value = 0; | |
124 | return *this; | |
125 | } | |
126 | ||
7939f6d1 | 127 | void |
fa0c0d10 | 128 | packagemeta::add_version (packageversion & thepkg) |
7939f6d1 | 129 | { |
bb849dbd | 130 | versions.registerbyobject (thepkg); |
7939f6d1 RC |
131 | } |
132 | ||
133 | /* assumption: package thepkg is already in the metadata list. */ | |
134 | void | |
fa0c0d10 | 135 | packagemeta::set_installed (packageversion & thepkg) |
7939f6d1 | 136 | { |
bb849dbd RC |
137 | packageversion *temp = versions.getbykey (thepkg.key); |
138 | if (temp == &thepkg) | |
139 | installed = &thepkg; | |
7939f6d1 | 140 | } |
fa0c0d10 RC |
141 | |
142 | /* uninstall a package if it's installed */ | |
143 | void | |
144 | packagemeta::uninstall () | |
145 | { | |
146 | if (installed) | |
147 | { | |
148 | /* this will need to be pushed down to the version, or even the source level | |
149 | * to allow differences between formats to be seamlessly managed | |
150 | * but for now: here is ok | |
151 | */ | |
152 | hash dirs; | |
3c054baf | 153 | String line = installed->getfirstfile (); |
8e9aa511 RC |
154 | |
155 | try_run_script ("/etc/preremove/", name); | |
3c054baf | 156 | while (line.size()) |
fa0c0d10 RC |
157 | { |
158 | dirs.add_subdirs (line); | |
159 | ||
1ac649ed | 160 | String d = cygpath (String ("/") + line); |
3c054baf | 161 | DWORD dw = GetFileAttributes (d.cstr_oneuse()); |
7e8fc33c RC |
162 | if (dw != INVALID_FILE_ATTRIBUTES |
163 | && !(dw & FILE_ATTRIBUTE_DIRECTORY)) | |
fa0c0d10 | 164 | { |
3c054baf RC |
165 | log (LOG_BABBLE, String("unlink ")+ d); |
166 | SetFileAttributes (d.cstr_oneuse(), dw & ~FILE_ATTRIBUTE_READONLY); | |
167 | DeleteFile (d.cstr_oneuse()); | |
edef4f57 CV |
168 | } |
169 | /* Check for Windows shortcut of same name. */ | |
3c054baf RC |
170 | d += ".lnk"; |
171 | dw = GetFileAttributes (d.cstr_oneuse()); | |
7e8fc33c RC |
172 | if (dw != INVALID_FILE_ATTRIBUTES |
173 | && !(dw & FILE_ATTRIBUTE_DIRECTORY)) | |
edef4f57 | 174 | { |
3c054baf | 175 | log (LOG_BABBLE, String("unlink ") + d); |
1ac649ed RC |
176 | SetFileAttributes (d.cstr_oneuse(), |
177 | dw & ~FILE_ATTRIBUTE_READONLY); | |
3c054baf | 178 | DeleteFile (d.cstr_oneuse()); |
fa0c0d10 RC |
179 | } |
180 | line = installed->getnextfile (); | |
181 | } | |
182 | installed->uninstall (); | |
183 | ||
184 | dirs.reverse_sort (); | |
185 | char *subdir = 0; | |
186 | while ((subdir = dirs.enumerate (subdir)) != 0) | |
187 | { | |
1ac649ed | 188 | String d = cygpath (String ("/") + subdir); |
3c054baf | 189 | if (RemoveDirectory (d.cstr_oneuse())) |
1ac649ed | 190 | log (LOG_BABBLE, String("rmdir ") + d); |
fa0c0d10 | 191 | } |
8e9aa511 | 192 | try_run_script ("/etc/postremove/", name); |
fa0c0d10 RC |
193 | } |
194 | installed = 0; | |
195 | } | |
bb849dbd RC |
196 | |
197 | ||
198 | void | |
199 | packagemeta::add_category (Category & cat) | |
200 | { | |
201 | /* add a new record for the package list */ | |
4fe323f9 RC |
202 | CategoryPackage & catpack = Categories.registerbykey (cat); |
203 | catpack.pkg = this; | |
bb849dbd RC |
204 | } |
205 | ||
3c054baf | 206 | String const |
df62e023 | 207 | packagemeta::SDesc () const |
bb849dbd | 208 | { |
7e8fc33c | 209 | for (size_t n = 1; n <= versions.number (); ++n) |
3c054baf | 210 | if (versions[n]->SDesc ().size()) |
bcf20115 RC |
211 | return versions[n]->SDesc (); |
212 | return NULL; | |
bb849dbd | 213 | }; |
cbfc4215 RC |
214 | |
215 | /* Return an appropriate caption given the current action. */ | |
3c054baf | 216 | String |
cbfc4215 RC |
217 | packagemeta::action_caption () |
218 | { | |
219 | if (!desired && installed) | |
220 | return "Uninstall"; | |
221 | else if (!desired) | |
222 | return "Skip"; | |
223 | else if (desired == installed && desired->binpicked) | |
224 | { | |
225 | packagedb db; | |
226 | return db.task == PackageDB_Install ? "Reinstall" : "Retrieve"; | |
227 | } | |
228 | else if (desired == installed && desired->srcpicked) | |
229 | /* FIXME: Redo source should come up if the tarball is already present locally */ | |
230 | return "Source"; | |
231 | else if (desired == installed) /* and neither src nor bin */ | |
232 | return "Keep"; | |
233 | else | |
234 | return desired->Canonical_version (); | |
235 | } | |
236 | ||
237 | /* Set the next action given a current action. */ | |
238 | void | |
239 | packagemeta::set_action (packageversion * default_version) | |
240 | { | |
241 | /* actions are the following: | |
242 | ||
243 | for install modes (from net/local) | |
244 | for each version: | |
245 | install this version | |
246 | install the source for this version | |
247 | and a boolean flag - force install to allow reinstallation, or bypassing requirements | |
248 | globally: | |
249 | install the source for the current version. | |
250 | ||
251 | to uninstall a package, the desired version is set to NULL; | |
252 | ||
253 | for mirroring modes (download only) | |
254 | for each version | |
255 | download this version | |
256 | download source for this version | |
257 | ||
258 | these are represented by the following: | |
259 | the desired pointer in the packagemetadata indicated which version we are operating on. | |
260 | if we are operating on the installed version, reinstall is a valid option. | |
261 | for the selected version, forceinstall means Do an install no matter what, and | |
262 | srcpicked means download the source. | |
263 | ||
264 | The default action for any installed package is to install the 'curr version' | |
265 | if it is not already installed. | |
266 | ||
267 | The default action for any non-installed package is to do nothing. | |
268 | ||
269 | To achieve a no-op, set desired==installed, and if (installed) set forceinstall=0 and | |
270 | srcpicked = 0; | |
271 | ||
272 | Iteration through versions should follow the following rules: | |
273 | selected radio button (prev/curr/test) (show as reinstall if that is the | |
274 | current version) ->source only (only if the package is installed) ->oldest version....s | |
275 | kip version of radio button... | |
276 | newest version->uninstall->no-op->selected radio button. | |
277 | ||
278 | If any state cannot be set (ie because (say) no prev entry exists for a package | |
279 | simply progress to the next option. | |
280 | ||
281 | */ | |
282 | ||
283 | /* We were set to uninstall the package */ | |
284 | if (!desired && installed) | |
285 | { | |
286 | /* No-op - keep whatever we've got */ | |
287 | desired = installed; | |
288 | if (desired) | |
289 | { | |
290 | desired->binpicked = 0; | |
291 | desired->srcpicked = 0; | |
292 | } | |
293 | return; | |
294 | } | |
295 | else if (desired == installed | |
7e8fc33c | 296 | && (!installed || !(installed->binpicked || installed->srcpicked))) |
cbfc4215 RC |
297 | /* Install the default trust version - this is a 'reinstall' for installed |
298 | * packages */ | |
299 | { | |
300 | desired = NULL; | |
301 | /* No-op */ | |
302 | desired = default_version; | |
303 | if (desired) | |
304 | { | |
305 | desired->binpicked = 1; | |
306 | return; | |
307 | } | |
308 | } | |
309 | /* are we currently on the radio button selection and installed */ | |
310 | if (desired == default_version && installed && | |
311 | (!desired || desired->binpicked) | |
312 | && (desired && | |
313 | (desired->src.Cached () || desired->src.sites.number ()))) | |
314 | { | |
315 | /* source only this file */ | |
316 | desired = installed; | |
317 | desired->binpicked = 0; | |
318 | desired->srcpicked = 1; | |
319 | return; | |
320 | } | |
321 | /* are we currently on source only or on the radio button but not installed */ | |
322 | else if ((desired == installed && installed | |
323 | && installed->srcpicked) || desired == default_version) | |
324 | { | |
325 | /* move onto the loop through versions */ | |
326 | desired = versions[1]; | |
327 | if (desired == default_version) | |
328 | desired = versions.number () > 1 ? versions[2] : NULL; | |
329 | if (desired) | |
330 | { | |
331 | desired->binpicked = 1; | |
332 | desired->srcpicked = 0; | |
333 | } | |
334 | return; | |
335 | } | |
336 | else | |
337 | { | |
338 | /* preserve the src tick box */ | |
339 | int source = desired->srcpicked; | |
340 | /* bump the version selected, skipping the radio button trust along the way */ | |
341 | size_t n; | |
7e8fc33c | 342 | for (n = 1; n <= versions.number () && desired != versions[n]; n++); |
cbfc4215 RC |
343 | /* n points at pkg->desired */ |
344 | n++; | |
345 | if (n <= versions.number ()) | |
346 | { | |
347 | if (default_version == versions[n]) | |
348 | n++; | |
349 | if (n <= versions.number ()) | |
350 | { | |
351 | desired = versions[n]; | |
352 | desired->srcpicked = source; | |
353 | return; | |
354 | } | |
355 | } | |
356 | /* went past the end - uninstall the package */ | |
357 | desired = NULL; | |
358 | } | |
359 | } | |
97647369 RC |
360 | |
361 | int | |
362 | packagemeta::set_requirements (trusts deftrust = TRUST_CURR, size_t depth = 0) | |
363 | { | |
364 | Dependency *dp; | |
365 | packagemeta *required; | |
366 | int changed = 0; | |
7e8fc33c | 367 | if (!desired || (desired != installed && !desired->binpicked)) |
97647369 RC |
368 | /* uninstall || source only */ |
369 | return 0; | |
370 | ||
371 | dp = desired->required; | |
372 | packagedb db; | |
373 | /* cheap test for too much recursion */ | |
374 | if (depth > 5) | |
375 | return 0; | |
376 | while (dp) | |
377 | { | |
378 | if ((required = db.packages.getbykey (dp->package)) == NULL) | |
7e8fc33c RC |
379 | { |
380 | dp = dp->next; | |
381 | changed++; | |
382 | continue; | |
383 | } | |
97647369 | 384 | if (!required->desired) |
7e8fc33c RC |
385 | { |
386 | /* it's set to uninstall */ | |
387 | required->set_action (required->trustp (deftrust)); | |
388 | } | |
97647369 | 389 | else if (required->desired != required->installed |
7e8fc33c RC |
390 | && !required->desired->binpicked) |
391 | { | |
392 | /* it's set to change to a different version source only */ | |
393 | required->desired->binpicked = 1; | |
394 | } | |
97647369 RC |
395 | /* does this requirement have requirements? */ |
396 | changed += required->set_requirements (deftrust, depth + 1); | |
397 | dp = dp->next; | |
398 | } | |
399 | return changed; | |
400 | } | |
7e8fc33c RC |
401 | |
402 | ||
403 | // Set a particular type of action. | |
404 | void | |
405 | packagemeta::set_action (_actions action, packageversion * default_version) | |
406 | { | |
407 | packagedb db; | |
408 | if (action == Default_action) | |
409 | { | |
410 | // XXX fix the list use to allow const ref usage. | |
411 | Category tempCategory("Misc"); | |
412 | if (installed | |
413 | || Categories.getbykey (db.categories.registerbykey ("Base")) | |
414 | || Categories.getbykey (tempCategory)) | |
415 | { | |
416 | desired = default_version; | |
417 | if (desired) | |
418 | { | |
419 | desired->binpicked = desired == installed ? 0 : 1; | |
420 | desired->srcpicked = 0; | |
421 | } | |
422 | } | |
423 | else | |
424 | desired = 0; | |
425 | return; | |
426 | } | |
427 | else if (action == Install_action) | |
428 | { | |
429 | desired = default_version; | |
430 | if (desired) | |
431 | { | |
432 | if (desired != installed) | |
433 | desired->binpicked = 1; | |
434 | else | |
435 | desired->binpicked = 0; | |
436 | desired->srcpicked = 0; | |
437 | } | |
438 | return; | |
439 | } | |
440 | else if (action == Reinstall_action) | |
441 | { | |
442 | desired = installed; | |
443 | if (desired) | |
444 | { | |
445 | desired->binpicked = 1; | |
446 | desired->srcpicked = 0; | |
447 | } | |
448 | } | |
449 | else if (action == Uninstall_action) | |
450 | { | |
451 | desired = 0; | |
452 | } | |
453 | } |