restart.c revision 5977a007
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 33 34/* 35 * Until XSMP provides a better way to know which clients are "managers", 36 * we have to hard code the list. 37 */ 38 39Bool 40CheckIsManager(char *program) 41{ 42 return (strcmp (program, "twm") == 0); 43} 44 45 46 47/* 48 * GetRestartInfo() will determine which method should be used to 49 * restart a client. 50 * 51 * 'restart_service_prop' is a property set by the client, or NULL. 52 * The format is "remote_start_protocol/remote_start_data". An 53 * example is "rstart-rsh/hostname". This is a non-standard property, 54 * which is the whole reason we need this function in order to determine 55 * the restart method. The proxy uses this property to over-ride the 56 * 'client_host_name' from the ICE connection (the proxy is connected to 57 * the SM via a local connection, but the proxy may be acting as a proxy 58 * for a remote client). 59 * 60 * 'client_host_name' is the connection info obtained from the ICE 61 * connection. It's format is "transport/host_info". An example 62 * is "tcp/machine:port". 63 * 64 * If 'restart_service_prop' is NULL, we use 'client_host_name' to 65 * determine the restart method. If the transport is "local", we 66 * do a local restart. Otherwise, we use the default "rstart-rsh" method. 67 * 68 * If 'restart_service_prop' is non-NULL, we check the remote_start_protocol 69 * field. "local" means a local restart. Currently, the only remote 70 * protocol we recognize is "rstart-rsh". If the remote protocol is 71 * "rstart-rsh" but the hostname in the 'restart_service_prop' matches 72 * 'client_host_name', we do a local restart. 73 * 74 * On return, set the run_local flag, restart_protocol and restart_machine. 75 */ 76 77void 78GetRestartInfo(char *restart_service_prop, char *client_host_name, 79 Bool *run_local, char **restart_protocol, char **restart_machine) 80{ 81 char hostnamebuf[80]; 82 char *temp; 83 84 *run_local = False; 85 *restart_protocol = NULL; 86 *restart_machine = NULL; 87 88 if (restart_service_prop) 89 { 90 gethostname (hostnamebuf, sizeof hostnamebuf); 91 92 if ((temp = (char *) strchr ( 93 restart_service_prop, '/')) == NULL) 94 { 95 *restart_protocol = (char *) XtNewString ("rstart-rsh"); 96 *restart_machine = (char *) XtNewString (restart_service_prop); 97 } 98 else 99 { 100 *restart_protocol = (char *) XtNewString (restart_service_prop); 101 (*restart_protocol)[temp - restart_service_prop] = '\0'; 102 *restart_machine = (char *) XtNewString (temp + 1); 103 } 104 105 if (strcmp (*restart_machine, hostnamebuf) == 0 || 106 strcmp (*restart_protocol, "local") == 0) 107 { 108 *run_local = True; 109 } 110 } 111 else 112 { 113 if (strncmp (client_host_name, "tcp/", 4) != 0 && 114 strncmp (client_host_name, "decnet/", 7) != 0) 115 { 116 *run_local = True; 117 } 118 else 119 { 120 *restart_protocol = (char *) XtNewString ("rstart-rsh"); 121 122 if ((temp = (char *) strchr ( 123 client_host_name, '/')) == NULL) 124 { 125 *restart_machine = (char *) XtNewString (client_host_name); 126 } 127 else 128 { 129 *restart_machine = (char *) XtNewString (temp + 1); 130 } 131 } 132 } 133} 134 135 136 137/* 138 * Restart clients. The flag indicates RESTART_MANAGERS or 139 * RESTART_REST_OF_CLIENTS. 140 */ 141 142Status 143Restart(int flag) 144{ 145 List *cl, *pl, *vl; 146 PendingClient *c; 147 Prop *prop; 148 const char *cwd; 149 char *program; 150 char **args; 151 char **env; 152 char **pp; 153 int cnt; 154 char *p; 155 char *restart_service_prop; 156 char *restart_protocol; 157 char *restart_machine; 158 Bool run_local; 159 Bool is_manager; 160 Bool ran_manager = 0; 161 162 for(cl = ListFirst(PendingList); cl; cl = ListNext(cl)) { 163 c = (PendingClient *)cl->thing; 164 165 if (verbose) { 166 printf("Restarting id '%s'...\n", c->clientId); 167 printf("Host = %s\n", c->clientHostname); 168 } 169 cwd = "."; 170 env = NULL; 171 program=NULL; 172 args=NULL; 173 restart_service_prop=NULL; 174 175 is_manager = 0; 176 177 for(pl = ListFirst(c->props); pl; pl = ListNext(pl)) { 178 prop = (Prop *)pl->thing; 179 if(!strcmp(prop->name, SmProgram)) { 180 vl = ListFirst(prop->values); 181 if(vl) program = ((PropValue *)vl->thing)->value; 182 if (CheckIsManager (program)) 183 is_manager = 1; 184 } else if(!strcmp(prop->name, SmCurrentDirectory)) { 185 vl = ListFirst(prop->values); 186 if(vl) cwd = ((PropValue *)vl->thing)->value; 187 } else if(!strcmp(prop->name, "_XC_RestartService")) { 188 vl = ListFirst(prop->values); 189 if(vl) restart_service_prop = 190 ((PropValue *)vl->thing)->value; 191 } else if(!strcmp(prop->name, SmRestartCommand)) { 192 cnt = ListCount(prop->values); 193 args = (char **)XtMalloc((cnt+1) * sizeof(char *)); 194 pp = args; 195 for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { 196 *pp++ = ((PropValue *)vl->thing)->value; 197 } 198 *pp = NULL; 199 } else if(!strcmp(prop->name, SmEnvironment)) { 200 cnt = ListCount(prop->values); 201 env = (char **)XtMalloc((cnt+3+1) * sizeof(char *)); 202 pp = env; 203 for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) { 204 p = ((PropValue *)vl->thing)->value; 205 if((display_env && strbw(p, "DISPLAY=")) 206 || (session_env && strbw(p, "SESSION_MANAGER=")) 207 || (audio_env && strbw(p, "AUDIOSERVER=")) 208 ) continue; 209 *pp++ = p; 210 } 211 if(display_env) *pp++ = display_env; 212 if(session_env) *pp++ = session_env; 213 if(audio_env) *pp++ = audio_env; 214 *pp = NULL; 215 } 216 } 217 218 if(program && args) { 219 char logtext[256]; 220 221 if ((flag == RESTART_MANAGERS && !is_manager) || 222 (flag == RESTART_REST_OF_CLIENTS && is_manager)) 223 { 224 if(args) XtFree((char *)args); 225 if(env) XtFree((char *)env); 226 continue; 227 } 228 229 if (flag == RESTART_MANAGERS && is_manager) 230 ran_manager = 1; 231 232 if (verbose) { 233 printf("\t%s\n", program); 234 printf("\t"); 235 for(pp = args; *pp; pp++) printf("%s ", *pp); 236 printf("\n"); 237 } 238 239 GetRestartInfo (restart_service_prop, c->clientHostname, 240 &run_local, &restart_protocol, &restart_machine); 241 242 if (run_local) 243 { 244 /* 245 * The client is being restarted on the local machine. 246 */ 247 248 snprintf (logtext, sizeof(logtext), "Restarting locally : "); 249 for (pp = args; *pp; pp++) 250 { 251 strcat (logtext, *pp); 252 strcat (logtext, " "); 253 } 254 255 strcat (logtext, "\n"); 256 add_log_text (logtext); 257 258 switch(fork()) { 259 case -1: 260 snprintf (logtext, sizeof(logtext), 261 "%s: Can't fork() %s", Argv[0], program); 262 add_log_text (logtext); 263 perror (logtext); 264 break; 265 case 0: /* kid */ 266 chdir(cwd); 267 if(env) environ = env; 268 execvp(program, args); 269 snprintf (logtext, sizeof(logtext), 270 "%s: Can't execvp() %s", Argv[0], program); 271 perror (logtext); 272 /* 273 * TODO : We would like to send this log information to the 274 * log window in the parent. This would require opening 275 * a pipe between the parent and child. The child would 276 * set close-on-exec. If the exec succeeds, the pipe will 277 * be closed. If it fails, the child can write a message 278 * to the parent. 279 */ 280 _exit(255); 281 default: /* parent */ 282 break; 283 } 284 } 285 else if (!remote_allowed) 286 { 287 fprintf(stderr, 288 "Can't remote start client ID '%s': only local supported\n", 289 c->clientId); 290 } 291 else 292 { 293 /* 294 * The client is being restarted on a remote machine. 295 */ 296 297 snprintf (logtext, sizeof(logtext), 298 "Restarting remotely on %s : ", restart_machine); 299 for (pp = args; *pp; pp++) 300 { 301 strcat (logtext, *pp); 302 strcat (logtext, " "); 303 } 304 strcat (logtext, "\n"); 305 add_log_text (logtext); 306 307 remote_start (restart_protocol, restart_machine, 308 program, args, cwd, env, 309 non_local_display_env, non_local_session_env); 310 } 311 312 if (restart_protocol) 313 XtFree (restart_protocol); 314 315 if (restart_machine) 316 XtFree (restart_machine); 317 318 } else { 319 fprintf(stderr, "Can't restart ID '%s': no program or no args\n", 320 c->clientId); 321 } 322 if(args) XtFree((char *)args); 323 if(env) XtFree((char *)env); 324 } 325 326 if (flag == RESTART_MANAGERS && !ran_manager) 327 return (0); 328 else 329 return (1); 330} 331 332 333 334/* 335 * Clone a client 336 */ 337 338void 339Clone(ClientRec *client, Bool useSavedState) 340{ 341 const char *cwd; 342 char *program; 343 char **args; 344 char **env; 345 char **pp; 346 char *p; 347 char *restart_service_prop; 348 char *restart_protocol; 349 char *restart_machine; 350 Bool run_local; 351 List *pl, *pj; 352 353 if (verbose) 354 { 355 printf ("Cloning id '%s', useSavedState = %d...\n", 356 client->clientId, useSavedState); 357 printf ("Host = %s\n", client->clientHostname); 358 } 359 360 cwd = "."; 361 env = NULL; 362 program = NULL; 363 args = NULL; 364 restart_service_prop = NULL; 365 366 for (pl = ListFirst (client->props); pl; pl = ListNext (pl)) 367 { 368 Prop *pprop = (Prop *) pl->thing; 369 List *vl = ListFirst (pprop->values); 370 PropValue *pval = (PropValue *) vl->thing; 371 372 if (strcmp (pprop->name, SmProgram) == 0) 373 program = (char *) pval->value; 374 else if (strcmp (pprop->name, SmCurrentDirectory) == 0) 375 cwd = (char *) pval->value; 376 else if (strcmp (pprop->name, "_XC_RestartService") == 0) 377 restart_service_prop = (char *) pval->value; 378 else if ( 379 (!useSavedState && strcmp (pprop->name, SmCloneCommand) == 0) || 380 (useSavedState && strcmp (pprop->name, SmRestartCommand) == 0)) 381 { 382 args = (char **) XtMalloc ( 383 (ListCount (pprop->values) + 1) * sizeof (char *)); 384 385 pp = args; 386 387 for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) 388 { 389 pval = (PropValue *) pj->thing; 390 *pp++ = (char *) pval->value; 391 } 392 *pp = NULL; 393 } 394 else if (strcmp (pprop->name, SmEnvironment) == 0) 395 { 396 env = (char **) XtMalloc ( 397 (ListCount (pprop->values) + 3 + 1) * sizeof (char *)); 398 pp = env; 399 400 for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj)) 401 { 402 pval = (PropValue *) pj->thing; 403 p = (char *) pval->value; 404 405 if ((display_env && strbw (p, "DISPLAY=")) 406 || (session_env && strbw (p, "SESSION_MANAGER=")) 407 || (audio_env && strbw (p, "AUDIOSERVER="))) 408 continue; 409 410 *pp++ = p; 411 } 412 413 if (display_env) 414 *pp++ = display_env; 415 if (session_env) 416 *pp++ = session_env; 417 if (audio_env) 418 *pp++ = audio_env; 419 420 *pp = NULL; 421 } 422 } 423 424 if (program && args) 425 { 426 if (verbose) 427 { 428 printf("\t%s\n", program); 429 printf("\t"); 430 for (pp = args; *pp; pp++) 431 printf ("%s ", *pp); 432 printf("\n"); 433 } 434 435 GetRestartInfo (restart_service_prop, client->clientHostname, 436 &run_local, &restart_protocol, &restart_machine); 437 438 if (run_local) 439 { 440 /* 441 * The client is being cloned on the local machine. 442 */ 443 444 char msg[256]; 445 446 switch(fork()) { 447 case -1: 448 snprintf (msg, sizeof(msg), 449 "%s: Can't fork() %s", Argv[0], program); 450 add_log_text (msg); 451 perror (msg); 452 break; 453 case 0: /* kid */ 454 chdir(cwd); 455 if(env) environ = env; 456 execvp(program, args); 457 snprintf (msg, sizeof(msg), 458 "%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, filename[128]; 522 const char *home; 523 int buflen, len; 524 525 /* 526 * First try ~/.xsmstartup, then system.xsm 527 */ 528 529 home = getenv ("HOME"); 530 if (!home) 531 home = "."; 532 snprintf (filename, sizeof(filename), "%s/.xsmstartup", home); 533 534 f = fopen (filename, "r"); 535 536 if (!f) 537 { 538 f = fopen (SYSTEM_INIT_FILE, "r"); 539 if (!f) 540 { 541 printf ("Could not find default apps file. Make sure you did\n"); 542 printf ("a 'make install' in the xsm build directory.\n"); 543 exit (1); 544 } 545 } 546 547 buf = NULL; 548 buflen = 0; 549 550 while (getnextline(&buf, &buflen, f)) 551 { 552 char logtext[256]; 553 554 if (buf[0] == '!') 555 continue; /* a comment */ 556 557 if ((p = strchr (buf, '\n'))) 558 *p = '\0'; 559 560 snprintf (logtext, sizeof(logtext), "Starting locally : %s\n", buf); 561 add_log_text (logtext); 562 563 len = strlen (buf); 564 565 buf[len] = '&'; 566 buf[len+1] = '\0'; 567 568 /* let the shell parse the stupid args */ 569 570 execute_system_command (buf); 571 } 572 573 if (buf) 574 free (buf); 575} 576 577 578 579void 580StartNonSessionAwareApps(void) 581{ 582 char logtext[256]; 583 int i; 584 585 for (i = 0; i < non_session_aware_count; i++) 586 { 587 /* 588 * Let the shell parse the stupid args. We need to add an "&" 589 * at the end of the command. We previously allocated an extra 590 * byte for this. 591 */ 592 593 snprintf (logtext, sizeof(logtext), "Restarting locally : %s\n", 594 non_session_aware_clients[i]); 595 add_log_text (logtext); 596 597 strcat (non_session_aware_clients[i], "&"); 598 execute_system_command (non_session_aware_clients[i]); 599 free ((char *) non_session_aware_clients[i]); 600 } 601 602 if (non_session_aware_clients) 603 { 604 free ((char *) non_session_aware_clients); 605 non_session_aware_clients = NULL; 606 } 607} 608