save.c revision 24047306
1/****************************************************************************** 2 3Copyright 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25Author: Ralph Mor, X Consortium 26******************************************************************************/ 27 28#include "smproxy.h" 29#ifdef HAVE_MKSTEMP 30#include <unistd.h> 31#endif 32 33 34static ProxyFileEntry *proxyFileHead = NULL; 35 36static int write_byte ( FILE *file, unsigned char b ); 37static int write_short ( FILE *file, unsigned short s ); 38static int write_counted_string ( FILE *file, char *string ); 39static int read_byte ( FILE *file, unsigned char *bp ); 40static int read_short ( FILE *file, unsigned short *shortp ); 41static int read_counted_string ( FILE *file, char **stringp ); 42 43#ifndef HAVE_ASPRINTF 44# include <stdarg.h> 45 46/* sprintf variant found in newer libc's which allocates string to print to */ 47_X_HIDDEN int _X_ATTRIBUTE_PRINTF(2,3) 48asprintf(char ** ret, const char *format, ...) 49{ 50 char buf[256]; 51 int len; 52 va_list ap; 53 54 va_start(ap, format); 55 len = vsnprintf(buf, sizeof(buf), format, ap); 56 va_end(ap); 57 58 if (len < 0) 59 return -1; 60 61 if (len < sizeof(buf)) 62 { 63 *ret = strdup(buf); 64 } 65 else 66 { 67 *ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */ 68 if (*ret != NULL) 69 { 70 va_start(ap, format); 71 len = vsnprintf(*ret, len + 1, format, ap); 72 va_end(ap); 73 if (len < 0) { 74 free(*ret); 75 *ret = NULL; 76 } 77 } 78 } 79 80 if (*ret == NULL) 81 return -1; 82 83 return len; 84} 85#endif 86 87 88 89static int 90write_byte (FILE *file, unsigned char b) 91{ 92 if (fwrite ((char *) &b, 1, 1, file) != 1) 93 return 0; 94 return 1; 95} 96 97 98static int 99write_short (FILE *file, unsigned short s) 100{ 101 unsigned char file_short[2]; 102 103 file_short[0] = (s & (unsigned)0xff00) >> 8; 104 file_short[1] = s & 0xff; 105 if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) 106 return 0; 107 return 1; 108} 109 110 111static int 112write_counted_string(FILE *file, char *string) 113{ 114 if (string) 115 { 116 unsigned char count = strlen (string); 117 118 if (write_byte (file, count) == 0) 119 return 0; 120 if (fwrite (string, (int) sizeof (char), (int) count, file) != count) 121 return 0; 122 } 123 else 124 { 125 if (write_byte (file, 0) == 0) 126 return 0; 127 } 128 129 return 1; 130} 131 132 133 134static int 135read_byte(FILE *file, unsigned char *bp) 136{ 137 if (fread ((char *) bp, 1, 1, file) != 1) 138 return 0; 139 return 1; 140} 141 142 143static int 144read_short(FILE *file, unsigned short *shortp) 145{ 146 unsigned char file_short[2]; 147 148 if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) 149 return 0; 150 *shortp = file_short[0] * 256 + file_short[1]; 151 return 1; 152} 153 154 155static int 156read_counted_string(FILE *file, char **stringp) 157{ 158 unsigned char len; 159 char *data; 160 161 if (read_byte (file, &len) == 0) 162 return 0; 163 if (len == 0) { 164 data = NULL; 165 } else { 166 data = (char *) malloc ((unsigned) len + 1); 167 if (!data) 168 return 0; 169 if (fread (data, (int) sizeof (char), (int) len, file) != len) { 170 free (data); 171 return 0; 172 } 173 data[len] = '\0'; 174 } 175 *stringp = data; 176 return 1; 177} 178 179 180 181/* 182 * An entry in the .smproxy file looks like this: 183 * 184 * FIELD BYTES 185 * ----- ---- 186 * client ID len 1 187 * client ID LIST of bytes 188 * WM_CLASS "res name" length 1 189 * WM_CLASS "res name" LIST of bytes 190 * WM_CLASS "res class" length 1 191 * WM_CLASS "res class" LIST of bytes 192 * WM_NAME length 1 193 * WM_NAME LIST of bytes 194 * WM_COMMAND arg count 1 195 * For each arg in WM_COMMAND 196 * arg length 1 197 * arg LIST of bytes 198 */ 199 200int 201WriteProxyFileEntry(FILE *proxyFile, WinInfo *theWindow) 202{ 203 int i; 204 205 if (!write_counted_string (proxyFile, theWindow->client_id)) 206 return 0; 207 if (!write_counted_string (proxyFile, theWindow->class.res_name)) 208 return 0; 209 if (!write_counted_string (proxyFile, theWindow->class.res_class)) 210 return 0; 211 if (!write_counted_string (proxyFile, theWindow->wm_name)) 212 return 0; 213 214 if (!theWindow->wm_command || theWindow->wm_command_count == 0) 215 { 216 if (!write_byte (proxyFile, 0)) 217 return 0; 218 } 219 else 220 { 221 if (!write_byte (proxyFile, (char) theWindow->wm_command_count)) 222 return 0; 223 for (i = 0; i < theWindow->wm_command_count; i++) 224 if (!write_counted_string (proxyFile, theWindow->wm_command[i])) 225 return 0; 226 } 227 228 return 1; 229} 230 231 232int 233ReadProxyFileEntry(FILE *proxyFile, ProxyFileEntry **pentry) 234{ 235 ProxyFileEntry *entry; 236 unsigned char byte; 237 int i; 238 239 *pentry = entry = (ProxyFileEntry *) malloc ( 240 sizeof (ProxyFileEntry)); 241 if (!*pentry) 242 return 0; 243 244 entry->tag = 0; 245 entry->client_id = NULL; 246 entry->class.res_name = NULL; 247 entry->class.res_class = NULL; 248 entry->wm_name = NULL; 249 entry->wm_command = NULL; 250 entry->wm_command_count = 0; 251 252 if (!read_counted_string (proxyFile, &entry->client_id)) 253 goto give_up; 254 if (!read_counted_string (proxyFile, &entry->class.res_name)) 255 goto give_up; 256 if (!read_counted_string (proxyFile, &entry->class.res_class)) 257 goto give_up; 258 if (!read_counted_string (proxyFile, &entry->wm_name)) 259 goto give_up; 260 261 if (!read_byte (proxyFile, &byte)) 262 goto give_up; 263 entry->wm_command_count = byte; 264 265 if (entry->wm_command_count == 0) 266 entry->wm_command = NULL; 267 else 268 { 269 entry->wm_command = (char **) malloc (entry->wm_command_count * 270 sizeof (char *)); 271 272 if (!entry->wm_command) 273 goto give_up; 274 275 for (i = 0; i < entry->wm_command_count; i++) 276 if (!read_counted_string (proxyFile, &entry->wm_command[i])) 277 goto give_up; 278 } 279 280 return 1; 281 282give_up: 283 284 if (entry->client_id) 285 free (entry->client_id); 286 if (entry->class.res_name) 287 free (entry->class.res_name); 288 if (entry->class.res_class) 289 free (entry->class.res_class); 290 if (entry->wm_name) 291 free (entry->wm_name); 292 if (entry->wm_command) 293 { 294 if (entry->wm_command_count) 295 { 296 for (i = 0; i < entry->wm_command_count; i++) 297 if (entry->wm_command[i]) 298 free (entry->wm_command[i]); 299 } 300 free ((char *) entry->wm_command); 301 } 302 303 free ((char *) entry); 304 *pentry = NULL; 305 306 return 0; 307} 308 309 310void 311ReadProxyFile(char *filename) 312{ 313 FILE *proxyFile; 314 ProxyFileEntry *entry; 315 int done = 0; 316 unsigned short version; 317 318 proxyFile = fopen (filename, "rb"); 319 if (!proxyFile) 320 return; 321 322 if (!read_short (proxyFile, &version) || 323 version > SAVEFILE_VERSION) 324 { 325 done = 1; 326 } 327 328 while (!done) 329 { 330 if (ReadProxyFileEntry (proxyFile, &entry)) 331 { 332 entry->next = proxyFileHead; 333 proxyFileHead = entry; 334 } 335 else 336 done = 1; 337 } 338 339 fclose (proxyFile); 340} 341 342 343 344static char * 345unique_filename(const char *path, const char *prefix, int *pFd) 346{ 347 char *tempFile = NULL; 348 int tempFd = 0; 349 350#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP) 351 if (asprintf (&tempFile, "%s/%sXXXXXX", path, prefix) == -1) 352 return NULL; 353#endif 354 355#ifdef HAVE_MKSTEMP 356 tempFd = mkstemp(tempFile); 357#else 358 359# ifdef HAVE_MKTEMP 360 if (mktemp(tempFile) == NULL) 361 tempFd = -1; 362# else /* fallback to tempnam */ 363 tempFile = tempnam (path, prefix); 364# endif /* HAVE_MKTEMP */ 365 366 if (tempFd != -1 && tempFile != NULL) 367 tempFd = open(tempFile, O_RDWR | O_CREAT | O_EXCL, 0600); 368#endif 369 370 if (tempFd == -1) { 371 free(tempFile); 372 return (NULL); 373 } 374 375 *pFd = tempFd; 376 return tempFile; 377 378} 379 380 381 382char * 383WriteProxyFile(void) 384{ 385 FILE *proxyFile = NULL; 386 char *filename = NULL; 387 int fd = -1; 388 const char *path; 389 WinInfo *winptr; 390 Bool success = False; 391 392 path = getenv ("SM_SAVE_DIR"); 393 if (!path) 394 { 395 path = getenv ("HOME"); 396 if (!path) 397 path = "."; 398 } 399 400 if ((filename = unique_filename (path, ".prx", &fd)) == NULL) 401 goto bad; 402 403 if (!(proxyFile = fdopen(fd, "wb"))) 404 goto bad; 405 406 if (!write_short (proxyFile, SAVEFILE_VERSION)) 407 goto bad; 408 409 success = True; 410 winptr = win_head; 411 412 while (winptr && success) 413 { 414 if (winptr->client_id) 415 if (!WriteProxyFileEntry (proxyFile, winptr)) 416 { 417 success = False; 418 break; 419 } 420 421 winptr = winptr->next; 422 } 423 424 bad: 425 426 if (proxyFile) 427 fclose (proxyFile); 428 else if (fd != -1) 429 close (fd); 430 431 if (success) 432 return (filename); 433 else 434 { 435 if (filename) 436 free (filename); 437 return (NULL); 438 } 439} 440 441 442 443char * 444LookupClientID(WinInfo *theWindow) 445{ 446 ProxyFileEntry *ptr; 447 int found = 0; 448 449 ptr = proxyFileHead; 450 while (ptr && !found) 451 { 452 if (!ptr->tag && 453 strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 && 454 strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 && 455 strcmp (theWindow->wm_name, ptr->wm_name) == 0) 456 { 457 int i; 458 459 if (theWindow->wm_command_count == ptr->wm_command_count) 460 { 461 for (i = 0; i < theWindow->wm_command_count; i++) 462 if (strcmp (theWindow->wm_command[i], 463 ptr->wm_command[i]) != 0) 464 break; 465 466 if (i == theWindow->wm_command_count) 467 found = 1; 468 } 469 } 470 471 if (!found) 472 ptr = ptr->next; 473 } 474 475 if (found) 476 { 477 ptr->tag = 1; 478 return (ptr->client_id); 479 } 480 else 481 return NULL; 482} 483