1 /* $Xorg: restart.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */ 2 /****************************************************************************** 3 4 Copyright 1993, 1998 The Open Group 5 6 Permission to use, copy, modify, distribute, and sell this software and its 7 documentation for any purpose is hereby granted without fee, provided that 8 the above copyright notice appear in all copies and that both that 9 copyright notice and this permission notice appear in supporting 10 documentation. 11 12 The above copyright notice and this permission notice shall be included in 13 all copies or substantial portions of the Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 Except as contained in this notice, the name of The Open Group shall not be 23 used in advertising or otherwise to promote the sale, use or other dealings 24 in this Software without prior written authorization from The Open Group. 25 ******************************************************************************/ 26 /* $XFree86: xc/programs/xsm/restart.c,v 1.5 2001/01/17 23:46:30 dawes Exp $ */ 27 28 #include "xsm.h" 29 #include "log.h" 30 #include "restart.h" 31 #include "saveutil.h" 32 33 34 /* 36 * Until XSMP provides a better way to know which clients are "managers", 37 * we have to hard code the list. 38 */ 39 40 Bool 41 CheckIsManager(char *program) 42 { 43 return (strcmp (program, "twm") == 0); 44 } 45 46 47 48 /* 50 * GetRestartInfo() will determine which method should be used to 51 * restart a client. 52 * 53 * 'restart_service_prop' is a property set by the client, or NULL. 54 * The format is "remote_start_protocol/remote_start_data". An 55 * example is "rstart-rsh/hostname". This is a non-standard property, 56 * which is the whole reason we need this function in order to determine 57 * the restart method. The proxy uses this property to over-ride the 58 * 'client_host_name' from the ICE connection (the proxy is connected to 59 * the SM via a local connection, but the proxy may be acting as a proxy 60 * for a remote client). 61 * 62 * 'client_host_name' is the connection info obtained from the ICE 63 * connection. It's format is "transport/host_info". An example 64 * is "tcp/machine:port". 65 * 66 * If 'restart_service_prop' is NULL, we use 'client_host_name' to 67 * determine the restart method. If the transport is "local", we 68 * do a local restart. Otherwise, we use the default "rstart-rsh" method. 69 * 70 * If 'restart_service_prop' is non-NULL, we check the remote_start_protocol 71 * field. "local" means a local restart. Currently, the only remote 72 * protocol we recognize is "rstart-rsh". If the remote protocol is 73 * "rstart-rsh" but the hostname in the 'restart_service_prop' matches 74 * 'client_host_name', we do a local restart. 75 * 76 * On return, set the run_local flag, restart_protocol and restart_machine. 77 */ 78 79 void 80 GetRestartInfo(char *restart_service_prop, char *client_host_name, 81 Bool *run_local, char **restart_protocol, char **restart_machine) 82 { 83 char hostnamebuf[80]; 84 char *temp; 85 86 *run_local = False; 87 *restart_protocol = NULL; 88 *restart_machine = NULL; 89 90 if (restart_service_prop) 91 { 92 gethostname (hostnamebuf, sizeof hostnamebuf); 93 94 if ((temp = (char *) strchr ( 95 restart_service_prop, '/')) == NULL) 96 { 97 *restart_protocol = (char *) XtNewString ("rstart-rsh"); 98 *restart_machine = (char *) XtNewString (restart_service_prop); 99 } 100 else 101 { 102 *restart_protocol = (char *) XtNewString (restart_service_prop); 103 (*restart_protocol)[temp - restart_service_prop] = '\0'; 104 *restart_machine = (char *) XtNewString (temp + 1); 105 } 106 107 if (strcmp (*restart_machine, hostnamebuf) == 0 || 108 strcmp (*restart_protocol, "local") == 0) 109 { 110 *run_local = True; 111 } 112 } 113 else 114 { 115 if (strncmp (client_host_name, "tcp/", 4) != 0 && 116 strncmp (client_host_name, "decnet/", 7) != 0) 117 { 118 *run_local = True; 119 } 120 else 121 { 122 *restart_protocol = (char *) XtNewString ("rstart-rsh"); 123 124 if ((temp = (char *) strchr ( 125 client_host_name, '/')) == NULL) 126 { 127 *restart_machine = (char *) XtNewString (client_host_name); 128 } 129 else 130 { 131 *restart_machine = (char *) XtNewString (temp + 1); 132 } 133 } 134 } 135 } 136 137 138 139 /* 141 * Restart clients. The flag indicates RESTART_MANAGERS or 142 * RESTART_REST_OF_CLIENTS. 143 */ 144 145 Status 146 Restart(int flag) 147 { 148 List *cl, *pl, *vl; 149 PendingClient *c; 150 Prop *prop; 151 const char *cwd; 152 char *program; 153 char **args; 154 char **env; 155 char **pp; 156 int cnt; 157 char *p; 158 char *restart_service_prop; 159 char *restart_protocol; 160 char *restart_machine; 161 Bool run_local; 162 Bool is_manager; 163 Bool ran_manager = 0; 164 165 for(cl = ListFirst(PendingList); cl; cl = ListNext(cl)) { 166 c = (PendingClient *)cl->thing; 167 168 if (verbose) { 169 printf("Restarting id '%s'...\n", c->clientId); 170 printf("Host = %s\n", c->clientHostname); 171 } 172 cwd = "."; 173 env = NULL; 174 program=NULL; 175 args=NULL; 176 restart_service_prop=NULL; 177 178 is_manager = 0; 179 180 for(pl = ListFirst(c->props); pl; pl = ListNext(pl)) { 181 prop = (Prop *)pl->thing; 182 if(!strcmp(prop->name, SmProgram)) { 183 vl = ListFirst(prop->values); 184 if(vl) program = ((PropValue *)vl->thing)->value; 185 if (CheckIsManager (program)) 186 is_manager = 1; 187 } else if(!strcmp(prop->name, SmCurrentDirectory)) { 188 vl = ListFirst(prop->values); 189 if(vl) cwd = ((PropValue *)vl->thing)->value; 190 } else if(!strcmp(prop->name, "_XC_RestartService")) { 191 vl = ListFirst(prop->values); 192 if(vl) restart_service_prop = 193 ((PropValue *)vl->thing)->value; 194 } else if(!strcmp(prop->name, SmRestartCommand)) { 195 cnt = ListCount(prop->values); 196 args = (char **)XtMalloc((cnt+1) * sizeof(char *)); 197 pp = args; 198 for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { 199 *pp++ = ((PropValue *)vl->thing)->value; 200 } 201 *pp = NULL; 202 } else if(!strcmp(prop->name, SmEnvironment)) { 203 cnt = ListCount(prop->values); 204 env = (char **)XtMalloc((cnt+3+1) * sizeof(char *)); 205 pp = env; 206 for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { 207 p = ((PropValue *)vl->thing)->value; 208 if((display_env && strbw(p, "DISPLAY=")) 209 || (session_env && strbw(p, "SESSION_MANAGER=")) 210 || (audio_env && strbw(p, "AUDIOSERVER=")) 211 ) continue; 212 *pp++ = p; 213 } 214 if(display_env) *pp++ = display_env; 215 if(session_env) *pp++ = session_env; 216 if(audio_env) *pp++ = audio_env; 217 *pp = NULL; 218 } 219 } 220 221 if(program && args) { 222 char logtext[256]; 223 224 if ((flag == RESTART_MANAGERS && !is_manager) || 225 (flag == RESTART_REST_OF_CLIENTS && is_manager)) 226 { 227 if(args) XtFree((char *)args); 228 if(env) XtFree((char *)env); 229 continue; 230 } 231 232 if (flag == RESTART_MANAGERS && is_manager) 233 ran_manager = 1; 234 235 if (verbose) { 236 printf("\t%s\n", program); 237 printf("\t"); 238 for(pp = args; *pp; pp++) printf("%s ", *pp); 239 printf("\n"); 240 } 241 242 GetRestartInfo (restart_service_prop, c->clientHostname, 243 &run_local, &restart_protocol, &restart_machine); 244 245 if (run_local) 246 { 247 /* 248 * The client is being restarted on the local machine. 249 */ 250 251 snprintf (logtext, sizeof(logtext), "Restarting locally : "); 252 for (pp = args; *pp; pp++) 253 { 254 strcat (logtext, *pp); 255 strcat (logtext, " "); 256 } 257 258 strcat (logtext, "\n"); 259 add_log_text (logtext); 260 261 switch(fork()) { 262 case -1: 263 snprintf (logtext, sizeof(logtext), 264 "%s: Can't fork() %s", Argv[0], program); 265 add_log_text (logtext); 266 perror (logtext); 267 break; 268 case 0: /* kid */ 269 chdir(cwd); 270 if(env) environ = env; 271 execvp(program, args); 272 snprintf (logtext, sizeof(logtext), 273 "%s: Can't execvp() %s", Argv[0], program); 274 perror (logtext); 275 /* 276 * TODO : We would like to send this log information to the 277 * log window in the parent. This would require opening 278 * a pipe between the parent and child. The child would 279 * set close-on-exec. If the exec succeeds, the pipe will 280 * be closed. If it fails, the child can write a message 281 * to the parent. 282 */ 283 _exit(255); 284 default: /* parent */ 285 break; 286 } 287 } 288 else if (!remote_allowed) 289 { 290 fprintf(stderr, 291 "Can't remote start client ID '%s': only local supported\n", 292 c->clientId); 293 } 294 else 295 { 296 /* 297 * The client is being restarted on a remote machine. 298 */ 299 300 snprintf (logtext, sizeof(logtext), 301 "Restarting remotely on %s : ", restart_machine); 302 for (pp = args; *pp; pp++) 303 { 304 strcat (logtext, *pp); 305 strcat (logtext, " "); 306 } 307 strcat (logtext, "\n"); 308 add_log_text (logtext); 309 310 remote_start (restart_protocol, restart_machine, 311 program, args, cwd, env, 312 non_local_display_env, non_local_session_env); 313 } 314 315 if (restart_protocol) 316 XtFree (restart_protocol); 317 318 if (restart_machine) 319 XtFree (restart_machine); 320 321 } else { 322 fprintf(stderr, "Can't restart ID '%s': no program or no args\n", 323 c->clientId); 324 } 325 if(args) XtFree((char *)args); 326 if(env) XtFree((char *)env); 327 } 328 329 if (flag == RESTART_MANAGERS && !ran_manager) 330 return (0); 331 else 332 return (1); 333 } 334 335 336 337 /* 339 * Clone a client 340 */ 341 342 void 343 Clone(ClientRec *client, Bool useSavedState) 344 { 345 const char *cwd; 346 char *program; 347 char **args; 348 char **env; 349 char **pp; 350 char *p; 351 char *restart_service_prop; 352 char *restart_protocol; 353 char *restart_machine; 354 Bool run_local; 355 List *pl, *pj; 356 357 if (verbose) 358 { 359 printf ("Cloning id '%s', useSavedState = %d...\n", 360 client->clientId, useSavedState); 361 printf ("Host = %s\n", client->clientHostname); 362 } 363 364 cwd = "."; 365 env = NULL; 366 program = NULL; 367 args = NULL; 368 restart_service_prop = NULL; 369 370 for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) 371 { 372 Prop *pprop = (Prop *) pl->thing; 373 List *vl = ListFirst (pprop->values); 374 PropValue *pval = (PropValue *) vl->thing; 375 376 if (strcmp (pprop->name, SmProgram) == 0) 377 program = (char *) pval->value; 378 else if (strcmp (pprop->name, SmCurrentDirectory) == 0) 379 cwd = (char *) pval->value; 380 else if (strcmp (pprop->name, "_XC_RestartService") == 0) 381 restart_service_prop = (char *) pval->value; 382 else if ( 383 (!useSavedState && strcmp (pprop->name, SmCloneCommand) == 0) || 384 (useSavedState && strcmp (pprop->name, SmRestartCommand) == 0)) 385 { 386 args = (char **) XtMalloc ( 387 (ListCount (pprop->values) + 1) * sizeof (char *)); 388 389 pp = args; 390 391 for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) 392 { 393 pval = (PropValue *) pj->thing; 394 *pp++ = (char *) pval->value; 395 } 396 *pp = NULL; 397 } 398 else if (strcmp (pprop->name, SmEnvironment) == 0) 399 { 400 env = (char **) XtMalloc ( 401 (ListCount (pprop->values) + 3 + 1) * sizeof (char *)); 402 pp = env; 403 404 for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) 405 { 406 pval = (PropValue *) pj->thing; 407 p = (char *) pval->value; 408 409 if ((display_env && strbw (p, "DISPLAY=")) 410 || (session_env && strbw (p, "SESSION_MANAGER=")) 411 || (audio_env && strbw (p, "AUDIOSERVER="))) 412 continue; 413 414 *pp++ = p; 415 } 416 417 if (display_env) 418 *pp++ = display_env; 419 if (session_env) 420 *pp++ = session_env; 421 if (audio_env) 422 *pp++ = audio_env; 423 424 *pp = NULL; 425 } 426 } 427 428 if (program && args) 429 { 430 if (verbose) 431 { 432 printf("\t%s\n", program); 433 printf("\t"); 434 for (pp = args; *pp; pp++) 435 printf ("%s ", *pp); 436 printf("\n"); 437 } 438 439 GetRestartInfo (restart_service_prop, client->clientHostname, 440 &run_local, &restart_protocol, &restart_machine); 441 442 if (run_local) 443 { 444 /* 445 * The client is being cloned on the local machine. 446 */ 447 448 char msg[256]; 449 450 switch(fork()) { 451 case -1: 452 snprintf (msg, sizeof(msg), 453 "%s: Can't fork() %s", Argv[0], program); 454 add_log_text (msg); 455 perror (msg); 456 break; 457 case 0: /* kid */ 458 chdir(cwd); 459 if(env) environ = env; 460 execvp(program, args); 461 snprintf (msg, sizeof(msg), 462 "%s: Can't execvp() %s", Argv[0], program); 463 perror (msg); 464 /* 465 * TODO : We would like to send this log information to the 466 * log window in the parent. This would require opening 467 * a pipe between the parent and child. The child would 468 * set close-on-exec. If the exec succeeds, the pipe will 469 * be closed. If it fails, the child can write a message 470 * to the parent. 471 */ 472 _exit(255); 473 default: /* parent */ 474 break; 475 } 476 } 477 else if (!remote_allowed) 478 { 479 fprintf(stderr, 480 "Can't remote clone client ID '%s': only local supported\n", 481 client->clientId); 482 } 483 else 484 { 485 /* 486 * The client is being cloned on a remote machine. 487 */ 488 489 remote_start (restart_protocol, restart_machine, 490 program, args, cwd, env, 491 non_local_display_env, non_local_session_env); 492 } 493 494 if (restart_protocol) 495 XtFree (restart_protocol); 496 497 if (restart_machine) 498 XtFree (restart_machine); 499 500 } 501 else 502 { 503 #ifdef XKB 504 XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_Failure); 505 #else 506 XBell (XtDisplay (topLevel), 0); 507 #endif 508 509 fprintf(stderr, "Can't restart ID '%s': no program or no args\n", 510 client->clientId); 511 } 512 513 if (args) 514 XtFree ((char *)args); 515 if (env) 516 XtFree ((char *)env); 517 } 518 519 520 521 void 523 StartDefaultApps (void) 524 { 525 FILE *f; 526 char *buf, *p, filename[128]; 527 const char *home; 528 int buflen, len; 529 530 /* 531 * First try ~/.xsmstartup, then system.xsm 532 */ 533 534 home = getenv ("HOME"); 535 if (!home) 536 home = "."; 537 snprintf (filename, sizeof(filename), "%s/.xsmstartup", home); 538 539 f = fopen (filename, "r"); 540 541 if (!f) 542 { 543 f = fopen (SYSTEM_INIT_FILE, "r"); 544 if (!f) 545 { 546 printf ("Could not find default apps file. Make sure you did\n"); 547 printf ("a 'make install' in the xsm build directory.\n"); 548 exit (1); 549 } 550 } 551 fcntl(fileno(f), F_SETFD, FD_CLOEXEC); 552 553 buf = NULL; 554 buflen = 0; 555 556 while (getnextline(&buf, &buflen, f)) 557 { 558 char logtext[256]; 559 560 if (buf[0] == '!') 561 continue; /* a comment */ 562 563 if ((p = strchr (buf, '\n'))) 564 *p = '\0'; 565 566 snprintf (logtext, sizeof(logtext), "Starting locally : %s\n", buf); 567 add_log_text (logtext); 568 569 len = strlen (buf); 570 571 buf[len] = '&'; 572 buf[len+1] = '\0'; 573 574 /* let the shell parse the stupid args */ 575 576 execute_system_command (buf); 577 } 578 579 if (buf) 580 free (buf); 581 } 582 583 584 585 void 587 StartNonSessionAwareApps(void) 588 { 589 char logtext[256]; 590 int i; 591 592 for (i = 0; i < non_session_aware_count; i++) 593 { 594 /* 595 * Let the shell parse the stupid args. We need to add an "&" 596 * at the end of the command. We previously allocated an extra 597 * byte for this. 598 */ 599 600 snprintf (logtext, sizeof(logtext), "Restarting locally : %s\n", 601 non_session_aware_clients[i]); 602 add_log_text (logtext); 603 604 strcat (non_session_aware_clients[i], "&"); 605 execute_system_command (non_session_aware_clients[i]); 606 free ((char *) non_session_aware_clients[i]); 607 } 608 609 if (non_session_aware_clients) 610 { 611 free ((char *) non_session_aware_clients); 612 non_session_aware_clients = NULL; 613 } 614 } 615