Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / DtsMM.c
1 /*
2  *      $TOG: DtsMM.c /main/16 1998/10/23 13:48:28 mgreess $
3  *
4  *      RESTRICTED CONFIDENTIAL INFORMATION:
5  *
6  *      (c) Copyright 1993,1994,1995 Sun Microsystems, Inc. 
7  *              All rights reserved.
8  */
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #define SUN_DB
17 #ifdef  SUN_DB
18 #include <sys/utsname.h>
19 #include <dirent.h>
20 #include <sys/mman.h>
21 #include <sys/param.h>
22 #endif
23 #include <string.h>
24 #define X_INCLUDE_DIRENT_H
25 #define XOS_USE_XT_LOCKING
26 #include <X11/Xos_r.h>
27 #include <Dt/DbReader.h>
28 #include "Dt/DtsMM.h"
29 #include "Dt/DtNlUtils.h"
30 #include <Dt/UserMsg.h>
31 #include "DtSvcLock.h"
32
33 extern char *strdup(const char *);
34 static int MMValidateDb(DtDirPaths *dirs, char *suffix);
35 static int _debug_print_name(char *name, char *label);
36
37 typedef int     (*genfunc)(const void *, const void *);
38
39 static  DtDtsMMDatabase *db_list;
40 static  caddr_t         mmaped_db = 0;
41 static  size_t          mmaped_size = 0;
42 static  int             mmaped_fd = 0;
43 static  DtDtsMMHeader   *head = 0;
44
45 void *
46 _DtDtsMMGetPtr(int index)
47 {
48         DtShmIntList  int_list;
49
50         _DtSvcProcessLock();
51         if(!mmaped_db)
52         {
53                 _DtDtsMMInit(0);
54         }
55         int_list = (DtShmIntList)&mmaped_db[sizeof(DtDtsMMHeader)];
56         _DtSvcProcessUnlock();
57         return((void *)&int_list[index]);
58 }
59
60 int
61 _DtDtsMMGetPtrSize(int index)
62 {
63         DtShmIntList  int_list;
64
65         _DtSvcProcessLock();
66         if(!mmaped_db)
67         {
68                 _DtDtsMMInit(0);
69         }
70         int_list = (DtShmIntList)&mmaped_db[sizeof(DtDtsMMHeader)];
71         _DtSvcProcessUnlock();
72         return(int_list[index-1]);
73 }
74
75 int *
76 _DtDtsMMGetDCNameIndex(int *size)
77 {
78         int *result;
79
80         _DtSvcProcessLock();
81         *size = _DtDtsMMGetPtrSize(head->name_list_offset);     
82         result = (int*) _DtDtsMMGetPtr(head->name_list_offset);
83         _DtSvcProcessUnlock();
84         return(result);
85 }
86
87 int *
88 _DtDtsMMGetDbName(DtDtsMMDatabase *db, DtShmBoson boson)
89 {
90         DtShmInttab     tab = (DtShmInttab)_DtDtsMMGetPtr(db->nameIndex);
91         return((int *)_DtShmFindIntTabEntry(tab, boson));
92 }
93
94 int *
95 _DtDtsMMGetNoNameIndex(int *size)
96 {
97         int *result;
98
99         _DtSvcProcessLock();
100
101         if(head->no_name_offset == -1)
102         {
103                 *size = 0;
104                 _DtSvcProcessUnlock();
105                 return(0);
106         }
107         *size = _DtDtsMMGetPtrSize(head->no_name_offset);       
108         result = (int *) _DtDtsMMGetPtr(head->no_name_offset);
109         _DtSvcProcessUnlock();
110         return(result);
111 }
112
113 /* returns the pointer to buffer only name list */
114 int *
115 _DtDtsMMGetBufferIndex(int *size)
116 {
117         int     *list = (int*)_DtDtsMMGetNoNameIndex(size);
118         int     *bufferIndex;
119
120         _DtSvcProcessLock();
121         *size -= head->buffer_start_index;
122         bufferIndex = &list[head->buffer_start_index];
123         _DtSvcProcessUnlock();
124
125         return(bufferIndex);
126 }
127
128 DtShmInttab
129 _DtDtsMMGetFileList(void)
130 {
131         DtShmInttab file_index;
132
133         _DtSvcProcessLock();
134         file_index = (DtShmStrtab)_DtDtsMMGetPtr(head->files_offset);
135         _DtSvcProcessUnlock();
136         return(file_index);
137 }
138
139 const char *
140 _DtDtsMMBosonToString(DtShmBoson boson)
141 {
142         DtShmStrtab str_table;
143
144         if (boson == 0)
145                 return(0);
146
147         _DtSvcProcessLock();
148         if(!mmaped_db)
149         {
150                 _DtDtsMMInit(0);
151         }
152
153         str_table = (DtShmStrtab)_DtDtsMMGetPtr(head->str_tbl_offset);
154         _DtSvcProcessUnlock();
155
156         return(_DtShmBosonToString(str_table, boson));
157 }
158
159 DtShmBoson
160 _DtDtsMMStringToBoson(const char *string)
161 {
162         DtShmStrtab str_table;
163
164         if ((string == (char *)NULL) || (*string == '\0'))
165                 return(-1);
166
167         _DtSvcProcessLock();
168         if(!mmaped_db)
169         {
170                 _DtDtsMMInit(0);
171         }
172
173         str_table = (DtShmStrtab)_DtDtsMMGetPtr(head->str_tbl_offset);
174         _DtSvcProcessUnlock();
175
176         return(_DtShmStringToBoson(str_table, string));
177 }
178
179 void
180 _DtDtsMMPrintFld(int fld, DtDtsMMField *fld_ptr, FILE *fd_in)
181 {
182         const   char    *tmp;
183         const   char    *tmpv;
184         FILE    *fd = fd_in;
185
186         if(!fd) fd = stdout;
187
188         tmp = _DtDtsMMBosonToString(fld_ptr->fieldName);
189         tmpv = _DtDtsMMBosonToString(fld_ptr->fieldValue);
190         fprintf(fd, "\t\t[%d]\t%s(%d)\t%s(%d)\n", fld, tmp,fld_ptr->fieldName,
191                 tmpv?tmpv:"(NULL)", fld_ptr->fieldValue);
192 }
193
194 void
195 _DtDtsMMPrintRec(int rec, DtDtsMMRecord *rec_ptr, FILE *fd_in)
196 {
197         int             fld;
198         DtDtsMMField    *fld_ptr;
199         DtDtsMMField    *fld_ptr_list;
200         const   char    *tmp;
201         FILE    *fd = fd_in;
202
203         if(!fd) fd = stdout;
204
205         tmp = _DtDtsMMBosonToString(rec_ptr->recordName);
206         fprintf(fd, "\tRec[%d] name = %s(%d)\n\t%d Fields\n", rec,
207                 tmp, rec_ptr->recordName,
208                 rec_ptr->fieldCount);
209         fld_ptr_list = _DtDtsMMGetPtr(rec_ptr->fieldList);
210         for(fld = 0; fld < rec_ptr->fieldCount; fld++)
211         {
212                 fld_ptr = &fld_ptr_list[fld];
213                 _DtDtsMMPrintFld(fld, fld_ptr, fd);
214         }
215 }
216
217 void
218 _DtDtsMMPrintDb(int db, DtDtsMMDatabase *db_ptr, FILE *fd_in)
219 {
220         int             rec;
221         DtDtsMMRecord   *rec_ptr;
222         DtDtsMMRecord   *rec_ptr_list;
223         const   char    *tmp;
224         FILE    *fd = fd_in;
225
226         if(!fd) fd = stdout;
227
228         fprintf(fd, "DB[%d] ", db);
229         tmp =  _DtDtsMMBosonToString(db_ptr->databaseName);
230         fprintf(fd, "name = %s(%d)\n", tmp, db_ptr->databaseName);
231         fprintf(fd, "%d Records\n", db_ptr->recordCount);
232         rec_ptr_list = _DtDtsMMGetPtr(db_ptr->recordList);
233         for(rec = 0; rec < db_ptr->recordCount; rec++)
234         {
235                 rec_ptr = &rec_ptr_list[rec];
236                 _DtDtsMMPrintRec(rec, rec_ptr, fd);
237         }
238 }
239
240 void
241 _DtDtsMMPrint(FILE *org_fd)
242 {
243         int             db;
244         DtDtsMMDatabase *db_ptr;
245         FILE            *fd = org_fd;
246         const   char    *tmp;
247
248         _DtSvcProcessLock();
249         if(!mmaped_db)
250         {
251                 _DtDtsMMInit(0);
252         }
253
254         for(db = 0; db < head->num_db; db++)
255         {
256                 db_ptr = &db_list[db];
257                 if(fd == 0)
258                 {
259                         chdir("/tmp");
260                         tmp = _DtDtsMMBosonToString(db_ptr->databaseName);
261                         if((fd = fopen(tmp, "w")) == NULL)
262                         {
263                             _DtSimpleError(
264                                         DtProgName, DtError, NULL,
265                                         (char*) tmp, NULL);
266                             continue;
267                         }
268                 }
269                 _DtDtsMMPrintDb(db, db_ptr, fd);
270                 if(org_fd == 0)
271                 {
272                         fclose(fd);
273                         fd = 0;
274                 }
275         }
276         _DtSvcProcessUnlock();
277 }
278
279 int
280 _DtDtsMMCompareRecordNames(DtDtsMMRecord *a, DtDtsMMRecord *b)
281 {
282         return (a->recordName - b->recordName);
283 }
284
285 int
286 _DtDtsMMCompareFieldNames(DtDtsMMField *a, DtDtsMMField *b)
287 {
288         return (a->fieldName - b->fieldName);
289 }
290
291 #include <Dt/Dts.h>
292
293 int
294 _DtDtsMMInit(int override)
295 {
296         DtDirPaths *dirs = _DtGetDatabaseDirPaths();
297         char    *CacheFile = _DtDtsMMCacheName(1);
298         if(override)
299         {
300                 if (!_DtDtsMMCreateDb(dirs, CacheFile, override))
301                 {
302                         free(CacheFile);
303                         _DtFreeDatabaseDirPaths(dirs);
304                         return 0;
305                 }
306                 _debug_print_name(CacheFile, "Init");
307         }
308         else
309         {
310                 int success = _DtDtsMMapDB(CacheFile);
311                 if(success)
312                 {
313                         if(!MMValidateDb(dirs, ".dt"))
314                         {
315                                 success = 0;
316                         }
317                         else
318                         {
319                                 _debug_print_name(CacheFile, "Mapped");
320                         }
321                 }
322                 if(!success)
323                 {
324                         free(CacheFile);
325                         CacheFile = _DtDtsMMCacheName(0);
326                         _debug_print_name(CacheFile, "Private");
327                         /* Check return status, and pass status to caller. */
328                         if (!_DtDtsMMCreateDb(dirs, CacheFile, override))
329                         {
330                                 free(CacheFile);
331                                 _DtFreeDatabaseDirPaths(dirs);
332                                 return 0;
333                         }
334                 }
335         }
336         free(CacheFile);
337         _DtFreeDatabaseDirPaths(dirs);
338         return 1;
339 }
340
341 char **
342 _DtsMMListDb()
343 {
344         int     i;
345         char    **list;
346
347         _DtSvcProcessLock();
348         if(!mmaped_db)
349         {
350                 _DtDtsMMInit(0);
351         }
352
353         list = (char **)malloc((head->num_db+1)*sizeof(char *));
354         for ( i = 0; i < head->num_db; i++ )
355         {
356                 list[i] = (char *)_DtDtsMMBosonToString(db_list[i].databaseName);
357         }
358         list[i] = 0;
359         _DtSvcProcessUnlock();
360         return(list);
361 }
362
363
364 DtDtsMMDatabase *
365 _DtDtsMMGet(const char *name)
366 {
367         int             i;
368         DtShmBoson      boson = _DtDtsMMStringToBoson(name);
369         DtDtsMMDatabase *ret_db;
370
371         _DtSvcProcessLock();
372         if(!mmaped_db)
373         {
374                 _DtDtsMMInit(0);
375         }
376         for(i = 0; i < head->num_db; i++)
377         {
378                 if(db_list[i].databaseName == boson)
379                 {
380                         ret_db = &db_list[i];
381                         _DtSvcProcessUnlock();
382
383                         return(ret_db);
384                 }
385         }
386         _DtSvcProcessUnlock();
387         return(NULL);
388 }
389
390
391 DtDtsMMField *
392 _DtDtsMMGetField(DtDtsMMRecord *rec, const char *name)
393 {
394         register int i;
395         int             fld;
396         DtDtsMMField    *fld_ptr;
397         DtDtsMMField    *fld_ptr_list;
398
399         /*
400          * Field names have been quarked so quark 'name' and
401          * do a linear search for the quark'ed field name.
402          */
403         DtShmBoson      tmp = _DtDtsMMStringToBoson (name);
404
405         fld_ptr_list = _DtDtsMMGetPtr(rec->fieldList);
406         for (i = 0; i < rec->fieldCount; i++)
407         {
408                 fld_ptr = &fld_ptr_list[i];
409                 if (fld_ptr->fieldName == tmp)
410                 {
411                         return (fld_ptr);
412                 }
413         }
414         return(NULL);
415 }
416
417 const char *
418 _DtDtsMMGetFieldByName(DtDtsMMRecord *rec, const char *name)
419 {
420         DtDtsMMField    *result;
421
422         result = _DtDtsMMGetField(rec, name);
423         if(result)
424         {
425                 return(_DtDtsMMBosonToString(result->fieldValue));
426         }
427         else
428         {
429                 return(NULL);
430         }
431
432 }
433
434 DtDtsMMRecord *
435 _DtDtsMMGetRecordByName(DtDtsMMDatabase *db, const char *name)
436 {
437         DtDtsMMRecord   srch;
438         DtDtsMMRecord   *result;
439         DtDtsMMRecord   *s = &srch;
440         register int i;
441         DtShmBoson      name_quark = _DtDtsMMStringToBoson(name);
442         DtDtsMMRecord   *rec_ptr;
443         DtDtsMMRecord   *rec_ptr_list;
444
445         /*
446          * If the fields are not sorted in alphanumeric order
447          * by name a binary search will fail.  So do the slow but
448          * sure linear search.
449          */
450         rec_ptr_list = _DtDtsMMGetPtr(db->recordList);
451
452         for (i = 0; i < db->recordCount; i++)
453         {
454                 rec_ptr = &rec_ptr_list[i];
455                 if (rec_ptr->recordName == name_quark)
456                 {
457                         return (rec_ptr);
458                 }
459         }
460         return NULL;
461 }
462 int
463 _DtDtsMMPathHash(DtDirPaths *dirs)
464 {
465         int     pathhash = 0;
466         DIR     *dirp;
467         struct  dirent  *dp = NULL;
468         int     suffixLen;
469         int     nameLen;
470         char    *file_suffix;
471         char    *next_path;
472         char    *suffix = ".dt";
473         int     i;
474         char    *cur_dir = getcwd(0,MAXPATHLEN);
475         struct  stat    buf;
476
477         _Xreaddirparams dirEntryBuf;
478         struct dirent *result;
479
480         for(i = 0; dirs->paths[i] ; i++)
481         {
482                 if(chdir(dirs->paths[i]) == -1)
483                 {
484                         continue;
485                 }
486                 dirp = opendir (".");
487                 while ((result = _XReaddir(dirp, dirEntryBuf)) != NULL)
488                 {
489                         if ((int)strlen (result->d_name) >= (int)strlen(suffix))
490                         {
491                                 suffixLen = DtCharCount(suffix);
492                                 nameLen = DtCharCount(result->d_name);
493                                 file_suffix = (char *)_DtGetNthChar(result->d_name,
494                                                 nameLen - suffixLen);
495                                 stat(result->d_name, &buf);
496                                 if (file_suffix &&
497                                         (strcmp(file_suffix, suffix) == 0) &&
498                                         (buf.st_mode&S_IFREG))
499                                 {
500                                         char *c = dirs->paths[i];
501                                         while(*c)
502                                         {
503                                                 pathhash += (int)*c;
504                                                 c++;
505                                         }
506                                         break;
507                                 }
508                         }
509                 }
510                 closedir(dirp);
511         }
512         chdir(cur_dir);
513         free(cur_dir);
514         return(pathhash);
515 }
516
517 char *
518 _DtDtsMMCacheName(int override)
519 {
520         char    *dsp = getenv("DISPLAY");
521         char    *results = 0;
522         char    *c;
523
524         if(override && dsp)
525         {
526                 results = malloc(strlen(_DTDTSMMTEMPDIR)+
527                                  strlen(_DTDTSMMTEMPFILE)+
528                                 strlen(dsp)+3);
529                 sprintf(results, "%s/%s%s\0",
530                                 _DTDTSMMTEMPDIR,
531                                 _DTDTSMMTEMPFILE,
532                                 dsp);
533                 c = strchr(results, ':');
534                 c = strchr(c, '.');
535                 if(c)
536                 {
537                         *c = '\0';
538                 }
539         }
540         else
541         {
542         /* tempnam(3) is affected by the TMPDIR environment variable. */
543         /* This creates problems for rename() if "tmpfile" and "cacheFile" */
544         /* are on different file systems.  Use tmpnam(3) to create the */
545         /* unique file name instead. */
546                 char tmpnam_buf[L_tmpnam + 1];
547
548                 results = (char *)malloc(sizeof(_DTDTSMMTEMPDIR) +
549                                          sizeof(_DTDTSMMTEMPFILE) +
550                                          L_tmpnam + 3);
551                 tmpnam(tmpnam_buf);
552                 sprintf(results, "%s/%s%s", _DTDTSMMTEMPDIR, _DTDTSMMTEMPFILE,
553                         basename(tmpnam_buf));
554         }
555         return(results);
556 }
557
558
559 int
560 _DtDtsMMapDB(const char *CacheFile)
561 {
562         struct  stat    buf;
563         int     success = FALSE;
564
565         _DtSvcProcessLock();
566
567         if (mmaped_fd > 0)
568         {
569                 /* Already have a file memory-mapped.  Unload it. */
570                 _DtDtsMMUnLoad();
571         }
572
573         mmaped_fd  = open(CacheFile, O_RDONLY, 0400);
574         if(mmaped_fd !=  -1)
575         {
576                 if(fstat(mmaped_fd, &buf) == 0 && buf.st_uid == getuid())
577                 {
578                         mmaped_db = (char *)mmap(NULL,
579                                         buf.st_size,
580                                         PROT_READ,
581 #if defined(sun) || defined(USL)
582                                         /* MAP_NORESERVE is only supported
583                                            on sun and novell platforms */
584                                         MAP_SHARED|MAP_NORESERVE,
585 #else
586                                         MAP_SHARED,
587 #endif
588                                         mmaped_fd,
589                                         NULL);
590                         if(mmaped_db != (void *) -1)
591                         {
592                                 success = TRUE;
593                                 mmaped_size = buf.st_size;
594                                 head = (DtDtsMMHeader *)mmaped_db;
595                                 db_list = (DtDtsMMDatabase *)_DtDtsMMGetPtr(head->db_offset);
596                         }
597                         else
598                         {
599                             _DtSimpleError(
600                                         DtProgName, DtError, NULL,
601                                         (char*) CacheFile, NULL);
602                         }
603                 }
604         }
605         if(!success)
606         {
607                 mmaped_db = 0;
608         }
609         _DtSvcProcessUnlock();
610         return(success);
611 }
612
613 static int
614 MMValidateDb(DtDirPaths *dirs, char *suffix)
615 {
616         DIR                     *dirp;
617         struct dirent           *direntp;
618         struct stat             buf;
619         struct stat             new_buf;
620         int                     size = sizeof(buf.st_mtime);
621         DtShmBoson              *boson_list = 0;
622         time_t                  *mtime_list;
623         int                     count = 0;
624         int                     i;
625         const char              *file;
626         int                     pathhash = _DtDtsMMPathHash(dirs);
627
628         _DtSvcProcessLock();
629         if(head->pathhash != pathhash)
630         {
631                 _DtSvcProcessUnlock();
632                 return(0);
633         }
634
635         count = head->files_count;
636         mtime_list = _DtDtsMMGetPtr(head->mtimes_offset);
637         boson_list = _DtDtsMMGetPtr(head->files_offset);
638
639         for(i = 0; i < count; i++)
640         {
641                 file = _DtDtsMMBosonToString(boson_list[i]);
642                 stat(file, &buf);
643                 if(mtime_list[i]  != buf.st_mtime)
644                 {
645                         _DtSvcProcessUnlock();
646                         return(0);
647                 }
648         }
649
650         _DtSvcProcessUnlock();
651         return(1);
652
653 }
654
655 char *
656 _DtDtsMMExpandValue(const char *value)
657 {
658         char *newval;
659
660         if(!value)
661         {
662                 return NULL;
663         }
664         newval = (char *)malloc(1024);
665
666         strcpy(newval, value);
667         _DtDbFillVariables(&newval);
668         return(newval);
669 }
670
671 void
672 _DtDtsMMSafeFree(char *value)
673 {
674         if(value && !_DtDtsMMIsMemory(value))
675         {
676                 free(value);
677         }
678 }
679
680 int
681 _DtDtsMMIsMemory(const char *value)
682 {
683         _DtSvcProcessLock();
684         if((caddr_t)value < mmaped_db || (caddr_t)value > mmaped_db+mmaped_size)
685         {
686                 _DtSvcProcessUnlock();
687                 return(0);
688         }
689         else
690         {
691                 _DtSvcProcessUnlock();
692                 return(1);
693         }
694 }
695
696 int
697 _DtDtsMMUnLoad()
698 {
699         int     error = 0;
700
701         _DtSvcProcessLock();
702         _DtDtsClear();
703         if(mmaped_db == 0)
704         {
705                 _DtSvcProcessUnlock();
706                 return(error);
707         }
708         if(munmap(mmaped_db, mmaped_size) == -1)
709         {
710                 _DtSimpleError(DtProgName, DtError, NULL,
711                                "munmap of dts_cache file", NULL);
712                 error = -1;
713         }
714         if(close(mmaped_fd) == -1)
715         {
716                 _DtSimpleError(DtProgName, DtError, NULL,
717                                "close of dts_cache file", NULL);
718         }
719
720         db_list = 0;
721         mmaped_db = 0;
722         mmaped_size = 0;
723         mmaped_fd = 0;
724         head = 0;
725         _DtSvcProcessUnlock();
726         return(error);
727 }
728
729 #include "Dt/UserMsg.h"
730
731 static int
732 _debug_print_name(char *name, char *label)
733 {
734 #ifdef DEBUG
735         static char     *db = (char *)-1;
736
737         _DtSvcProcessLock();
738         if(db == (char *)-1)
739         {
740                 db = getenv("MMAP_DEBUG");
741         }
742         _DtSvcProcessUnlock();
743
744         if(db)
745                 _DtSimpleError(db,
746                         DtInformation,
747                         NULL,
748                         "%s - db name = %s\n", label,
749                         name);
750 #endif /* DEBUG */
751         return(0);
752 }