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