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#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 42static FILE *fh; 43 44static char ***requests, **events, **errors; 45static unsigned nmajor, *nminor, nevent, nerror; 46#endif 47 48#ifdef X_REGISTRY_RESOURCE 49static const char **resources; 50static unsigned nresource; 51#endif 52 53#if defined(X_REGISTRY_RESOURCE) || defined(X_REGISTRY_REQUEST) 54/* 55 * File parsing routines 56 */ 57static int 58double_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 */ 87static void 88RegisterRequestName(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 107static void 108RegisterEventName(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 120static void 121RegisterErrorName(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 133void 134RegisterExtensionNames(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 211const char * 212LookupRequestName(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 222const char * 223LookupMajorName(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 243const char * 244LookupEventName(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 253const char * 254LookupErrorName(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 268void 269RegisterResourceName(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 282const char * 283LookupResourceName(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 293void 294dixFreeRegistry(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 328void 329dixCloseRegistry(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 */ 342void 343dixResetRegistry(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