Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtSearch / opendblk.c
1 /*
2  *   COMPONENT_NAME: austext
3  *
4  *   FUNCTIONS: open_dblk
5  *
6  *   ORIGINS: 27
7  *
8  *   (C) COPYRIGHT International Business Machines Corp. 1993,1995
9  *   All Rights Reserved
10  *   US Government Users Restricted Rights - Use, duplication or
11  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
12  */
13 /*********************** OPENDBLK.C ************************
14  * $XConsortium: opendblk.c /main/5 1996/05/07 13:43:01 drk $
15  * October 1993.
16  * Opens all vista and the d99 database files in a dblk list.
17  * Most errors are handled by disconnecting the offending
18  * dblk from the list.  Of course loss of ALL dblks is fatal.
19  *
20  * The nonvista d99 files (words inverted index) are opened,
21  * mostly to test if they can be found.  If not, we can return
22  * a complete error message for the single dblk and unlink it.
23  * Vista can only open all databases at once.
24  *
25  * Does not use dmacros.h for vista calls so error msgs can be
26  * constructed and added to global msglist (although hard vista
27  * errors will still first send a msg to stdout via dberr.c).
28  * 
29  * Open_dblk() should be used to replace all OPEN() calls
30  * in systems using DBLK structures.
31  * (1) It does not open dictionary files because they are not
32  *     always needed (in OE, these are opened in oeinit.c).
33  * (2) It does not read dbrec system records because the caller may
34  *     want to initialize them (in OE, these are read and
35  *     validated by ve_initialize() in ve.c).
36  * (3) It does not open the other d9x files because they
37  *     may not be present, depending on values in dbrec record.
38  *
39  * INPUT:
40  * 'dblist' is linked list of dblks.
41  *      Each dblk must have valid 'name' field,
42  *      and 'path' field must be NULL or a valid path string.
43  * 'numpages' is the number of vista cache pages to be opened.
44  *      Where speed is critical it should be 64--
45  *      for normal operations it should be no less than 16.
46  * 'debugging' is a boolean. It is usually set to (usrblk.debug & USRDBG_RARE)
47  *      and if TRUE, trace msgs are written to stdout.
48  *
49  * OUTPUT:
50  * Sets correct vistano, iifile, and iimtime fields in each surviving dblk.
51  * Places all err msgs on global msglist as they occur.
52  * Sets austext_exit_dbms to d_close() on success (retncode > 0).
53  * Returns TRUE if at least some of the databases were opened.
54  *    Bad dblks are unlinked from dblist and freed.
55  * Returns FALSE if fatal errors.
56  *
57  * $Log$
58  * Revision 2.5  1996/02/01  19:19:41  miker
59  * Minor change to err msg.
60  *
61  * Revision 2.4  1995/10/25  15:26:16  miker
62  * Added prolog.
63  *
64  * Revision 2.3  1995/10/19  20:25:52  miker
65  * Renaming database files no longer required.
66  * Transaction logging disabled, no space needed for overflow files.
67  * Open mode of non-vista database files also tracks new vista db_oflag.
68  *
69  * Revision 2.2  1995/10/03  21:45:26  miker
70  * Cosmetic msg changes only.
71  *
72  * Revision 2.1  1995/09/22  21:38:03  miker
73  * Freeze DtSearch 0.1, AusText 2.1.8
74  *
75  * Revision 1.8  1995/09/05  19:04:40  miker
76  * Name and msgs changes for DtSearch.  Made ausapi_msglist universal.
77  */
78 #include "SearchE.h"
79 #include <string.h>
80 #include <errno.h>
81 #include <fcntl.h>
82 #include <sys/stat.h>
83 #include "vista.h"
84
85 #define PROGNAME        "OPENDBLK"
86 #define MS_misc         1
87 #define MS_oeinit       9
88 #define MS_vista        13
89
90 /****************************************/
91 /*                                      */
92 /*              open_dblk               */
93 /*                                      */
94 /****************************************/
95 /* dblk.path may be NULL */
96 int             open_dblk (DBLK ** dblist, int numpages, int debugging)
97 {
98     DBLK           *db, *bad_db, **lastlink;
99     int             i;
100     size_t          totlen = 0L;
101     char           *allnames;
102     int             vistano = 0;
103     char           *srcptr, *targptr;
104     char            temp_file_name[1024];
105     char            sprintbuf[1024];
106     struct stat     statbuf;
107     char        open_mode [8];
108
109     if (debugging)
110         fprintf (aa_stderr, PROGNAME"76 "
111             "Entering open_dblks().  db_oflag==%d.\n",
112             db_oflag);
113     if (dblist == NULL || numpages < 8) {
114 BAD_INPUT:
115         sprintf (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 99,
116                 "%s Programming Error: Invalid input to open_dblk()."),
117             PROGNAME "99");
118         DtSearchAddMessage (sprintbuf);
119         return FALSE;
120     }
121     if (*dblist == NULL)        /* empty list of dblks */
122         goto BAD_INPUT;
123
124     if (debugging) {
125         fprintf (aa_stderr, PROGNAME "96 Current list of dblks:\n");
126         for (db = *dblist; db != NULL; db = db->link) {
127             targptr = sprintbuf;
128             for (i = 0; i < db->ktcount; i++) {
129                 *targptr++ = db->keytypes[i].ktchar;
130             }
131             *targptr = 0;
132             fprintf (aa_stderr, "--> DBLK at %p link=%p name='%s' maxhits=%d\n"
133                 "    keytypes='%s', path='%s'\n",
134                 db, db->link, db->name, db->maxhits,
135                 sprintbuf, NULLORSTR (db->path));
136         }
137     }
138
139     /* By doing setpages first, we can trap previously opened databases.
140      * Overflow and transaction locking files are not required.
141      */
142     d_setpages (numpages, 0);
143     if (db_status != S_OKAY) {
144         DtSearchAddMessage (vista_msg (PROGNAME "389"));
145         return FALSE;
146     }
147
148     /* ---- PASS #1 ------------------------------------------
149      * Open nonvista (d99) files.  If error, unlink dblk from dblist.
150      * Add up the total string length of surviving paths and database names.
151      * This giant path/file string will be used in the single d_open()
152      * below to find the .dbd files.
153      * While we're at it, set vistano in each dblk.
154      * The open mode depends on the current setting of db_oflag.
155      */
156     if (db_oflag == O_RDONLY)
157         strcpy (open_mode, "rb");
158     else
159         strcpy (open_mode, "r+b");
160     db = *dblist;
161     lastlink = dblist;
162     while (db != NULL) {
163         if (db->path == NULL)
164             db->path = strdup ("");
165         strcpy (temp_file_name, db->path);
166         strcat (temp_file_name, db->name);
167         strcat (temp_file_name, EXT_DTBS);
168         if ((db->iifile = fopen (temp_file_name, open_mode)) == NULL) {
169             if (debugging)
170                 fprintf (aa_stderr, PROGNAME "129 UNLINK: cant open '%s'.\n",
171                     temp_file_name);
172             sprintf (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 317,
173                     "%s Cannot open database file '%s'.\n"
174                     "  Errno %d = %s\n"
175                     "  %s is removing '%s' from list of available databases."),
176                 PROGNAME "317", temp_file_name, errno, strerror (errno),
177                 OE_prodname, db->name);
178             if (errno == ENOENT)
179                 strcat (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 318,
180                     "\n  This can usually be corrected by specifying a valid\n"
181                     "  database PATH in the site configuration file."));
182             DtSearchAddMessage (sprintbuf);
183             goto DELETE_DB;
184         }
185
186         /*
187          * Find and save the timestamp for when the d99 file was
188          * last modified. An engine reinit is forced if it changes
189          * while the engine is running. 
190          */
191         if (fstat (fileno (db->iifile), &statbuf) == -1) {
192             if (debugging)
193                 fprintf (aa_stderr,
194                     PROGNAME "149 UNLINK: cant get status '%s'.\n",
195                     temp_file_name);
196             sprintf (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 1404,
197                     "%s Removing database '%s' from list of "
198                     "available databases because status is "
199                     "unavailable for file %s: %s"),
200                 PROGNAME "1404", db->name, temp_file_name, strerror (errno));
201             DtSearchAddMessage (sprintbuf);
202             goto DELETE_DB;
203         }
204         db->iimtime = statbuf.st_mtime;
205
206         /*
207          * This dblk is ok so far.  Increment pointers and
208          * continue. 
209          */
210         if (debugging)
211             fprintf (aa_stderr, PROGNAME "163 opened '%s'.\n", temp_file_name);
212         db->vistano = vistano++;
213         totlen += strlen (db->path) + strlen (db->name) + 16;
214         lastlink = &db->link;
215         db = db->link;
216         continue;
217
218 DELETE_DB:
219         /*
220          * This dblk failed in one or more ways. Unlink it and
221          * don't increment pointers. If all dblks unlinked, *dblist
222          * will = NULL. 
223          */
224         bad_db = db;    /* temp save */
225         *lastlink = db->link;
226         db = db->link;
227         free (bad_db);
228     }   /* end PASS #1 */
229
230     /* quit if no dblks remain */
231     if (vistano <= 0) {
232         sprintf (sprintbuf, catgets (dtsearch_catd, MS_misc, 8,
233                 "%s No valid databases remain."), PROGNAME "265");
234         DtSearchAddMessage (sprintbuf);
235         return FALSE;
236     }
237
238     allnames = austext_malloc (totlen + 512, PROGNAME "66", NULL);
239
240     /* ---- PASS #2 ------------------------------------------
241      * Build string of accumulated path and database names.
242      */
243     targptr = allnames;
244     for (db = *dblist; db != NULL; db = db->link) {
245         srcptr = db->path;
246         while (*srcptr != 0)
247             *targptr++ = *srcptr++;
248
249         srcptr = db->name;
250         while (*srcptr != 0)
251             *targptr++ = *srcptr++;
252         *targptr++ = ';';
253     }
254     *(--targptr) = 0;   /* terminate string */
255
256     if (debugging)
257         fprintf (aa_stderr,
258             PROGNAME "150 vista opening databases '%s'\n", allnames);
259     d_open (allnames, "o");     /* replaces OPEN() call from dmacros.h */
260
261     if (db_status != S_OKAY) {
262         targptr = austext_malloc (totlen + 128, PROGNAME"239", NULL);
263         sprintf (targptr, catgets (dtsearch_catd, MS_vista, 378,
264             "%s Could not open following database name string:\n  '%s'"),
265             PROGNAME"378", allnames);
266         DtSearchAddMessage (targptr);
267         DtSearchAddMessage (vista_msg (PROGNAME"379"));
268         free (allnames);
269         free (targptr);
270         return FALSE;
271     }
272     else if (debugging)
273         fprintf (aa_stderr, " --> vista open successful!\n");
274
275     /* From here on, emergency exits MUST close the databases */
276     austext_exit_dbms = (void (*) (int)) d_close;
277
278     free (allnames);
279     return TRUE;
280 }  /* open_dblk() */
281
282 /*********************** OPENDBLK.C ************************/