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