609 lines
15 KiB
C
609 lines
15 KiB
C
/* $Xorg: restart.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */
|
||
/******************************************************************************
|
||
|
||
Copyright 1993, 1998 The Open Group
|
||
|
||
Permission to use, copy, modify, distribute, and sell this software and its
|
||
documentation for any purpose is hereby granted without fee, provided that
|
||
the above copyright notice appear in all copies and that both that
|
||
copyright notice and this permission notice appear in supporting
|
||
documentation.
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
Except as contained in this notice, the name of The Open Group shall not be
|
||
used in advertising or otherwise to promote the sale, use or other dealings
|
||
in this Software without prior written authorization from The Open Group.
|
||
******************************************************************************/
|
||
/* $XFree86: xc/programs/xsm/restart.c,v 1.5 2001/01/17 23:46:30 dawes Exp $ */
|
||
|
||
#include "xsm.h"
|
||
#include "log.h"
|
||
#include "restart.h"
|
||
#include "saveutil.h"
|
||
|
||
|
||
/*
|
||
* Until XSMP provides a better way to know which clients are "managers",
|
||
* we have to hard code the list.
|
||
*/
|
||
|
||
Bool
|
||
CheckIsManager(char *program)
|
||
{
|
||
return (strcmp (program, "twm") == 0);
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* GetRestartInfo() will determine which method should be used to
|
||
* restart a client.
|
||
*
|
||
* 'restart_service_prop' is a property set by the client, or NULL.
|
||
* The format is "remote_start_protocol/remote_start_data". An
|
||
* example is "rstart-rsh/hostname". This is a non-standard property,
|
||
* which is the whole reason we need this function in order to determine
|
||
* the restart method. The proxy uses this property to over-ride the
|
||
* 'client_host_name' from the ICE connection (the proxy is connected to
|
||
* the SM via a local connection, but the proxy may be acting as a proxy
|
||
* for a remote client).
|
||
*
|
||
* 'client_host_name' is the connection info obtained from the ICE
|
||
* connection. It's format is "transport/host_info". An example
|
||
* is "tcp/machine:port".
|
||
*
|
||
* If 'restart_service_prop' is NULL, we use 'client_host_name' to
|
||
* determine the restart method. If the transport is "local", we
|
||
* do a local restart. Otherwise, we use the default "rstart-rsh" method.
|
||
*
|
||
* If 'restart_service_prop' is non-NULL, we check the remote_start_protocol
|
||
* field. "local" means a local restart. Currently, the only remote
|
||
* protocol we recognize is "rstart-rsh". If the remote protocol is
|
||
* "rstart-rsh" but the hostname in the 'restart_service_prop' matches
|
||
* 'client_host_name', we do a local restart.
|
||
*
|
||
* On return, set the run_local flag, restart_protocol and restart_machine.
|
||
*/
|
||
|
||
void
|
||
GetRestartInfo(char *restart_service_prop, char *client_host_name,
|
||
Bool *run_local, char **restart_protocol, char **restart_machine)
|
||
{
|
||
char hostnamebuf[80];
|
||
char *temp;
|
||
|
||
*run_local = False;
|
||
*restart_protocol = NULL;
|
||
*restart_machine = NULL;
|
||
|
||
if (restart_service_prop)
|
||
{
|
||
gethostname (hostnamebuf, sizeof hostnamebuf);
|
||
|
||
if ((temp = (char *) strchr (
|
||
restart_service_prop, '/')) == NULL)
|
||
{
|
||
*restart_protocol = (char *) XtNewString ("rstart-rsh");
|
||
*restart_machine = (char *) XtNewString (restart_service_prop);
|
||
}
|
||
else
|
||
{
|
||
*restart_protocol = (char *) XtNewString (restart_service_prop);
|
||
(*restart_protocol)[temp - restart_service_prop] = '\0';
|
||
*restart_machine = (char *) XtNewString (temp + 1);
|
||
}
|
||
|
||
if (strcmp (*restart_machine, hostnamebuf) == 0 ||
|
||
strcmp (*restart_protocol, "local") == 0)
|
||
{
|
||
*run_local = True;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (strncmp (client_host_name, "tcp/", 4) != 0 &&
|
||
strncmp (client_host_name, "decnet/", 7) != 0)
|
||
{
|
||
*run_local = True;
|
||
}
|
||
else
|
||
{
|
||
*restart_protocol = (char *) XtNewString ("rstart-rsh");
|
||
|
||
if ((temp = (char *) strchr (
|
||
client_host_name, '/')) == NULL)
|
||
{
|
||
*restart_machine = (char *) XtNewString (client_host_name);
|
||
}
|
||
else
|
||
{
|
||
*restart_machine = (char *) XtNewString (temp + 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Restart clients. The flag indicates RESTART_MANAGERS or
|
||
* RESTART_REST_OF_CLIENTS.
|
||
*/
|
||
|
||
Status
|
||
Restart(int flag)
|
||
{
|
||
List *cl, *pl, *vl;
|
||
PendingClient *c;
|
||
Prop *prop;
|
||
const char *cwd;
|
||
char *program;
|
||
char **args;
|
||
char **env;
|
||
char **pp;
|
||
int cnt;
|
||
char *p;
|
||
char *restart_service_prop;
|
||
char *restart_protocol;
|
||
char *restart_machine;
|
||
Bool run_local;
|
||
Bool is_manager;
|
||
Bool ran_manager = 0;
|
||
|
||
for(cl = ListFirst(PendingList); cl; cl = ListNext(cl)) {
|
||
c = (PendingClient *)cl->thing;
|
||
|
||
if (verbose) {
|
||
printf("Restarting id '%s'...\n", c->clientId);
|
||
printf("Host = %s\n", c->clientHostname);
|
||
}
|
||
cwd = ".";
|
||
env = NULL;
|
||
program=NULL;
|
||
args=NULL;
|
||
restart_service_prop=NULL;
|
||
|
||
is_manager = 0;
|
||
|
||
for(pl = ListFirst(c->props); pl; pl = ListNext(pl)) {
|
||
prop = (Prop *)pl->thing;
|
||
if(!strcmp(prop->name, SmProgram)) {
|
||
vl = ListFirst(prop->values);
|
||
if(vl) program = ((PropValue *)vl->thing)->value;
|
||
if (CheckIsManager (program))
|
||
is_manager = 1;
|
||
} else if(!strcmp(prop->name, SmCurrentDirectory)) {
|
||
vl = ListFirst(prop->values);
|
||
if(vl) cwd = ((PropValue *)vl->thing)->value;
|
||
} else if(!strcmp(prop->name, "_XC_RestartService")) {
|
||
vl = ListFirst(prop->values);
|
||
if(vl) restart_service_prop =
|
||
((PropValue *)vl->thing)->value;
|
||
} else if(!strcmp(prop->name, SmRestartCommand)) {
|
||
cnt = ListCount(prop->values);
|
||
args = (char **)XtMalloc((cnt+1) * sizeof(char *));
|
||
pp = args;
|
||
for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) {
|
||
*pp++ = ((PropValue *)vl->thing)->value;
|
||
}
|
||
*pp = NULL;
|
||
} else if(!strcmp(prop->name, SmEnvironment)) {
|
||
cnt = ListCount(prop->values);
|
||
env = (char **)XtMalloc((cnt+3+1) * sizeof(char *));
|
||
pp = env;
|
||
for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) {
|
||
p = ((PropValue *)vl->thing)->value;
|
||
if((display_env && strbw(p, "DISPLAY="))
|
||
|| (session_env && strbw(p, "SESSION_MANAGER="))
|
||
|| (audio_env && strbw(p, "AUDIOSERVER="))
|
||
) continue;
|
||
*pp++ = p;
|
||
}
|
||
if(display_env) *pp++ = display_env;
|
||
if(session_env) *pp++ = session_env;
|
||
if(audio_env) *pp++ = audio_env;
|
||
*pp = NULL;
|
||
}
|
||
}
|
||
|
||
if(program && args) {
|
||
char logtext[256];
|
||
|
||
if ((flag == RESTART_MANAGERS && !is_manager) ||
|
||
(flag == RESTART_REST_OF_CLIENTS && is_manager))
|
||
{
|
||
if(args) XtFree((char *)args);
|
||
if(env) XtFree((char *)env);
|
||
continue;
|
||
}
|
||
|
||
if (flag == RESTART_MANAGERS && is_manager)
|
||
ran_manager = 1;
|
||
|
||
if (verbose) {
|
||
printf("\t%s\n", program);
|
||
printf("\t");
|
||
for(pp = args; *pp; pp++) printf("%s ", *pp);
|
||
printf("\n");
|
||
}
|
||
|
||
GetRestartInfo (restart_service_prop, c->clientHostname,
|
||
&run_local, &restart_protocol, &restart_machine);
|
||
|
||
if (run_local)
|
||
{
|
||
/*
|
||
* The client is being restarted on the local machine.
|
||
*/
|
||
|
||
snprintf (logtext, sizeof(logtext), "Restarting locally : ");
|
||
for (pp = args; *pp; pp++)
|
||
{
|
||
strcat (logtext, *pp);
|
||
strcat (logtext, " ");
|
||
}
|
||
|
||
strcat (logtext, "\n");
|
||
add_log_text (logtext);
|
||
|
||
switch(fork()) {
|
||
case -1:
|
||
snprintf (logtext, sizeof(logtext),
|
||
"%s: Can't fork() %s", Argv[0], program);
|
||
add_log_text (logtext);
|
||
perror (logtext);
|
||
break;
|
||
case 0: /* kid */
|
||
chdir(cwd);
|
||
if(env) environ = env;
|
||
execvp(program, args);
|
||
snprintf (logtext, sizeof(logtext),
|
||
"%s: Can't execvp() %s", Argv[0], program);
|
||
perror (logtext);
|
||
/*
|
||
* TODO : We would like to send this log information to the
|
||
* log window in the parent. This would require opening
|
||
* a pipe between the parent and child. The child would
|
||
* set close-on-exec. If the exec succeeds, the pipe will
|
||
* be closed. If it fails, the child can write a message
|
||
* to the parent.
|
||
*/
|
||
_exit(255);
|
||
default: /* parent */
|
||
break;
|
||
}
|
||
}
|
||
else if (!remote_allowed)
|
||
{
|
||
fprintf(stderr,
|
||
"Can't remote start client ID '%s': only local supported\n",
|
||
c->clientId);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* The client is being restarted on a remote machine.
|
||
*/
|
||
|
||
snprintf (logtext, sizeof(logtext),
|
||
"Restarting remotely on %s : ", restart_machine);
|
||
for (pp = args; *pp; pp++)
|
||
{
|
||
strcat (logtext, *pp);
|
||
strcat (logtext, " ");
|
||
}
|
||
strcat (logtext, "\n");
|
||
add_log_text (logtext);
|
||
|
||
remote_start (restart_protocol, restart_machine,
|
||
program, args, cwd, env,
|
||
non_local_display_env, non_local_session_env);
|
||
}
|
||
|
||
if (restart_protocol)
|
||
XtFree (restart_protocol);
|
||
|
||
if (restart_machine)
|
||
XtFree (restart_machine);
|
||
|
||
} else {
|
||
fprintf(stderr, "Can't restart ID '%s': no program or no args\n",
|
||
c->clientId);
|
||
}
|
||
if(args) XtFree((char *)args);
|
||
if(env) XtFree((char *)env);
|
||
}
|
||
|
||
if (flag == RESTART_MANAGERS && !ran_manager)
|
||
return (0);
|
||
else
|
||
return (1);
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Clone a client
|
||
*/
|
||
|
||
void
|
||
Clone(ClientRec *client, Bool useSavedState)
|
||
{
|
||
const char *cwd;
|
||
char *program;
|
||
char **args;
|
||
char **env;
|
||
char **pp;
|
||
char *p;
|
||
char *restart_service_prop;
|
||
char *restart_protocol;
|
||
char *restart_machine;
|
||
Bool run_local;
|
||
List *pl, *pj;
|
||
|
||
if (verbose)
|
||
{
|
||
printf ("Cloning id '%s', useSavedState = %d...\n",
|
||
client->clientId, useSavedState);
|
||
printf ("Host = %s\n", client->clientHostname);
|
||
}
|
||
|
||
cwd = ".";
|
||
env = NULL;
|
||
program = NULL;
|
||
args = NULL;
|
||
restart_service_prop = NULL;
|
||
|
||
for (pl = ListFirst (client->props); pl; pl = ListNext (pl))
|
||
{
|
||
Prop *pprop = (Prop *) pl->thing;
|
||
List *vl = ListFirst (pprop->values);
|
||
PropValue *pval = (PropValue *) vl->thing;
|
||
|
||
if (strcmp (pprop->name, SmProgram) == 0)
|
||
program = (char *) pval->value;
|
||
else if (strcmp (pprop->name, SmCurrentDirectory) == 0)
|
||
cwd = (char *) pval->value;
|
||
else if (strcmp (pprop->name, "_XC_RestartService") == 0)
|
||
restart_service_prop = (char *) pval->value;
|
||
else if (
|
||
(!useSavedState && strcmp (pprop->name, SmCloneCommand) == 0) ||
|
||
(useSavedState && strcmp (pprop->name, SmRestartCommand) == 0))
|
||
{
|
||
args = (char **) XtMalloc (
|
||
(ListCount (pprop->values) + 1) * sizeof (char *));
|
||
|
||
pp = args;
|
||
|
||
for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj))
|
||
{
|
||
pval = (PropValue *) pj->thing;
|
||
*pp++ = (char *) pval->value;
|
||
}
|
||
*pp = NULL;
|
||
}
|
||
else if (strcmp (pprop->name, SmEnvironment) == 0)
|
||
{
|
||
env = (char **) XtMalloc (
|
||
(ListCount (pprop->values) + 3 + 1) * sizeof (char *));
|
||
pp = env;
|
||
|
||
for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj))
|
||
{
|
||
pval = (PropValue *) pj->thing;
|
||
p = (char *) pval->value;
|
||
|
||
if ((display_env && strbw (p, "DISPLAY="))
|
||
|| (session_env && strbw (p, "SESSION_MANAGER="))
|
||
|| (audio_env && strbw (p, "AUDIOSERVER=")))
|
||
continue;
|
||
|
||
*pp++ = p;
|
||
}
|
||
|
||
if (display_env)
|
||
*pp++ = display_env;
|
||
if (session_env)
|
||
*pp++ = session_env;
|
||
if (audio_env)
|
||
*pp++ = audio_env;
|
||
|
||
*pp = NULL;
|
||
}
|
||
}
|
||
|
||
if (program && args)
|
||
{
|
||
if (verbose)
|
||
{
|
||
printf("\t%s\n", program);
|
||
printf("\t");
|
||
for (pp = args; *pp; pp++)
|
||
printf ("%s ", *pp);
|
||
printf("\n");
|
||
}
|
||
|
||
GetRestartInfo (restart_service_prop, client->clientHostname,
|
||
&run_local, &restart_protocol, &restart_machine);
|
||
|
||
if (run_local)
|
||
{
|
||
/*
|
||
* The client is being cloned on the local machine.
|
||
*/
|
||
|
||
char msg[256];
|
||
|
||
switch(fork()) {
|
||
case -1:
|
||
snprintf (msg, sizeof(msg),
|
||
"%s: Can't fork() %s", Argv[0], program);
|
||
add_log_text (msg);
|
||
perror (msg);
|
||
break;
|
||
case 0: /* kid */
|
||
chdir(cwd);
|
||
if(env) environ = env;
|
||
execvp(program, args);
|
||
snprintf (msg, sizeof(msg),
|
||
"%s: Can't execvp() %s", Argv[0], program);
|
||
perror (msg);
|
||
/*
|
||
* TODO : We would like to send this log information to the
|
||
* log window in the parent. This would require opening
|
||
* a pipe between the parent and child. The child would
|
||
* set close-on-exec. If the exec succeeds, the pipe will
|
||
* be closed. If it fails, the child can write a message
|
||
* to the parent.
|
||
*/
|
||
_exit(255);
|
||
default: /* parent */
|
||
break;
|
||
}
|
||
}
|
||
else if (!remote_allowed)
|
||
{
|
||
fprintf(stderr,
|
||
"Can't remote clone client ID '%s': only local supported\n",
|
||
client->clientId);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* The client is being cloned on a remote machine.
|
||
*/
|
||
|
||
remote_start (restart_protocol, restart_machine,
|
||
program, args, cwd, env,
|
||
non_local_display_env, non_local_session_env);
|
||
}
|
||
|
||
if (restart_protocol)
|
||
XtFree (restart_protocol);
|
||
|
||
if (restart_machine)
|
||
XtFree (restart_machine);
|
||
|
||
}
|
||
else
|
||
{
|
||
#ifdef XKB
|
||
XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_Failure);
|
||
#else
|
||
XBell (XtDisplay (topLevel), 0);
|
||
#endif
|
||
|
||
fprintf(stderr, "Can't restart ID '%s': no program or no args\n",
|
||
client->clientId);
|
||
}
|
||
|
||
if (args)
|
||
XtFree ((char *)args);
|
||
if (env)
|
||
XtFree ((char *)env);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
StartDefaultApps (void)
|
||
{
|
||
FILE *f;
|
||
char *buf, *p, filename[128];
|
||
const char *home;
|
||
int buflen, len;
|
||
|
||
/*
|
||
* First try ~/.xsmstartup, then system.xsm
|
||
*/
|
||
|
||
home = getenv ("HOME");
|
||
if (!home)
|
||
home = ".";
|
||
snprintf (filename, sizeof(filename), "%s/.xsmstartup", home);
|
||
|
||
f = fopen (filename, "r");
|
||
|
||
if (!f)
|
||
{
|
||
f = fopen (SYSTEM_INIT_FILE, "r");
|
||
if (!f)
|
||
{
|
||
printf ("Could not find default apps file. Make sure you did\n");
|
||
printf ("a 'make install' in the xsm build directory.\n");
|
||
exit (1);
|
||
}
|
||
}
|
||
fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
|
||
|
||
buf = NULL;
|
||
buflen = 0;
|
||
|
||
while (getnextline(&buf, &buflen, f))
|
||
{
|
||
char logtext[256];
|
||
|
||
if (buf[0] == '!')
|
||
continue; /* a comment */
|
||
|
||
if ((p = strchr (buf, '\n')))
|
||
*p = '\0';
|
||
|
||
snprintf (logtext, sizeof(logtext), "Starting locally : %s\n", buf);
|
||
add_log_text (logtext);
|
||
|
||
len = strlen (buf);
|
||
|
||
buf[len] = '&';
|
||
buf[len+1] = '\0';
|
||
|
||
/* let the shell parse the stupid args */
|
||
|
||
execute_system_command (buf);
|
||
}
|
||
|
||
if (buf)
|
||
free (buf);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
StartNonSessionAwareApps(void)
|
||
{
|
||
char logtext[256];
|
||
int i;
|
||
|
||
for (i = 0; i < non_session_aware_count; i++)
|
||
{
|
||
/*
|
||
* Let the shell parse the stupid args. We need to add an "&"
|
||
* at the end of the command. We previously allocated an extra
|
||
* byte for this.
|
||
*/
|
||
|
||
snprintf (logtext, sizeof(logtext), "Restarting locally : %s\n",
|
||
non_session_aware_clients[i]);
|
||
add_log_text (logtext);
|
||
|
||
strcat (non_session_aware_clients[i], "&");
|
||
execute_system_command (non_session_aware_clients[i]);
|
||
free ((char *) non_session_aware_clients[i]);
|
||
}
|
||
|
||
if (non_session_aware_clients)
|
||
{
|
||
free ((char *) non_session_aware_clients);
|
||
non_session_aware_clients = NULL;
|
||
}
|
||
}
|