2 * The new sysinstall program.
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
8 * Jordan Hubbard. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer,
15 * verbatim and that no modifications are made prior to this
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 #include "sysinstall.h"
44 /* Macros and magic values */
48 /* A structure holding the root, top and plist pointer at once */
51 PkgNodePtr root; /* root of tree */
52 PkgNodePtr top; /* part of tree we handle */
53 PkgNodePtr plist; /* list of selected packages */
55 typedef struct ListPtrs* ListPtrsPtr;
57 static void index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie);
59 /* Shared between index_initialize() and the various clients of it */
66 return ptr ? strdup(ptr) : NULL;
69 static char *descrs[] = {
70 "Package Selection", "To mark a package, move to it and press SPACE. If the package is\n"
71 "already marked, it will be unmarked or deleted (if installed).\n"
72 "Items marked with a `D' are dependencies which will be auto-loaded.\n"
73 "To search for a package by name, press ESC. To select a category,\n"
74 "press RETURN. NOTE: The All category selection creates a very large\n"
75 "submenu! If you select it, please be patient while it comes up.",
76 "Package Targets", "These are the packages you've selected for extraction.\n\n"
77 "If you're sure of these choices, select OK.\n"
78 "If not, select Cancel to go back to the package selection menu.\n",
79 "All", "All available packages in all categories.",
80 "accessibility", "Ports to help disabled users.",
81 "afterstep", "Ports to support the AfterStep window manager.",
82 "arabic", "Ported software for Arab countries.",
83 "archivers", "Utilities for archiving and unarchiving data.",
84 "astro", "Applications related to astronomy.",
85 "audio", "Audio utilities - most require a supported sound card.",
86 "benchmarks", "Utilities for measuring system performance.",
87 "biology", "Software related to biology.",
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 "deskutils", "Various Desktop utilities.",
94 "devel", "Software development utilities and libraries.",
95 "dns", "Domain Name Service tools.",
96 "docs", "Meta-ports for FreeBSD documentation.",
97 "editors", "Editors.",
98 "elisp", "Things related to Emacs Lisp.",
99 "emulators", "Utilities for emulating other operating systems.",
100 "finance", "Monetary, financial and related applications.",
101 "french", "Ported software for French countries.",
102 "ftp", "FTP client and server utilities.",
103 "games", "Various and sundry amusements.",
104 "german", "Ported software for Germanic countries.",
105 "geography", "Geography-related software.",
106 "gnome", "Components of the Gnome Desktop environment.",
107 "gnustep", "Software for GNUstep desktop environment.",
108 "graphics", "Graphics libraries and utilities.",
109 "haskell", "Software related to the Haskell language.",
110 "hamradio", "Software for amateur radio.",
111 "hebrew", "Ported software for Hebrew language.",
112 "hungarian", "Ported software for the Hungarian market.",
113 "ipv6", "IPv6 related software.",
114 "irc", "Internet Relay Chat utilities.",
115 "japanese", "Ported software for the Japanese market.",
116 "java", "Java language support.",
117 "kde", "Software for the K Desktop Environment.",
118 "kld", "Kernel loadable modules",
119 "korean", "Ported software for the Korean market.",
120 "lang", "Computer languages.",
121 "linux", "Linux programs that can run under binary compatibility.",
122 "lisp", "Software related to the Lisp language.",
123 "mail", "Electronic mail packages and utilities.",
124 "math", "Mathematical computation software.",
125 "mbone", "Applications and utilities for the MBONE.",
126 "misc", "Miscellaneous utilities.",
127 "multimedia", "Multimedia software.",
128 "net", "Networking utilities.",
129 "net-im", "Instant messaging software.",
130 "net-mgmt", "Network management tools.",
131 "net-p2p", "Peer to peer network applications.",
132 "news", "USENET News support software.",
133 "palm", "Software support for the Palm(tm) series.",
134 "parallel", "Applications dealing with parallelism in computing.",
135 "pear", "Software related to the Pear PHP framework.",
136 "perl5", "Utilities/modules for the PERL5 language.",
137 "plan9", "Software from the Plan9 operating system.",
138 "polish", "Ported software for the Polish market.",
139 "ports-mgmt", "Utilities for managing ports and packages.",
140 "portuguese", "Ported software for the Portuguese market.",
141 "print", "Utilities for dealing with printing.",
142 "python", "Software related to the Python language.",
143 "ruby", "Software related to the Ruby language.",
144 "rubygems", "Ports of RubyGems packages.",
145 "russian", "Ported software for the Russian market.",
146 "scheme", "Software related to the Scheme language.",
147 "science", "Scientific software.",
148 "security", "System security software.",
149 "shells", "Various shells (tcsh, bash, etc).",
150 "spanish", "Ported software for the Spanish market.",
151 "sysutils", "Various system utilities.",
152 "tcl", "TCL and packages that depend on it.",
153 "tcl80", "TCL v8.0 and packages that depend on it.",
154 "tcl82", "TCL v8.2 and packages that depend on it.",
155 "tcl83", "TCL v8.3 and packages that depend on it.",
156 "tcl84", "TCL v8.4 and packages that depend on it.",
157 "textproc", "Text processing/search utilities.",
158 "tk", "Tk and packages that depend on it.",
159 "tk80", "Tk8.0 and packages that depend on it.",
160 "tk82", "Tk8.2 and packages that depend on it.",
161 "tk83", "Tk8.3 and packages that depend on it.",
162 "tk84", "Tk8.4 and packages that depend on it.",
163 "tkstep80", "Ports to support the TkStep window manager.",
164 "ukrainian", "Ported software for the Ukrainian market.",
165 "vietnamese", "Ported software for the Vietnamese market.",
166 "windowmaker", "Ports to support the WindowMaker window manager.",
167 "www", "Web utilities (browsers, HTTP servers, etc).",
168 "x11", "X Window System based utilities.",
169 "x11-clocks", "X Window System based clocks.",
170 "x11-drivers", "X Window System drivers.",
171 "x11-fm", "X Window System based file managers.",
172 "x11-fonts", "X Window System fonts and font utilities.",
173 "x11-servers", "X Window System servers.",
174 "x11-themes", "X Window System themes.",
175 "x11-toolkits", "X Window System based development toolkits.",
176 "x11-wm", "X Window System window managers.",
177 "xfce", "Software related to the Xfce Desktop Environment.",
178 "zope", "Software related to the Zope platform.",
183 fetch_desc(char *name)
187 for (i = 0; descrs[i]; i += 2) {
188 if (!strcmp(descrs[i], name))
189 return descrs[i + 1];
191 return "No description provided";
195 new_pkg_node(char *name, node_type type)
197 PkgNodePtr tmp = safe_malloc(sizeof(PkgNode));
199 tmp->name = _strdup(name);
209 for (i = 0; buf[i]; i++)
210 if (buf[i] == '\t' || buf[i] == '\n')
216 new_index(char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *deps, int volume)
218 IndexEntryPtr tmp = safe_malloc(sizeof(IndexEntry));
220 tmp->name = _strdup(name);
221 tmp->path = _strdup(pathto);
222 tmp->prefix = _strdup(prefix);
223 tmp->comment = _strdup(comment);
224 tmp->descrfile = strip(_strdup(descr));
225 tmp->maintainer = _strdup(maint);
226 tmp->deps = _strdup(deps);
228 tmp->installed = package_installed(name);
229 tmp->vol_checked = 0;
230 tmp->volume = volume;
235 else if (low_volume > volume)
237 if (high_volume < volume)
238 high_volume = volume;
244 index_register(PkgNodePtr top, char *where, IndexEntryPtr ptr)
248 for (q = NULL, p = top->kids; p; p = p->next) {
249 if (!strcmp(p->name, where)) {
255 /* Add new category */
256 q = new_pkg_node(where, PLACE);
257 q->desc = fetch_desc(where);
261 p = new_pkg_node(ptr->name, PACKAGE);
262 p->desc = ptr->comment;
269 copy_to_sep(char *to, char *from, int sep)
273 tok = strchr(from, sep);
280 return tok + 1 - from;
284 skip_to_sep(char *from, int sep)
288 tok = strchr(from, sep);
292 return tok + 1 - from;
296 readline(FILE *fp, char *buf, int max)
301 while ((rv = fread(&ch, 1, 1, fp)) == 1 && ch != '\n' && i < max)
309 * XXX - this function should do error checking, and skip corrupted INDEX
310 * lines without a set number of '|' delimited fields.
314 index_parse(FILE *fp, char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *cats, char *rdeps, int *volume)
316 char line[10240 + 2048 * 7];
322 i = readline(fp, line, sizeof line);
326 cp += copy_to_sep(name, cp, '|'); /* package name */
327 cp += copy_to_sep(pathto, cp, '|'); /* ports directory */
328 cp += copy_to_sep(prefix, cp, '|'); /* prefix */
329 cp += copy_to_sep(comment, cp, '|'); /* comment */
330 cp += copy_to_sep(descr, cp, '|'); /* path to pkg-descr */
331 cp += copy_to_sep(maint, cp, '|'); /* maintainer */
332 cp += copy_to_sep(cats, cp, '|'); /* categories */
333 cp += skip_to_sep(cp, '|'); /* build deps - not used */
334 cp += copy_to_sep(rdeps, cp, '|'); /* run deps */
336 cp += skip_to_sep(cp, '|'); /* url - not used */
338 strncpy(junk, cp, 1023);
343 cp += skip_to_sep(cp, '|'); /* extract deps - not used */
345 cp += skip_to_sep(cp, '|'); /* patch deps - not used */
347 cp += skip_to_sep(cp, '|'); /* fetch deps - not used */
349 cp += copy_to_sep(volstr, cp, '|'); /* media volume */
351 strncpy(volstr, cp, 1023);
353 *volume = atoi(volstr);
358 index_read(FILE *fp, PkgNodePtr papa)
360 char name[127], pathto[255], prefix[255], comment[255], descr[127], maint[127], cats[511], deps[2048 * 8];
364 while (index_parse(fp, name, pathto, prefix, comment, descr, maint, cats, deps, &volume) != EOF) {
365 char *cp, *cp2, tmp[1024];
368 idx = new_index(name, pathto, prefix, comment, descr, maint, deps, volume);
369 /* For now, we only add things to menus if they're in categories. Keywords are ignored */
370 for (cp = strcpy(tmp, cats); (cp2 = strchr(cp, ' ')) != NULL; cp = cp2 + 1) {
372 index_register(papa, cp, idx);
374 index_register(papa, cp, idx);
376 /* Add to special "All" category */
377 index_register(papa, "All", idx);
380 /* Adjust dependency counts */
381 for (i = papa->kids; i != NULL; i = i->next)
382 if (strcmp(i->name, "All") == 0)
384 for (i = i->kids; i != NULL; i = i->next)
385 if (((IndexEntryPtr)i->data)->installed)
386 index_recorddeps(TRUE, papa, i->data);
392 index_init(PkgNodePtr top, PkgNodePtr plist)
395 top->next = top->kids = NULL;
396 top->name = "Package Selection";
398 top->desc = fetch_desc(top->name);
402 plist->next = plist->kids = NULL;
403 plist->name = "Package Targets";
405 plist->desc = fetch_desc(plist->name);
411 index_print(PkgNodePtr top, int level)
416 for (i = 0; i < level; i++) putchar('\t');
417 printf("name [%s]: %s\n", top->type == PLACE ? "place" : "package", top->name);
418 for (i = 0; i < level; i++) putchar('\t');
419 printf("desc: %s\n", top->desc);
421 index_print(top->kids, level + 1);
426 /* Swap one node for another */
428 swap_nodes(PkgNodePtr a, PkgNodePtr b)
439 /* Use a disgustingly simplistic bubble sort to put our lists in order */
441 index_sort(PkgNodePtr top)
445 /* Sort everything at the top level */
446 for (p = top->kids; p; p = p->next) {
447 for (q = top->kids; q; q = q->next) {
448 if (q->next && strcmp(q->name, q->next->name) > 0)
449 swap_nodes(q, q->next);
453 /* Now sub-sort everything n levels down */
454 for (p = top->kids; p; p = p->next) {
460 /* Delete an entry out of the list it's in (only the plist, at present) */
462 index_delete(PkgNodePtr n)
465 PkgNodePtr p = n->next;
470 else /* Kludgy end sentinal */
475 * Search for a given node by name, returning the category in if
479 index_search(PkgNodePtr top, char *str, PkgNodePtr *tp)
483 for (p = top->kids; p && p->name; p = p->next) {
484 if (p->type == PACKAGE) {
485 /* If tp == NULL, we're looking for an exact package match */
486 if (!tp && !strcmp(p->name, str))
489 /* If tp, we're looking for both a package and a pointer to the place it's in */
490 if (tp && !strncmp(p->name, str, strlen(str))) {
496 /* The usual recursion-out-of-laziness ploy */
497 if ((sp = index_search(p, str, tp)) != NULL)
507 pkg_checked(dialogMenuItem *self)
509 ListPtrsPtr lists = (ListPtrsPtr)self->aux;
510 PkgNodePtr kp = self->data, plist = lists->plist;
513 i = index_search(plist, kp->name, NULL) ? TRUE : FALSE;
514 if (kp->type == PACKAGE && plist) {
515 IndexEntryPtr ie = kp->data;
518 markD = ie->depc > 0; /* needed as dependency */
519 markX = i || ie->installed; /* selected or installed */
520 self->mark = markX ? 'X' : 'D';
521 return markD || markX;
527 pkg_fire(dialogMenuItem *self)
530 ListPtrsPtr lists = (ListPtrsPtr)self->aux;
531 PkgNodePtr sp, kp = self->data, plist = lists->plist;
535 else if (kp->type == PACKAGE) {
536 IndexEntryPtr ie = kp->data;
538 sp = index_search(plist, kp->name, NULL);
539 /* Not already selected? */
541 if (!ie->installed) {
542 PkgNodePtr np = (PkgNodePtr)safe_malloc(sizeof(PkgNode));
545 np->next = plist->kids;
547 index_recorddeps(TRUE, lists->root, ie);
548 msgInfo("Added %s to selection list", kp->name);
550 else if (ie->depc == 0) {
551 if (!msgNoYes("Do you really want to delete %s from the system?", kp->name)) {
552 if (vsystem("pkg_delete %s %s", isDebug() ? "-v" : "", kp->name)) {
553 msgConfirm("Warning: pkg_delete of %s failed.\n Check debug output for details.", kp->name);
557 index_recorddeps(FALSE, lists->root, ie);
562 msgConfirm("Warning: Package %s is needed by\n %d other installed package%s.",
563 kp->name, ie->depc, (ie->depc != 1) ? "s" : "");
566 index_recorddeps(FALSE, lists->root, ie);
567 msgInfo("Removed %s from selection list", kp->name);
571 /* Mark menu for redraw if we had dependencies */
572 if (strlen(ie->deps) > 0)
575 else { /* Not a package, must be a directory */
579 index_menu(lists->root, kp, plist, &p, &s);
580 ret = DITEM_SUCCESS | DITEM_CONTINUE;
586 pkg_selected(dialogMenuItem *self, int is_selected)
588 PkgNodePtr kp = self->data;
590 if (!is_selected || kp->type != PACKAGE)
592 msgInfo("%s", kp->desc);
596 index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll)
598 struct ListPtrs lists;
603 dialogMenuItem *nitems;
615 /* Figure out if this menu is full of "leaves" or "branches" */
616 for (kp = top->kids; kp && kp->name; kp = kp->next) {
620 if (kp->type == PACKAGE && plist) {
622 if ((len = strlen(kp->name)) > maxname)
627 msgConfirm("The %s menu is empty.", top->name);
628 return DITEM_LEAVE_MENU;
638 if (!hasPackages && plist) {
639 nitems = item_add(nitems, "OK", NULL, NULL, NULL, NULL, NULL, NULL, &curr, &max);
640 nitems = item_add(nitems, "Install", NULL, NULL, NULL, NULL, NULL, NULL, &curr, &max);
642 while (kp && kp->name) {
644 IndexEntryPtr ie = kp->data;
646 /* Brutally adjust description to fit in menu */
647 if (kp->type == PACKAGE)
648 snprintf(buf, sizeof buf, "[%s]", ie->path ? ie->path : "External vendor");
650 SAFE_STRCPY(buf, kp->desc);
651 if (strlen(buf) > (_MAX_DESC - maxname))
652 buf[_MAX_DESC - maxname] = '\0';
653 nitems = item_add(nitems, kp->name, buf, pkg_checked,
654 pkg_fire, pkg_selected, kp, &lists,
659 /* NULL delimiter so item_free() knows when to stop later */
660 nitems = item_add(nitems, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
664 dialog_clear_norefresh();
666 rval = dialog_checklist(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems, NULL);
668 rval = dialog_menu(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems + (plist ? 2 : 0), (char *)plist, pos, scroll);
669 if (rval == -1 && plist) {
674 if ((cp = msgGetInput(cp, "Search by package name. Please enter search string:")) != NULL) {
675 PkgNodePtr p = index_search(top, cp, &menu);
680 /* These need to be set to point at the found item, actually. Hmmm! */
682 index_menu(root, menu, plist, &pos, &scroll);
685 msgConfirm("Search string: %s yielded no hits.", cp);
689 items_free(nitems, &curr, &max);
691 return rval ? DITEM_FAILURE : DITEM_SUCCESS;
696 index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended,
699 int status = DITEM_SUCCESS;
700 Boolean notyet = FALSE;
702 IndexEntryPtr id = who->data;
706 * Short-circuit the package dependency checks. We're already
707 * maintaining a data structure of installed packages, so if a
708 * package is already installed, don't try to check to make sure
709 * that all of its dependencies are installed. At best this
710 * wastes a ton of cycles and can cause minor delays between
711 * package extraction. At worst it can cause an infinite loop with
712 * a certain faulty INDEX file.
715 if (id->installed == 1 || (have_volumes && id->vol_checked == current_volume))
716 return DITEM_SUCCESS;
719 if (id && id->deps && strlen(id->deps)) {
720 char t[2048 * 8], *cp, *cp2;
722 SAFE_STRCPY(t, id->deps);
724 while (cp && DITEM_STATUS(status) == DITEM_SUCCESS) {
725 if ((cp2 = index(cp, ' ')) != NULL)
727 if ((tmp2 = index_search(top, cp, NULL)) != NULL) {
728 status = index_extract(dev, top, tmp2, TRUE, current_volume);
729 if (DITEM_STATUS(status) != DITEM_SUCCESS) {
730 /* package probably on a future disc volume */
731 if (status & DITEM_CONTINUE) {
732 status = DITEM_SUCCESS;
734 } else if (variable_get(VAR_NO_CONFIRM))
735 msgNotify("Loading of dependent package %s failed", cp);
737 msgConfirm("Loading of dependent package %s failed", cp);
740 else if (!package_installed(cp)) {
741 if (variable_get(VAR_NO_CONFIRM))
742 msgNotify("Warning: %s is a required package but was not found.", cp);
744 msgConfirm("Warning: %s is a required package but was not found.", cp);
754 * If iterating through disc volumes one at a time indicate failure if
755 * dependency install failed due to package being on a higher volume
756 * numbered disc, but that we should continue anyway. Note that this
757 * package has already been processed for this disc volume so we don't
758 * need to do it again.
763 id->vol_checked = current_volume;
764 return DITEM_FAILURE | DITEM_CONTINUE;
768 * Done with the deps? Try to load the real m'coy. If iterating
769 * through a multi-volume disc set fail the install if the package
770 * is on a higher numbered volume to cut down on disc switches the
771 * user needs to do, but indicate caller should continue processing
772 * despite error return. Note this package was processed for the
773 * current disc being checked.
776 if (DITEM_STATUS(status) == DITEM_SUCCESS) {
777 /* Prompt user if the package is not available on the current volume. */
778 if(mediaDevice->type == DEVICE_TYPE_CDROM) {
779 if (current_volume != 0 && id->volume > current_volume) {
781 id->vol_checked = current_volume;
782 return DITEM_FAILURE | DITEM_CONTINUE;
784 while (id->volume != dev->volume) {
785 if (!msgYesNo("This is disc #%d. Package %s is on disc #%d\n"
786 "Would you like to switch discs now?\n", dev->volume,
787 id->name, id->volume)) {
788 DEVICE_SHUTDOWN(mediaDevice);
789 msgConfirm("Please remove disc #%d from your drive, and add disc #%d\n",
790 dev->volume, id->volume);
791 DEVICE_INIT(mediaDevice);
794 return DITEM_FAILURE;
798 status = package_extract(dev, who->name, depended);
799 if (DITEM_STATUS(status) == DITEM_SUCCESS)
807 index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie)
809 char depends[1024 * 16], *space, *todo;
811 IndexEntryPtr found_ie;
813 SAFE_STRCPY(depends, ie->deps);
814 for (todo = depends; todo != NULL; ) {
815 space = index(todo, ' ');
819 if (strlen(todo) > 0) { /* only non-empty dependencies */
820 found = index_search(root, todo, NULL);
822 found_ie = found->data;
837 static Boolean index_initted;
839 /* Read and initialize global index */
841 index_initialize(char *path)
846 if (!index_initted) {
848 dialog_clear_norefresh();
849 have_volumes = FALSE;
850 low_volume = high_volume = 0;
853 if (!mediaVerify()) {
855 return DITEM_FAILURE;
858 /* Does it move when you kick it? */
859 if (!DEVICE_INIT(mediaDevice)) {
861 return DITEM_FAILURE;
864 dialog_clear_norefresh();
865 msgNotify("Attempting to fetch %s file from selected media.", path);
866 fp = DEVICE_GET(mediaDevice, path, TRUE);
868 msgConfirm("Unable to get %s file from selected media.\n\n"
869 "This may be because the packages collection is not available\n"
870 "on the distribution media you've chosen, most likely an FTP site\n"
871 "without the packages collection mirrored. Please verify that\n"
872 "your media, or your path to the media, is correct and try again.", path);
873 DEVICE_SHUTDOWN(mediaDevice);
875 return DITEM_FAILURE;
877 dialog_clear_norefresh();
878 msgNotify("Located INDEX, now reading package data from it...");
879 index_init(&Top, &Plist);
880 if (index_read(fp, &Top)) {
881 msgConfirm("I/O or format error on %s file.\n"
882 "Please verify media (or path to media) and try again.",
886 return DITEM_FAILURE;
890 index_initted = TRUE;
893 return DITEM_SUCCESS;