Home | History | Annotate | Line # | Download | only in dist
      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