summaryrefslogtreecommitdiff
path: root/xc/programs/xsm/restart.c
diff options
context:
space:
mode:
Diffstat (limited to 'xc/programs/xsm/restart.c')
-rw-r--r--xc/programs/xsm/restart.c602
1 files changed, 602 insertions, 0 deletions
diff --git a/xc/programs/xsm/restart.c b/xc/programs/xsm/restart.c
new file mode 100644
index 000000000..223b9b19c
--- /dev/null
+++ b/xc/programs/xsm/restart.c
@@ -0,0 +1,602 @@
+/* $TOG: restart.c /main/27 1998/02/09 14:14:58 kaleb $ */
+/******************************************************************************
+
+Copyright 1993, 1998 The Open Group
+
+All Rights Reserved.
+
+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.4 1999/03/28 16:27:18 dawes Exp $ */
+
+#include "xsm.h"
+#include "log.h"
+#include "restart.h"
+#include "saveutil.h"
+
+extern char **environ;
+
+
+/*
+ * 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;
+ 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.
+ */
+
+ sprintf (logtext, "Restarting locally : ");
+ for (pp = args; *pp; pp++)
+ {
+ strcat (logtext, *pp);
+ strcat (logtext, " ");
+ }
+
+ strcat (logtext, "\n");
+ add_log_text (logtext);
+
+ switch(fork()) {
+ case -1:
+ sprintf (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);
+ sprintf (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.
+ */
+
+ sprintf (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)
+{
+ 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:
+ sprintf (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);
+ sprintf (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, *home, filename[128];
+ int buflen, len;
+
+ /*
+ * First try ~/.xsmstartup, then system.xsm
+ */
+
+ home = (char *) getenv ("HOME");
+ if (!home)
+ home = ".";
+ sprintf (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);
+ }
+ }
+
+ 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';
+
+ sprintf (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.
+ */
+
+ sprintf (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;
+ }
+}