Various DPMI fixes and preliminary DPMI raw mode switch handler.
[wine] / loader / loadorder.c
1 /*
2  * Module/Library loadorder
3  *
4  * Copyright 1999 Bertho Stultiens
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10
11 #include "config.h"
12 #include "windef.h"
13 #include "options.h"
14 #include "loadorder.h"
15 #include "heap.h"
16 #include "options.h"
17 #include "module.h"
18 #include "elfdll.h"
19 #include "debug.h"
20
21 DEFAULT_DEBUG_CHANNEL(module)
22
23
24 /* #define DEBUG_LOADORDER */
25
26 #define LOADORDER_ALLOC_CLUSTER 32      /* Allocate with 32 entries at a time */
27
28 static module_loadorder_t default_loadorder;
29 static module_loadorder_t *module_loadorder = NULL;
30 static int nmodule_loadorder = 0;
31 static int nmodule_loadorder_alloc = 0;
32
33 static struct tagDllOverride {
34         char *key,*value;
35 } DefaultDllOverrides[] = {
36         {"kernel32,gdi32,user32",       "builtin"},
37         {"kernel,gdi,user",             "builtin"},
38         {"toolhelp",                    "builtin"},
39         {"comdlg32,commdlg",            "elfdll,builtin,native"},
40         {"version,ver",                 "elfdll,builtin,native"},
41         {"shell32,shell",               "builtin,native"},
42         {"lz32,lzexpand",               "builtin,native"},
43         {"commctrl,comctl32",           "builtin,native"},
44         {"wsock32,winsock",             "builtin"},
45         {"advapi32,crtdll,ntdll",       "builtin,native"},
46         {"mpr,winspool",                "builtin,native"},
47         {"ddraw,dinput,dsound",         "builtin,native"},
48         {"winmm, mmsystem",             "builtin"},
49         {"msvideo, msvfw32",            "builtin, native"},
50         {"mcicda.drv, mciseq.drv",      "builtin, native"},
51         {"mciwave.drv",                 "builtin, native"},
52         {"mciavi.drv, mcianim.drv",     "native, builtin"},
53         {"w32skrnl",                    "builtin"},
54         {"wnaspi32,wow32",              "builtin"},
55         {"system,display,wprocs ",      "builtin"},
56         {"wineps",                      "builtin"},
57         /* we have to use libglide2x.so instead of glide2x.dll ... */
58         {"glide2x",                     "so,native"},
59         {NULL,NULL},
60 };
61
62 /***************************************************************************
63  *      cmp_sort_func   (internal, static)
64  *
65  * Sorting and comparing function used in sort and search of loadorder
66  * entries.
67  */
68 static int cmp_sort_func(const void *s1, const void *s2)
69 {
70         return strcasecmp(((module_loadorder_t *)s1)->modulename, ((module_loadorder_t *)s2)->modulename);
71 }
72
73
74 /***************************************************************************
75  *      get_tok (internal, static)
76  *
77  * strtok wrapper for non-destructive buffer writing.
78  * NOTE: strtok is not reentrant and therefore this code is neither.
79  */
80 static char *get_tok(const char *str, const char *delim)
81 {
82         static char *buf = NULL;
83         char *cptr;
84
85         if(!str && !buf)
86                 return NULL;
87
88         if(str && buf)
89         {
90                 HeapFree(SystemHeap, 0, buf);
91                 buf = NULL;
92         }
93
94         if(str && !buf)
95         {
96                 buf = HEAP_strdupA(SystemHeap, 0, str);
97                 cptr = strtok(buf, delim);
98         }
99         else
100         {
101                 cptr = strtok(NULL, delim);
102         }
103
104         if(!cptr)
105         {
106                 HeapFree(SystemHeap, 0, buf);
107                 buf = NULL;
108         }
109         return cptr;
110 }
111
112
113 /***************************************************************************
114  *      ParseLoadOrder  (internal, static)
115  *
116  * Parses the loadorder options from the configuration and puts it into
117  * a structure.
118  */
119 static BOOL ParseLoadOrder(char *order, module_loadorder_t *mlo)
120 {
121         char *cptr;
122         int n = 0;
123
124         memset(mlo->loadorder, 0, sizeof(mlo->loadorder));
125
126         cptr = get_tok(order, ", \t");
127         while(cptr)
128         {
129                 char type = MODULE_LOADORDER_INVALID;
130
131                 if(n >= MODULE_LOADORDER_NTYPES)
132                 {
133                         ERR(module, "More than existing %d module-types specified, rest ignored", MODULE_LOADORDER_NTYPES);
134                         break;
135                 }
136
137                 switch(*cptr)
138                 {
139                 case 'N':       /* Native */
140                 case 'n': type = MODULE_LOADORDER_DLL; break;
141
142                 case 'E':       /* Elfdll */
143                 case 'e': type = MODULE_LOADORDER_ELFDLL; break;
144
145                 case 'S':       /* So */
146                 case 's': type = MODULE_LOADORDER_SO; break;
147
148                 case 'B':       /* Builtin */
149                 case 'b': type = MODULE_LOADORDER_BI; break;
150
151                 default:
152                         ERR(module, "Invalid load order module-type '%s', ignored\n", cptr);
153                 }
154
155                 if(type != MODULE_LOADORDER_INVALID)
156                 {
157                         mlo->loadorder[n++] = type;
158                 }
159                 cptr = get_tok(NULL, ", \t");
160         }
161         return TRUE;
162 }
163
164
165 /***************************************************************************
166  *      AddLoadOrder    (internal, static)
167  *
168  * Adds an entry in the list of overrides. If the entry exists then the
169  * override parameter determines whether it will be overwriten.
170  */
171 static BOOL AddLoadOrder(module_loadorder_t *plo, BOOL override)
172 {
173         int i;
174
175         /* TRACE(module, "'%s' -> %08lx\n", plo->modulename, *(DWORD *)(plo->loadorder)); */
176
177         for(i = 0; i < nmodule_loadorder; i++)
178         {
179                 if(!cmp_sort_func(plo, &module_loadorder[i]))
180                 {
181                         if(!override)
182                                 ERR(module, "Module '%s' is already in the list of overrides, using first definition\n", plo->modulename);
183                         else
184                                 memcpy(module_loadorder[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
185                         return TRUE;
186                 }
187         }
188
189         if(nmodule_loadorder >= nmodule_loadorder_alloc)
190         {
191                 /* No space in current array, make it larger */
192                 nmodule_loadorder_alloc += LOADORDER_ALLOC_CLUSTER;
193                 module_loadorder = (module_loadorder_t *)HeapReAlloc(SystemHeap,
194                                                                      0,
195                                                                      module_loadorder,
196                                                                      nmodule_loadorder_alloc * sizeof(module_loadorder_t));
197                 if(!module_loadorder)
198                 {
199                         MSG("Virtual memory exhausted\n");
200                         exit(1);
201                 }
202         }
203         memcpy(module_loadorder[nmodule_loadorder].loadorder, plo->loadorder, sizeof(plo->loadorder));
204         module_loadorder[nmodule_loadorder].modulename = HEAP_strdupA(SystemHeap, 0, plo->modulename);
205         nmodule_loadorder++;
206         return TRUE;
207 }
208
209
210 /***************************************************************************
211  *      AddLoadOrderSet (internal, static)
212  *
213  * Adds an set of entries in the list of overrides from the key parameter.
214  * If the entry exists then the override parameter determines whether it
215  * will be overwriten.
216  */
217 static BOOL AddLoadOrderSet(char *key, char *order, BOOL override)
218 {
219         module_loadorder_t ldo;
220         char *cptr;
221
222         /* Parse the loadorder before the rest because strtok is not reentrant */
223         if(!ParseLoadOrder(order, &ldo))
224                 return FALSE;
225
226         cptr = get_tok(key, ", \t");
227         while(cptr)
228         {
229                 char *ext = strrchr(cptr, '.');
230                 if(ext)
231                 {
232                         if(strlen(ext) == 4 && (!strcasecmp(ext, ".dll") || !strcasecmp(ext, ".exe")))
233                                 MSG("Warning: Loadorder override '%s' contains an extension and might not be found during lookup\n", cptr);
234                 }
235
236                 ldo.modulename = cptr;
237                 if(!AddLoadOrder(&ldo, override))
238                         return FALSE;
239                 cptr = get_tok(NULL, ", \t");
240         }
241         return TRUE;
242 }
243
244
245 /***************************************************************************
246  *      ParseCommandlineOverrides       (internal, static)
247  *
248  * The commandline is in the form:
249  * name[,name,...]=native[,b,...][:...]
250  */
251 static BOOL ParseCommandlineOverrides(void)
252 {
253         char *cpy;
254         char *key;
255         char *next;
256         char *value;
257         BOOL retval = TRUE;
258
259         if(!Options.dllFlags)
260                 return TRUE;
261
262         cpy = HEAP_strdupA(SystemHeap, 0, Options.dllFlags);
263         key = cpy;
264         next = key;
265         for(; next; key = next)
266         {
267                 next = strchr(key, ':');
268                 if(next)
269                 {
270                         *next = '\0';
271                         next++;
272                 }
273                 value = strchr(key, '=');
274                 if(!value)
275                 {
276                         retval = FALSE;
277                         goto endit;
278                 }
279                 *value = '\0';
280                 value++;
281
282                 TRACE(module, "Commandline override '%s' = '%s'\n", key, value);
283                 
284                 if(!AddLoadOrderSet(key, value, TRUE))
285                 {
286                         retval = FALSE;
287                         goto endit;
288                 }
289         }
290 endit:
291         HeapFree(SystemHeap, 0, cpy);
292         return retval;;
293 }
294
295
296 /***************************************************************************
297  *      MODULE_InitLoadOrder    (internal)
298  *
299  * Initialize the load order from the wine.conf file.
300  * The section has tyhe following format:
301  * Section:
302  *      [DllDefaults]
303  *
304  * Keys:
305  *      EXTRA_LD_LIBRARY_PATH=/usr/local/lib/wine[:/more/path/to/search[:...]]
306  * The path will be appended to any existing LD_LIBRARY_PATH from the 
307  * environment (see note in code below).
308  *
309  *      DefaultLoadOrder=native,elfdll,so,builtin
310  * A comma seperated list of module-types to try to load in that specific
311  * order. The DefaultLoadOrder key is used as a fallback when a module is
312  * not specified explicitely. If the DefaultLoadOrder key is not found, 
313  * then the order "dll,elfdll,so,bi" is used
314  * The possible module-types are:
315  *      - native        Native windows dll files
316  *      - elfdll        Dlls encapsulated in .so libraries
317  *      - so            Native .so libraries mapped to dlls
318  *      - builtin       Built-in modules
319  *
320  * Case is not important and only the first letter of each type is enough to
321  * identify the type n[ative], e[lfdll], s[o], b[uiltin]. Also whitespace is
322  * ignored.
323  * E.g.:
324  *      n,el    ,s , b
325  * is equal to:
326  *      native,elfdll,so,builtin
327  *
328  * Section:
329  *      [DllOverrides]
330  *
331  * Keys:
332  * There are no explicit keys defined other than module/library names. A comma
333  * separated list of modules is followed by an assignment of the load-order
334  * for these specific modules. See above for possible types. You should not
335  * specify an extension.
336  * Examples:
337  * kernel32, gdi32, user32 = builtin
338  * kernel, gdi, user = builtin
339  * comdlg32 = elfdll, native, builtin
340  * commdlg = native, builtin
341  * version, ver = elfdll, native, builtin
342  *
343  * Section:
344  *      [DllPairs]
345  *
346  * Keys:
347  * This is a simple pairing in the form 'name1 = name2'. It is supposed to
348  * identify the dlls that cannot live without eachother unless they are
349  * loaded in the same format. Examples are common dialogs and controls,
350  * shell, kernel, gdi, user, etc...
351  * The code will issue a warning if the loadorder of these pairs are different
352  * and might cause hard-to-find bugs due to incompatible pairs loaded at
353  * run-time. Note that this pairing gives *no* guarantee that the pairs
354  * actually get loaded as the same type, nor that the correct versions are
355  * loaded (might be implemented later). It merely notes obvious trouble.
356  * Examples:
357  * kernel = kernel32
358  * commdlg = comdlg32
359  *
360  */
361
362 #define BUFFERSIZE      1024
363
364 BOOL MODULE_InitLoadOrder(void)
365 {
366         char buffer[BUFFERSIZE];
367         int nbuffer;
368
369 #if defined(HAVE_DL_API)
370         /* Get/set the new LD_LIBRARY_PATH */
371         nbuffer = PROFILE_GetWineIniString("DllDefaults", "EXTRA_LD_LIBRARY_PATH", "", buffer, sizeof(buffer));
372
373         if(nbuffer)
374         {
375                 extra_ld_library_path = HEAP_strdupA(SystemHeap, 0, buffer);
376                 TRACE(module, "Setting extra LD_LIBRARY_PATH=%s\n", buffer);
377         }
378 #endif
379
380         /* Get the default load order */
381         nbuffer = PROFILE_GetWineIniString("DllDefaults", "DefaultLoadOrder", "n,e,s,b", buffer, sizeof(buffer));
382         if(!nbuffer)
383         {
384                 MSG("MODULE_InitLoadOrder: misteriously read nothing from default loadorder\n");
385                 return FALSE;
386         }
387
388         TRACE(module, "Setting default loadorder=%s\n", buffer);
389
390         if(!ParseLoadOrder(buffer, &default_loadorder))
391                 return FALSE;
392         default_loadorder.modulename = "<none>";
393
394         {
395             int i;
396             for (i=0;DefaultDllOverrides[i].key;i++)
397                 AddLoadOrderSet(
398                     DefaultDllOverrides[i].key,
399                     DefaultDllOverrides[i].value,
400                     FALSE
401                 );
402         }
403
404         /* Read the explicitely defined orders for specific modules as an entire section */
405         nbuffer = PROFILE_GetWineIniString("DllOverrides", NULL, "", buffer, sizeof(buffer));
406         if(nbuffer == BUFFERSIZE-2)
407         {
408                 ERR(module, "BUFFERSIZE %d is too small to read [DllOverrides]. Needs to grow in the source\n", BUFFERSIZE);
409                 return FALSE;
410         }
411         if(nbuffer)
412         {
413                 /* We only have the keys in the buffer, not the values */
414                 char *key;
415                 char value[BUFFERSIZE];
416                 char *next;
417
418                 for(key = buffer; *key; key = next)
419                 {
420                         next = key + strlen(key) + 1;
421
422                         nbuffer = PROFILE_GetWineIniString("DllOverrides", key, "", value, sizeof(value));
423                         if(!nbuffer)
424                         {
425                                 ERR(module, "Module(s) '%s' will always fail to load. Are you sure you want this?\n", key);
426                                 value[0] = '\0';        /* Just in case */
427                         }
428                         if(nbuffer == BUFFERSIZE-2)
429                         {
430                                 ERR(module, "BUFFERSIZE %d is too small to read [DllOverrides] key '%s'. Needs to grow in the source\n", BUFFERSIZE, key);
431                                 return FALSE;
432                         }
433
434                         TRACE(module, "Key '%s' uses override '%s'\n", key, value);
435
436                         if(!AddLoadOrderSet(key, value, TRUE))
437                                 return FALSE;
438                 }
439         }
440
441         /* Add the commandline overrides to the pool */
442         if(!ParseCommandlineOverrides())
443         {
444                 MSG(    "Syntax: -dll name[,name[,...]]={native|elfdll|so|builtin}[,{n|e|s|b}[,...]][:...]\n"
445                         "    - 'name' is the name of any dll without extension\n"
446                         "    - the order of loading (native, elfdll, so and builtin) can be abbreviated\n"
447                         "      with the first letter\n"
448                         "    - different loadorders for different dlls can be specified by seperating the\n"
449                         "      commandline entries with a ':'\n"
450                         "    Example:\n"
451                         "    -dll comdlg32,commdlg=n:shell,shell32=b\n"
452                    );
453                 return FALSE;
454         }
455
456         /* Sort the array for quick lookup */
457         qsort(module_loadorder, nmodule_loadorder, sizeof(module_loadorder[0]), cmp_sort_func);
458
459         /* Check the pairs of dlls */
460         nbuffer = PROFILE_GetWineIniString("DllPairs", NULL, "", buffer, sizeof(buffer));
461         if(nbuffer == BUFFERSIZE-2)
462         {
463                 ERR(module, "BUFFERSIZE %d is too small to read [DllPairs]. Needs to grow in the source\n", BUFFERSIZE);
464                 return FALSE;
465         }
466         if(nbuffer)
467         {
468                 /* We only have the keys in the buffer, not the values */
469                 char *key;
470                 char value[BUFFERSIZE];
471                 char *next;
472
473                 for(key = buffer; *key; key = next)
474                 {
475                         module_loadorder_t *plo1, *plo2;
476
477                         next = key + strlen(key) + 1;
478
479                         nbuffer = PROFILE_GetWineIniString("DllPairs", key, "", value, sizeof(value));
480                         if(!nbuffer)
481                         {
482                                 ERR(module, "Module pair '%s' is not associated with another module?\n", key);
483                                 continue;
484                         }
485                         if(nbuffer == BUFFERSIZE-2)
486                         {
487                                 ERR(module, "BUFFERSIZE %d is too small to read [DllPairs] key '%s'. Needs to grow in the source\n", BUFFERSIZE, key);
488                                 return FALSE;
489                         }
490
491                         plo1 = MODULE_GetLoadOrder(key);
492                         plo2 = MODULE_GetLoadOrder(value);
493                         assert(plo1 && plo2);
494
495                         if(memcmp(plo1->loadorder, plo2->loadorder, sizeof(plo1->loadorder)))
496                                 MSG("Warning: Modules '%s' and '%s' have different loadorder which may cause trouble\n", key, value);
497                 }
498         }
499
500         if(TRACE_ON(module))
501         {
502                 int i, j;
503                 static char types[6] = "-NESB";
504
505                 for(i = 0; i < nmodule_loadorder; i++)
506                 {
507                         DPRINTF("%3d: %-12s:", i, module_loadorder[i].modulename);
508                         for(j = 0; j < MODULE_LOADORDER_NTYPES; j++)
509                                 DPRINTF(" %c", types[module_loadorder[i].loadorder[j] % (MODULE_LOADORDER_NTYPES+1)]);
510                         DPRINTF("\n");
511                 }
512         }
513
514         return TRUE;
515 }
516
517
518 /***************************************************************************
519  *      MODULE_GetLoadOrder     (internal)
520  *
521  * Locate the loadorder of a module.
522  * Any path is stripped from the path-argument and so are the extension
523  * '.dll' and '.exe'. A lookup in the table can yield an override for the
524  * specific dll. Otherwise the default load order is returned.
525  */
526 module_loadorder_t *MODULE_GetLoadOrder(const char *path)
527 {
528         module_loadorder_t lo, *tmp;
529         char fname[256];
530         char *cptr;
531         char *name;
532         int len;
533
534         assert(path != NULL);
535
536         /* Strip path information */
537         cptr = strrchr(path, '\\');
538         if(!cptr)
539                 name = strrchr(path, '/');
540         else
541                 name = strrchr(cptr, '/');
542
543         if(!name)
544                 name = cptr ? cptr+1 : (char *)path;
545         else
546                 name++;
547
548         if((cptr = strchr(name, ':')) != NULL)  /* Also strip drive if in format 'C:MODULE.DLL' */
549                 name = cptr+1;
550
551         len = strlen(name);
552         if(len >= sizeof(fname) || len <= 0)
553         {
554                 ERR(module, "Path '%s' -> '%s' reduces to zilch or just too large...\n", path, name);
555                 return &default_loadorder;
556         }
557
558         strcpy(fname, name);
559         if(len >= 4 && (!lstrcmpiA(fname+len-4, ".dll") || !lstrcmpiA(fname+len-4, ".exe")))
560                 fname[len-4] = '\0';
561
562         lo.modulename = fname;
563         tmp = bsearch(&lo, module_loadorder, nmodule_loadorder, sizeof(module_loadorder[0]), cmp_sort_func);
564
565         TRACE(module, "Looking for '%s' (%s), found '%s'\n", path, fname, tmp ? tmp->modulename : "<nothing>");
566
567         if(!tmp)
568                 return &default_loadorder;
569         return tmp;
570 }
571