]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - release/sysinstall/index.c
This commit was generated by cvs2svn to compensate for changes in r53654,
[FreeBSD/FreeBSD.git] / release / sysinstall / index.c
1 /*
2  * The new sysinstall program.
3  *
4  * This is probably the last program in the `sysinstall' line - the next
5  * generation being essentially a complete rewrite.
6  *
7  * $FreeBSD$
8  *
9  * Copyright (c) 1995
10  *      Jordan Hubbard.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer,
17  *    verbatim and that no modifications are made prior to this
18  *    point in the file.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <ncurses.h>
42 #include <dialog.h>
43 #include "sysinstall.h"
44
45 /* Macros and magic values */
46 #define MAX_MENU        12
47 #define _MAX_DESC       55
48
49 /* A structure holding the root, top and plist pointer at once */
50 struct ListPtrs
51 {
52     PkgNodePtr root;    /* root of tree */
53     PkgNodePtr top;     /* part of tree we handle */
54     PkgNodePtr plist;   /* list of selected packages */
55 };
56 typedef struct ListPtrs* ListPtrsPtr;
57
58 static void     index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie);
59
60 /* Shared between index_initialize() and the various clients of it */
61 PkgNode Top, Plist;
62
63 /* Smarter strdup */
64 inline char *
65 _strdup(char *ptr)
66 {
67     return ptr ? strdup(ptr) : NULL;
68 }
69
70 static char *descrs[] = {
71     "Package Selection", "To mark a package, move to it and press SPACE.  If the package is\n"
72     "already marked, it will be unmarked or deleted (if installed).\n"
73     "Items marked with a `D' are dependencies which will be auto-loaded.\n"
74     "To search for a package by name, press ESC.  To select a category,\n"
75     "press RETURN.  NOTE:  The All category selection creates a very large\n"
76     "submenu!  If you select it, please be patient while it comes up.",
77     "Package Targets", "These are the packages you've selected for extraction.\n\n"
78     "If you're sure of these choices, select OK.\n"
79     "If not, select Cancel to go back to the package selection menu.\n",
80     "All", "All available packages in all categories.",
81     "afterstep", "Ports to support the AfterStep window manager.",
82     "applications", "User application software.",
83     "astro", "Applications related to astronomy.",
84     "archivers", "Utilities for archiving and unarchiving data.",
85     "audio", "Audio utilities - most require a supported sound card.",
86     "biology", "Software related to biology.",
87     "benchmarks", "Utilities for measuring system performance.",
88     "cad", "Computer Aided Design utilities.",
89     "chinese", "Ported software for the Chinese market.",
90     "comms", "Communications utilities.",
91     "converters", "Format conversion utilities.",
92     "databases", "Database software.",
93     "devel", "Software development utilities and libraries.",
94     "deskutils", "Various Desktop utilities.",
95     "documentation", "Document preparation utilities.",
96     "editors", "Common text editors.",
97     "elisp", "Things related to Emacs Lisp.",
98     "elisp", "Emacs lisp ports.",
99     "emulators", "Utilities for emulating other OS types.",
100     "ftp", "FTP client and server utilities.",
101     "games", "Various and sundry amusements.",
102     "german", "Ported software for Germanic countries.",
103     "graphics", "Graphics libraries and utilities.",
104     "gnome", "Components of the Gnome Desktop environment.",
105     "irc", "Internet Relay Chat utilities.",
106     "japanese", "Ported software for the Japanese market.",
107     "java", "Java language support.",
108     "kde", "Software for the K Desktop Environment.",
109     "korean", "Ported software for the Korean market.",
110     "lang", "Computer languages.",
111     "languages", "Computer languages.",
112     "libraries", "Software development libraries.",
113     "mail", "Electronic mail packages and utilities.",
114     "math", "Mathematical computation software.",
115     "mbone", "Applications and utilities for the MBONE.",
116     "misc", "Miscellaneous utilities.",
117     "net", "Networking utilities.",
118     "news", "USENET News support software.",
119     "numeric", "Mathematical computation software.",
120     "offix", "An office automation suite of sorts.",
121     "orphans", "Packages without a home elsewhere.",
122     "palm", "Software support for the 3Com Palm Pilot(tm) series.",
123     "pilot", "Software support for the 3Com Palm Pilot(tm) series.",
124     "perl5", "Utilities/modules for the PERL5 language.",
125     "plan9", "Software from the Plan9 operating system.",
126     "print", "Utilities for dealing with printing.",
127     "printing", "Utilities for dealing with printing.",
128     "programming", "Software development utilities and libraries.",
129     "python", "Software related to the Python language.",
130     "russian", "Ported software for the Russian market.",
131     "security", "System security software.",
132     "shells", "Various shells (tcsh, bash, etc).",
133     "sysutils", "Various system utilities.",
134     "textproc", "Text processing/search utilities.",
135     "tcl75", "TCL v7.5 and packages that depend on it.",
136     "tcl76", "TCL v7.6 and packages that depend on it.",
137     "tcl80", "TCL v8.0 and packages that depend on it.",
138     "tcl80", "TCL v8.0 and packages that depend on it.",
139     "tcl82", "TCL v8.2 and packages that depend on it.",
140     "tk41", "Tk4.1 and packages that depend on it.",
141     "tk42", "Tk4.2 and packages that depend on it.",
142     "tk80", "Tk8.0 and packages that depend on it.",
143     "tk81", "Tk8.1 and packages that depend on it.",
144     "tk82", "Tk8.2 and packages that depend on it.",
145     "tkstep80", "tkstep wm and packages that depend on it.",
146     "troff", "TROFF text formatting utilities.",
147     "vietnamese", "Ported software for the Vietnamese market.",
148     "windowmaker", "Ports to support the WindowMaker window manager.",
149     "www", "WEB utilities (browers, HTTP servers, etc).",
150     "x11", "X Window System based utilities.",
151     "x11-clocks", "X Window System based clocks.",
152     "x11-fm", "X Window System based file managers.",
153     "x11-fonts", "X Window System fonts and font utilities.",
154     "x11-servers", "X Window System servers.",
155     "x11-toolkits", "X Window System based development toolkits.",
156     "x11-wm", "X Window System window managers.",
157     NULL, NULL,
158 };
159
160 static char *
161 fetch_desc(char *name)
162 {
163     int i;
164
165     for (i = 0; descrs[i]; i += 2) {
166         if (!strcmp(descrs[i], name))
167             return descrs[i + 1];
168     }
169     return "No description provided";
170 }
171
172 static PkgNodePtr
173 new_pkg_node(char *name, node_type type)
174 {
175     PkgNodePtr tmp = safe_malloc(sizeof(PkgNode));
176
177     tmp->name = _strdup(name);
178     tmp->type = type;
179     return tmp;
180 }
181
182 static char *
183 strip(char *buf)
184 {
185     int i;
186
187     for (i = 0; buf[i]; i++)
188         if (buf[i] == '\t' || buf[i] == '\n')
189             buf[i] = ' ';
190     return buf;
191 }
192
193 static IndexEntryPtr
194 new_index(char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *deps)
195 {
196     IndexEntryPtr tmp = safe_malloc(sizeof(IndexEntry));
197
198     tmp->name =         _strdup(name);
199     tmp->path =         _strdup(pathto);
200     tmp->prefix =       _strdup(prefix);
201     tmp->comment =      _strdup(comment);
202     tmp->descrfile =    strip(_strdup(descr));
203     tmp->maintainer =   _strdup(maint);
204     tmp->deps =         _strdup(deps);
205     tmp->depc =         0;
206     tmp->installed =    package_exists(name);
207     return tmp;
208 }
209
210 static void
211 index_register(PkgNodePtr top, char *where, IndexEntryPtr ptr)
212 {
213     PkgNodePtr p, q;
214
215     for (q = NULL, p = top->kids; p; p = p->next) {
216         if (!strcmp(p->name, where)) {
217             q = p;
218             break;
219         }
220     }
221     if (!p) {
222         /* Add new category */
223         q = new_pkg_node(where, PLACE);
224         q->desc = fetch_desc(where);
225         q->next = top->kids;
226         top->kids = q;
227     }
228     p = new_pkg_node(ptr->name, PACKAGE);
229     p->desc = ptr->comment;
230     p->data = ptr;
231     p->next = q->kids;
232     q->kids = p;
233 }
234
235 static int
236 copy_to_sep(char *to, char *from, int sep)
237 {
238     char *tok;
239
240     tok = strchr(from, sep);
241     if (!tok) {
242         *to = '\0';
243         return 0;
244     }
245     *tok = '\0';
246     strcpy(to, from);
247     return tok + 1 - from;
248 }
249
250 static int
251 readline(FILE *fp, char *buf, int max)
252 {
253     int rv, i = 0;
254     char ch;
255
256     while ((rv = fread(&ch, 1, 1, fp)) == 1 && ch != '\n' && i < max)
257         buf[i++] = ch;
258     if (i < max)
259         buf[i] = '\0';
260     return rv;
261 }
262
263 int
264 index_parse(FILE *fp, char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *cats, char *rdeps)
265 {
266     char line[1024];
267     char junk[256];
268     char *cp;
269     int i;
270
271     i = readline(fp, line, 1024);
272     if (i <= 0)
273         return EOF;
274     cp = line;
275     cp += copy_to_sep(name, cp, '|');
276     cp += copy_to_sep(pathto, cp, '|');
277     cp += copy_to_sep(prefix, cp, '|');
278     cp += copy_to_sep(comment, cp, '|');
279     cp += copy_to_sep(descr, cp, '|');
280     cp += copy_to_sep(maint, cp, '|');
281     cp += copy_to_sep(cats, cp, '|');
282     cp += copy_to_sep(junk, cp, '|');   /* build deps - not used */
283     if (index(cp, '|'))
284         copy_to_sep(rdeps, cp, '|');
285     else
286         strncpy(rdeps, cp, 510);
287     return 0;
288 }
289
290 int
291 index_read(FILE *fp, PkgNodePtr papa)
292 {
293     char name[127], pathto[255], prefix[255], comment[255], descr[127], maint[127], cats[511], deps[511];
294     PkgNodePtr i;
295
296     while (index_parse(fp, name, pathto, prefix, comment, descr, maint, cats, deps) != EOF) {
297         char *cp, *cp2, tmp[511];
298         IndexEntryPtr idx;
299
300         idx = new_index(name, pathto, prefix, comment, descr, maint, deps);
301         /* For now, we only add things to menus if they're in categories.  Keywords are ignored */
302         for (cp = strcpy(tmp, cats); (cp2 = strchr(cp, ' ')) != NULL; cp = cp2 + 1) {
303             *cp2 = '\0';
304             index_register(papa, cp, idx);
305         }
306         index_register(papa, cp, idx);
307
308         /* Add to special "All" category */
309         index_register(papa, "All", idx);
310     }
311
312     /* Adjust dependency counts */
313     for (i = papa->kids; i != NULL; i = i->next)
314         if (strcmp(i->name, "All") == 0)
315             break;
316     for (i = i->kids; i != NULL; i = i->next)
317         if (((IndexEntryPtr)i->data)->installed)
318             index_recorddeps(TRUE, papa, i->data);
319
320     return 0;
321 }
322
323 void
324 index_init(PkgNodePtr top, PkgNodePtr plist)
325 {
326     if (top) {
327         top->next = top->kids = NULL;
328         top->name = "Package Selection";
329         top->type = PLACE;
330         top->desc = fetch_desc(top->name);
331         top->data = NULL;
332     }
333     if (plist) {
334         plist->next = plist->kids = NULL;
335         plist->name = "Package Targets";
336         plist->type = PLACE;
337         plist->desc = fetch_desc(plist->name);
338         plist->data = NULL;
339     }
340 }
341
342 void
343 index_print(PkgNodePtr top, int level)
344 {
345     int i;
346
347     while (top) {
348         for (i = 0; i < level; i++) putchar('\t');
349         printf("name [%s]: %s\n", top->type == PLACE ? "place" : "package", top->name);
350         for (i = 0; i < level; i++) putchar('\t');
351         printf("desc: %s\n", top->desc);
352         if (top->kids)
353             index_print(top->kids, level + 1);
354         top = top->next;
355     }
356 }
357
358 /* Swap one node for another */
359 static void
360 swap_nodes(PkgNodePtr a, PkgNodePtr b)
361 {
362     PkgNode tmp;
363
364     tmp = *a;
365     *a = *b;
366     a->next = tmp.next;
367     tmp.next = b->next;
368     *b = tmp;
369 }
370
371 /* Use a disgustingly simplistic bubble sort to put our lists in order */
372 void
373 index_sort(PkgNodePtr top)
374 {
375     PkgNodePtr p, q;
376
377     /* Sort everything at the top level */
378     for (p = top->kids; p; p = p->next) {
379         for (q = top->kids; q; q = q->next) {
380             if (q->next && strcmp(q->name, q->next->name) > 0)
381                 swap_nodes(q, q->next);
382         }
383     }
384
385     /* Now sub-sort everything n levels down */    
386     for (p = top->kids; p; p = p->next) {
387         if (p->kids)
388             index_sort(p);
389     }
390 }
391
392 /* Delete an entry out of the list it's in (only the plist, at present) */
393 void
394 index_delete(PkgNodePtr n)
395 {
396     if (n->next) {
397         PkgNodePtr p = n->next;
398
399         *n = *(n->next);
400         safe_free(p);
401     }
402     else /* Kludgy end sentinal */
403         n->name = NULL;
404 }
405
406 /*
407  * Search for a given node by name, returning the category in if
408  * tp is non-NULL.
409  */
410 PkgNodePtr
411 index_search(PkgNodePtr top, char *str, PkgNodePtr *tp)
412 {
413     PkgNodePtr p, sp;
414
415     for (p = top->kids; p && p->name; p = p->next) {
416         if (p->type == PACKAGE) {
417             /* If tp == NULL, we're looking for an exact package match */
418             if (!tp && !strcmp(p->name, str))
419                 return p;
420
421             /* If tp, we're looking for both a package and a pointer to the place it's in */
422             if (tp && !strncmp(p->name, str, strlen(str))) {
423                 *tp = top;
424                 return p;
425             }
426         }
427         else if (p->kids) {
428             /* The usual recursion-out-of-laziness ploy */
429             if ((sp = index_search(p, str, tp)) != NULL)
430                 return sp;
431         }
432     }
433     if (p && !p->name)
434         p = NULL;
435     return p;
436 }
437
438 int
439 pkg_checked(dialogMenuItem *self)
440 {
441     ListPtrsPtr lists = (ListPtrsPtr)self->aux;
442     PkgNodePtr kp = self->data, plist = lists->plist;
443     int i;
444
445     i = index_search(plist, kp->name, NULL) ? TRUE : FALSE;
446     if (kp->type == PACKAGE && plist) {
447         IndexEntryPtr ie = kp->data;
448         int markD, markX;
449
450         markD = ie->depc > 0; /* needed as dependency */
451         markX = i || ie->installed; /* selected or installed */
452         self->mark = markX ? 'X' : 'D';
453         return markD || markX;
454     } else
455         return FALSE;
456 }
457
458 int
459 pkg_fire(dialogMenuItem *self)
460 {
461     int ret;
462     ListPtrsPtr lists = (ListPtrsPtr)self->aux;
463     PkgNodePtr sp, kp = self->data, plist = lists->plist;
464
465     if (!plist)
466         ret = DITEM_FAILURE;
467     else if (kp->type == PACKAGE) {
468         IndexEntryPtr ie = kp->data;
469
470         sp = index_search(plist, kp->name, NULL);
471         /* Not already selected? */
472         if (!sp) {
473             if (!ie->installed) {
474                 PkgNodePtr np = (PkgNodePtr)safe_malloc(sizeof(PkgNode));
475
476                 *np = *kp;
477                 np->next = plist->kids;
478                 plist->kids = np;
479                 index_recorddeps(TRUE, lists->root, ie);
480                 msgInfo("Added %s to selection list", kp->name);
481             }
482             else if (ie->depc == 0) {
483                 WINDOW *save = savescr();
484
485                 if (!msgYesNo("Do you really want to delete %s from the system?", kp->name)) {
486                     if (vsystem("pkg_delete %s %s", isDebug() ? "-v" : "", kp->name)) {
487                         msgConfirm("Warning:  pkg_delete of %s failed.\n  Check debug output for details.", kp->name);
488                     }
489                     else {
490                         ie->installed = 0;
491                         index_recorddeps(FALSE, lists->root, ie);
492                     }
493                 }
494                 restorescr(save);
495             }
496             else
497                 msgConfirm("Warning: Package %s is needed by\n  %d other installed package%s.",
498                            kp->name, ie->depc, (ie->depc != 1) ? "s" : "");
499         }
500         else {
501             index_recorddeps(FALSE, lists->root, ie);
502             msgInfo("Removed %s from selection list", kp->name);
503             index_delete(sp);
504         }
505         ret = DITEM_SUCCESS;
506         /* Mark menu for redraw if we had dependencies */
507         if (strlen(ie->deps) > 0)
508             ret |= DITEM_REDRAW;
509     }
510     else {      /* Not a package, must be a directory */
511         int p, s;
512                     
513         p = s = 0;
514         index_menu(lists->root, kp, plist, &p, &s);
515         ret = DITEM_SUCCESS | DITEM_CONTINUE;
516     }
517     return ret;
518 }
519
520 void
521 pkg_selected(dialogMenuItem *self, int is_selected)
522 {
523     PkgNodePtr kp = self->data;
524
525     if (!is_selected || kp->type != PACKAGE)
526         return;
527     msgInfo(kp->desc);
528 }
529
530 int
531 index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll)
532 {
533     struct ListPtrs lists;
534     int n, rval, maxname;
535     int curr, max;
536     PkgNodePtr kp;
537     dialogMenuItem *nitems;
538     Boolean hasPackages;
539     WINDOW *w;
540
541     lists.root = root;
542     lists.top = top;
543     lists.plist = plist;
544
545     hasPackages = FALSE;
546     nitems = NULL;
547
548     w = savescr();
549     n = maxname = 0;
550     /* Figure out if this menu is full of "leaves" or "branches" */
551     for (kp = top->kids; kp && kp->name; kp = kp->next) {
552         int len;
553
554         ++n;
555         if (kp->type == PACKAGE && plist) {
556             hasPackages = TRUE;
557             if ((len = strlen(kp->name)) > maxname)
558                 maxname = len;
559         }
560     }
561     if (!n && plist) {
562         msgConfirm("The %s menu is empty.", top->name);
563         restorescr(w);
564         return DITEM_LEAVE_MENU;
565     }
566
567     while (1) {
568         n = 0;
569         curr = max = 0;
570         use_helpline(NULL);
571         use_helpfile(NULL);
572         kp = top->kids;
573         if (!hasPackages && plist) {
574             nitems = item_add(nitems, "OK", NULL, NULL, NULL, NULL, NULL, 0, &curr, &max);
575             nitems = item_add(nitems, "Install", NULL, NULL, NULL, NULL, NULL, 0, &curr, &max);
576         }
577         while (kp && kp->name) {
578             char buf[256];
579             IndexEntryPtr ie = kp->data;
580
581             /* Brutally adjust description to fit in menu */
582             if (kp->type == PACKAGE)
583                 snprintf(buf, sizeof buf, "[%s]", ie->path ? ie->path : "External vendor");
584             else
585                 SAFE_STRCPY(buf, kp->desc);
586             if (strlen(buf) > (_MAX_DESC - maxname))
587                 buf[_MAX_DESC - maxname] = '\0';
588             nitems = item_add(nitems, kp->name, buf, pkg_checked, pkg_fire, pkg_selected, kp, (int)&lists, &curr, &max);
589             ++n;
590             kp = kp->next;
591         }
592         /* NULL delimiter so item_free() knows when to stop later */
593         nitems = item_add(nitems, NULL, NULL, NULL, NULL, NULL, NULL, 0, &curr, &max);
594
595 recycle:
596         dialog_clear_norefresh();
597         if (hasPackages)
598             rval = dialog_checklist(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems, NULL);
599         else
600             rval = dialog_menu(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems + (plist ? 2 : 0), (char *)plist, pos, scroll);
601         if (rval == -1 && plist) {
602             static char *cp;
603             PkgNodePtr menu;
604
605             /* Search */
606             if ((cp = msgGetInput(cp, "Search by package name.  Please enter search string:")) != NULL) {
607                 PkgNodePtr p = index_search(top, cp, &menu);
608
609                 if (p) {
610                     int pos, scroll;
611
612                     /* These need to be set to point at the found item, actually.  Hmmm! */
613                     pos = scroll = 0;
614                     index_menu(root, menu, plist, &pos, &scroll);
615                 }
616                 else
617                     msgConfirm("Search string: %s yielded no hits.", cp);
618             }
619             goto recycle;
620         }
621         items_free(nitems, &curr, &max);
622         restorescr(w);
623         return rval ? DITEM_FAILURE : DITEM_SUCCESS;
624     }
625 }
626
627 int
628 index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended)
629 {
630     int status = DITEM_SUCCESS;
631     PkgNodePtr tmp2;
632     IndexEntryPtr id = who->data;
633
634     if (id && id->deps && strlen(id->deps)) {
635         char t[1024], *cp, *cp2;
636
637         SAFE_STRCPY(t, id->deps);
638         cp = t;
639         while (cp && DITEM_STATUS(status) == DITEM_SUCCESS) {
640             if ((cp2 = index(cp, ' ')) != NULL)
641                 *cp2 = '\0';
642             if ((tmp2 = index_search(top, cp, NULL)) != NULL) {
643                 status = index_extract(dev, top, tmp2, TRUE);
644                 if (DITEM_STATUS(status) != DITEM_SUCCESS) {
645                     if (variable_get(VAR_NO_CONFIRM))
646                         msgNotify("Loading of dependant package %s failed", cp);
647                     else
648                         msgConfirm("Loading of dependant package %s failed", cp);
649                 }
650             }
651             else if (!package_exists(cp)) {
652                 if (variable_get(VAR_NO_CONFIRM))
653                     msgNotify("Warning: %s is a required package but was not found.", cp);
654                 else
655                     msgConfirm("Warning: %s is a required package but was not found.", cp);
656             }
657             if (cp2)
658                 cp = cp2 + 1;
659             else
660                 cp = NULL;
661         }
662     }
663     /* Done with the deps?  Load the real m'coy */
664     if (DITEM_STATUS(status) == DITEM_SUCCESS) {
665         status = package_extract(dev, who->name, depended);
666         if (DITEM_STATUS(status) == DITEM_SUCCESS)
667             id->installed = 1;
668     }
669     return status;
670 }
671
672 static void
673 index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie)
674 {
675    char depends[1024], *space, *todo;
676    PkgNodePtr found;
677    IndexEntryPtr found_ie;
678
679    SAFE_STRCPY(depends, ie->deps);
680    for (todo = depends; todo != NULL; ) {
681       space = index(todo, ' ');
682       if (space != NULL)
683          *space = '\0';
684
685       if (strlen(todo) > 0) { /* only non-empty dependencies */
686           found = index_search(root, todo, NULL);
687           if (found != NULL) {
688               found_ie = found->data;
689               if (add)
690                   ++found_ie->depc;
691               else
692                   --found_ie->depc;
693           }
694       }
695
696       if (space != NULL)
697          todo = space + 1;
698       else
699          todo = NULL;
700    }
701 }
702
703 static Boolean index_initted;
704
705 /* Read and initialize global index */
706 int
707 index_initialize(char *path)
708 {
709     FILE *fp;
710
711     if (!index_initted) {
712         /* Got any media? */
713         if (!mediaVerify())
714             return DITEM_FAILURE;
715
716         /* Does it move when you kick it? */
717         if (!mediaDevice->init(mediaDevice))
718             return DITEM_FAILURE;
719
720         msgNotify("Attempting to fetch %s file from selected media.", path);
721         fp = mediaDevice->get(mediaDevice, path, TRUE);
722         if (!fp) {
723             dialog_clear_norefresh();
724             msgConfirm("Unable to get packages/INDEX file from selected media.\n"
725                        "This may be because the packages collection is not available at\n"
726                        "on the distribution media you've chosen (most likely an FTP site\n"
727                        "without the packages collection mirrored).  Please verify media\n"
728                        "(or path to media) and try again.  If your local site does not\n"
729                        "carry the packages collection, then we recommend either a CD\n"
730                        "distribution or the master distribution on ftp.freebsd.org.");
731             mediaDevice->shutdown(mediaDevice);
732             return DITEM_FAILURE | DITEM_RESTORE;
733         }
734         msgNotify("Located INDEX, now reading package data from it...");
735         index_init(&Top, &Plist);
736         if (index_read(fp, &Top)) {
737             msgConfirm("I/O or format error on packages/INDEX file.\n"
738                        "Please verify media (or path to media) and try again.");
739             fclose(fp);
740             return DITEM_FAILURE | DITEM_RESTORE;
741         }
742         fclose(fp);
743         index_sort(&Top);
744         index_initted = TRUE;
745     }
746     return DITEM_SUCCESS | DITEM_RESTORE;
747 }