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