registry.c revision 706f2543
1/************************************************************
2
3Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7this permission notice appear in supporting documentation.  This permission
8notice shall be included in all copies or substantial portions of the
9Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
14AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
18********************************************************/
19
20#ifdef HAVE_DIX_CONFIG_H
21#include <dix-config.h>
22#endif
23
24#ifdef XREGISTRY
25
26#include <stdlib.h>
27#include <string.h>
28#include <X11/X.h>
29#include <X11/Xproto.h>
30#include "resource.h"
31#include "registry.h"
32
33#define BASE_SIZE 16
34#define CORE "X11"
35#define FILENAME SERVER_MISC_CONFIG_PATH "/protocol.txt"
36
37#define PROT_COMMENT '#'
38#define PROT_REQUEST 'R'
39#define PROT_EVENT 'V'
40#define PROT_ERROR 'E'
41
42static FILE *fh;
43
44static char ***requests, **events, **errors, **resources;
45static unsigned nmajor, *nminor, nevent, nerror, nresource;
46
47/*
48 * File parsing routines
49 */
50static int double_size(void *p, unsigned n, unsigned size)
51{
52    char **ptr = (char **)p;
53    unsigned s, f;
54
55    if (n) {
56	s = n * size;
57	n *= 2 * size;
58	f = n;
59    } else {
60	s = 0;
61	n = f = BASE_SIZE * size;
62    }
63
64    *ptr = realloc(*ptr, n);
65    if (!*ptr) {
66	dixResetRegistry();
67	return FALSE;
68    }
69    memset(*ptr + s, 0, f - s);
70    return TRUE;
71}
72
73static void
74RegisterRequestName(unsigned major, unsigned minor, char *name)
75{
76    while (major >= nmajor) {
77	if (!double_size(&requests, nmajor, sizeof(char **)))
78	    return;
79	if (!double_size(&nminor, nmajor, sizeof(unsigned)))
80	    return;
81	nmajor = nmajor ? nmajor * 2 : BASE_SIZE;
82    }
83    while (minor >= nminor[major]) {
84	if (!double_size(requests+major, nminor[major], sizeof(char *)))
85	    return;
86	nminor[major] = nminor[major] ? nminor[major] * 2 : BASE_SIZE;
87    }
88
89    free(requests[major][minor]);
90    requests[major][minor] = name;
91}
92
93static void
94RegisterEventName(unsigned event, char *name) {
95    while (event >= nevent) {
96	if (!double_size(&events, nevent, sizeof(char *)))
97	    return;
98	nevent = nevent ? nevent * 2 : BASE_SIZE;
99    }
100
101    free(events[event]);
102    events[event] = name;
103}
104
105static void
106RegisterErrorName(unsigned error, char *name) {
107    while (error >= nerror) {
108	if (!double_size(&errors, nerror, sizeof(char *)))
109	    return;
110	nerror = nerror ? nerror * 2 : BASE_SIZE;
111    }
112
113    free(errors[error]);
114    errors[error] = name;
115}
116
117void
118RegisterExtensionNames(ExtensionEntry *extEntry)
119{
120    char buf[256], *lineobj, *ptr;
121    unsigned offset;
122
123    if (fh == NULL)
124	return;
125
126    rewind(fh);
127
128    while (fgets(buf, sizeof(buf), fh)) {
129	lineobj = NULL;
130	ptr = strchr(buf, '\n');
131	if (ptr)
132	    *ptr = 0;
133
134	/* Check for comments or empty lines */
135	switch (buf[0]) {
136	case PROT_REQUEST:
137	case PROT_EVENT:
138	case PROT_ERROR:
139	    break;
140	case PROT_COMMENT:
141	case '\0':
142	    continue;
143	default:
144	    goto invalid;
145	}
146
147	/* Check for space character in the fifth position */
148	ptr = strchr(buf, ' ');
149	if (!ptr || ptr != buf + 4)
150	    goto invalid;
151
152	/* Duplicate the string after the space */
153	lineobj = strdup(ptr + 1);
154	if (!lineobj)
155	    continue;
156
157	/* Check for a colon somewhere on the line */
158	ptr = strchr(buf, ':');
159	if (!ptr)
160	    goto invalid;
161
162	/* Compare the part before colon with the target extension name */
163	*ptr = 0;
164	if (strcmp(buf + 5, extEntry->name))
165	    goto skip;
166
167	/* Get the opcode for the request, event, or error */
168	offset = strtol(buf + 1, &ptr, 10);
169	if (offset == 0 && ptr == buf + 1)
170	    goto invalid;
171
172	/* Save the strdup result in the registry */
173	switch(buf[0]) {
174	case PROT_REQUEST:
175	    if (extEntry->base)
176		RegisterRequestName(extEntry->base, offset, lineobj);
177	    else
178		RegisterRequestName(offset, 0, lineobj);
179	    continue;
180	case PROT_EVENT:
181	    RegisterEventName(extEntry->eventBase + offset, lineobj);
182	    continue;
183	case PROT_ERROR:
184	    RegisterErrorName(extEntry->errorBase + offset, lineobj);
185	    continue;
186	}
187
188    invalid:
189	LogMessage(X_WARNING, "Invalid line in " FILENAME ", skipping\n");
190    skip:
191	free(lineobj);
192    }
193}
194
195/*
196 * Registration functions
197 */
198
199void
200RegisterResourceName(RESTYPE resource, char *name)
201{
202    resource &= TypeMask;
203
204    while (resource >= nresource) {
205	if (!double_size(&resources, nresource, sizeof(char *)))
206	    return;
207	nresource = nresource ? nresource * 2 : BASE_SIZE;
208    }
209
210    resources[resource] = name;
211}
212
213/*
214 * Lookup functions
215 */
216
217const char *
218LookupRequestName(int major, int minor)
219{
220    if (major >= nmajor)
221	return XREGISTRY_UNKNOWN;
222    if (minor >= nminor[major])
223	return XREGISTRY_UNKNOWN;
224
225    return requests[major][minor] ? requests[major][minor] : XREGISTRY_UNKNOWN;
226}
227
228const char *
229LookupMajorName(int major)
230{
231    if (major < 128) {
232	const char *retval;
233
234	if (major >= nmajor)
235	    return XREGISTRY_UNKNOWN;
236	if (0 >= nminor[major])
237	    return XREGISTRY_UNKNOWN;
238
239	retval = requests[major][0];
240	return retval ? retval + sizeof(CORE) : XREGISTRY_UNKNOWN;
241    } else {
242	ExtensionEntry *extEntry = GetExtensionEntry(major);
243	return extEntry ? extEntry->name : XREGISTRY_UNKNOWN;
244    }
245}
246
247const char *
248LookupEventName(int event)
249{
250    event &= 127;
251    if (event >= nevent)
252	return XREGISTRY_UNKNOWN;
253
254    return events[event] ? events[event] : XREGISTRY_UNKNOWN;
255}
256
257const char *
258LookupErrorName(int error)
259{
260    if (error >= nerror)
261	return XREGISTRY_UNKNOWN;
262
263    return errors[error] ? errors[error] : XREGISTRY_UNKNOWN;
264}
265
266const char *
267LookupResourceName(RESTYPE resource)
268{
269    resource &= TypeMask;
270    if (resource >= nresource)
271	return XREGISTRY_UNKNOWN;
272
273    return resources[resource] ? resources[resource] : XREGISTRY_UNKNOWN;
274}
275
276/*
277 * Setup and teardown
278 */
279void
280dixResetRegistry(void)
281{
282    ExtensionEntry extEntry;
283
284    /* Free all memory */
285    while (nmajor--) {
286	while (nminor[nmajor])
287	    free(requests[nmajor][--nminor[nmajor]]);
288	free(requests[nmajor]);
289    }
290    free(requests);
291    free(nminor);
292
293    while (nevent--)
294	free(events[nevent]);
295    free(events);
296
297    while (nerror--)
298	free(errors[nerror]);
299    free(errors);
300
301    free(resources);
302
303    requests = NULL;
304    nminor = NULL;
305    events = NULL;
306    errors = NULL;
307    resources = NULL;
308
309    nmajor = nevent = nerror = nresource = 0;
310
311    /* Open the protocol file */
312    if (fh)
313	fclose(fh);
314    fh = fopen(FILENAME, "r");
315    if (!fh)
316	LogMessage(X_WARNING, "Failed to open protocol names file " FILENAME "\n");
317
318    /* Add built-in resources */
319    RegisterResourceName(RT_NONE, "NONE");
320    RegisterResourceName(RT_WINDOW, "WINDOW");
321    RegisterResourceName(RT_PIXMAP, "PIXMAP");
322    RegisterResourceName(RT_GC, "GC");
323    RegisterResourceName(RT_FONT, "FONT");
324    RegisterResourceName(RT_CURSOR, "CURSOR");
325    RegisterResourceName(RT_COLORMAP, "COLORMAP");
326    RegisterResourceName(RT_CMAPENTRY, "COLORMAP ENTRY");
327    RegisterResourceName(RT_OTHERCLIENT, "OTHER CLIENT");
328    RegisterResourceName(RT_PASSIVEGRAB, "PASSIVE GRAB");
329
330    /* Add the core protocol */
331    memset(&extEntry, 0, sizeof(extEntry));
332    extEntry.name = CORE;
333    RegisterExtensionNames(&extEntry);
334}
335
336#endif /* XREGISTRY */
337