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