restart.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /* $Xorg: restart.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */
  2. /******************************************************************************
  3. Copyright 1993, 1998 The Open Group
  4. Permission to use, copy, modify, distribute, and sell this software and its
  5. documentation for any purpose is hereby granted without fee, provided that
  6. the above copyright notice appear in all copies and that both that
  7. copyright notice and this permission notice appear in supporting
  8. documentation.
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  15. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  16. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  17. Except as contained in this notice, the name of The Open Group shall not be
  18. used in advertising or otherwise to promote the sale, use or other dealings
  19. in this Software without prior written authorization from The Open Group.
  20. ******************************************************************************/
  21. /* $XFree86: xc/programs/xsm/restart.c,v 1.5 2001/01/17 23:46:30 dawes Exp $ */
  22. #include "xsm.h"
  23. #include "log.h"
  24. #include "restart.h"
  25. #include "saveutil.h"
  26. /*
  27. * Until XSMP provides a better way to know which clients are "managers",
  28. * we have to hard code the list.
  29. */
  30. Bool
  31. CheckIsManager(char *program)
  32. {
  33. return (strcmp (program, "twm") == 0);
  34. }
  35. /*
  36. * GetRestartInfo() will determine which method should be used to
  37. * restart a client.
  38. *
  39. * 'restart_service_prop' is a property set by the client, or NULL.
  40. * The format is "remote_start_protocol/remote_start_data". An
  41. * example is "rstart-rsh/hostname". This is a non-standard property,
  42. * which is the whole reason we need this function in order to determine
  43. * the restart method. The proxy uses this property to over-ride the
  44. * 'client_host_name' from the ICE connection (the proxy is connected to
  45. * the SM via a local connection, but the proxy may be acting as a proxy
  46. * for a remote client).
  47. *
  48. * 'client_host_name' is the connection info obtained from the ICE
  49. * connection. It's format is "transport/host_info". An example
  50. * is "tcp/machine:port".
  51. *
  52. * If 'restart_service_prop' is NULL, we use 'client_host_name' to
  53. * determine the restart method. If the transport is "local", we
  54. * do a local restart. Otherwise, we use the default "rstart-rsh" method.
  55. *
  56. * If 'restart_service_prop' is non-NULL, we check the remote_start_protocol
  57. * field. "local" means a local restart. Currently, the only remote
  58. * protocol we recognize is "rstart-rsh". If the remote protocol is
  59. * "rstart-rsh" but the hostname in the 'restart_service_prop' matches
  60. * 'client_host_name', we do a local restart.
  61. *
  62. * On return, set the run_local flag, restart_protocol and restart_machine.
  63. */
  64. void
  65. GetRestartInfo(char *restart_service_prop, char *client_host_name,
  66. Bool *run_local, char **restart_protocol, char **restart_machine)
  67. {
  68. char hostnamebuf[80];
  69. char *temp;
  70. *run_local = False;
  71. *restart_protocol = NULL;
  72. *restart_machine = NULL;
  73. if (restart_service_prop)
  74. {
  75. gethostname (hostnamebuf, sizeof hostnamebuf);
  76. if ((temp = (char *) strchr (
  77. restart_service_prop, '/')) == NULL)
  78. {
  79. *restart_protocol = (char *) XtNewString ("rstart-rsh");
  80. *restart_machine = (char *) XtNewString (restart_service_prop);
  81. }
  82. else
  83. {
  84. *restart_protocol = (char *) XtNewString (restart_service_prop);
  85. (*restart_protocol)[temp - restart_service_prop] = '\0';
  86. *restart_machine = (char *) XtNewString (temp + 1);
  87. }
  88. if (strcmp (*restart_machine, hostnamebuf) == 0 ||
  89. strcmp (*restart_protocol, "local") == 0)
  90. {
  91. *run_local = True;
  92. }
  93. }
  94. else
  95. {
  96. if (strncmp (client_host_name, "tcp/", 4) != 0 &&
  97. strncmp (client_host_name, "decnet/", 7) != 0)
  98. {
  99. *run_local = True;
  100. }
  101. else
  102. {
  103. *restart_protocol = (char *) XtNewString ("rstart-rsh");
  104. if ((temp = (char *) strchr (
  105. client_host_name, '/')) == NULL)
  106. {
  107. *restart_machine = (char *) XtNewString (client_host_name);
  108. }
  109. else
  110. {
  111. *restart_machine = (char *) XtNewString (temp + 1);
  112. }
  113. }
  114. }
  115. }
  116. /*
  117. * Restart clients. The flag indicates RESTART_MANAGERS or
  118. * RESTART_REST_OF_CLIENTS.
  119. */
  120. Status
  121. Restart(int flag)
  122. {
  123. List *cl, *pl, *vl;
  124. PendingClient *c;
  125. Prop *prop;
  126. const char *cwd;
  127. char *program;
  128. char **args;
  129. char **env;
  130. char **pp;
  131. int cnt;
  132. char *p;
  133. char *restart_service_prop;
  134. char *restart_protocol;
  135. char *restart_machine;
  136. Bool run_local;
  137. Bool is_manager;
  138. Bool ran_manager = 0;
  139. for(cl = ListFirst(PendingList); cl; cl = ListNext(cl)) {
  140. c = (PendingClient *)cl->thing;
  141. if (verbose) {
  142. printf("Restarting id '%s'...\n", c->clientId);
  143. printf("Host = %s\n", c->clientHostname);
  144. }
  145. cwd = ".";
  146. env = NULL;
  147. program=NULL;
  148. args=NULL;
  149. restart_service_prop=NULL;
  150. is_manager = 0;
  151. for(pl = ListFirst(c->props); pl; pl = ListNext(pl)) {
  152. prop = (Prop *)pl->thing;
  153. if(!strcmp(prop->name, SmProgram)) {
  154. vl = ListFirst(prop->values);
  155. if(vl) program = ((PropValue *)vl->thing)->value;
  156. if (CheckIsManager (program))
  157. is_manager = 1;
  158. } else if(!strcmp(prop->name, SmCurrentDirectory)) {
  159. vl = ListFirst(prop->values);
  160. if(vl) cwd = ((PropValue *)vl->thing)->value;
  161. } else if(!strcmp(prop->name, "_XC_RestartService")) {
  162. vl = ListFirst(prop->values);
  163. if(vl) restart_service_prop =
  164. ((PropValue *)vl->thing)->value;
  165. } else if(!strcmp(prop->name, SmRestartCommand)) {
  166. cnt = ListCount(prop->values);
  167. args = (char **)XtMalloc((cnt+1) * sizeof(char *));
  168. pp = args;
  169. for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) {
  170. *pp++ = ((PropValue *)vl->thing)->value;
  171. }
  172. *pp = NULL;
  173. } else if(!strcmp(prop->name, SmEnvironment)) {
  174. cnt = ListCount(prop->values);
  175. env = (char **)XtMalloc((cnt+3+1) * sizeof(char *));
  176. pp = env;
  177. for(vl = ListFirst(prop->values); vl; vl = ListNext(vl)) {
  178. p = ((PropValue *)vl->thing)->value;
  179. if((display_env && strbw(p, "DISPLAY="))
  180. || (session_env && strbw(p, "SESSION_MANAGER="))
  181. || (audio_env && strbw(p, "AUDIOSERVER="))
  182. ) continue;
  183. *pp++ = p;
  184. }
  185. if(display_env) *pp++ = display_env;
  186. if(session_env) *pp++ = session_env;
  187. if(audio_env) *pp++ = audio_env;
  188. *pp = NULL;
  189. }
  190. }
  191. if(program && args) {
  192. char logtext[256];
  193. if ((flag == RESTART_MANAGERS && !is_manager) ||
  194. (flag == RESTART_REST_OF_CLIENTS && is_manager))
  195. {
  196. if(args) XtFree((char *)args);
  197. if(env) XtFree((char *)env);
  198. continue;
  199. }
  200. if (flag == RESTART_MANAGERS && is_manager)
  201. ran_manager = 1;
  202. if (verbose) {
  203. printf("\t%s\n", program);
  204. printf("\t");
  205. for(pp = args; *pp; pp++) printf("%s ", *pp);
  206. printf("\n");
  207. }
  208. GetRestartInfo (restart_service_prop, c->clientHostname,
  209. &run_local, &restart_protocol, &restart_machine);
  210. if (run_local)
  211. {
  212. /*
  213. * The client is being restarted on the local machine.
  214. */
  215. snprintf (logtext, sizeof(logtext), "Restarting locally : ");
  216. for (pp = args; *pp; pp++)
  217. {
  218. strcat (logtext, *pp);
  219. strcat (logtext, " ");
  220. }
  221. strcat (logtext, "\n");
  222. add_log_text (logtext);
  223. switch(fork()) {
  224. case -1:
  225. snprintf (logtext, sizeof(logtext),
  226. "%s: Can't fork() %s", Argv[0], program);
  227. add_log_text (logtext);
  228. perror (logtext);
  229. break;
  230. case 0: /* kid */
  231. chdir(cwd);
  232. if(env) environ = env;
  233. execvp(program, args);
  234. snprintf (logtext, sizeof(logtext),
  235. "%s: Can't execvp() %s", Argv[0], program);
  236. perror (logtext);
  237. /*
  238. * TODO : We would like to send this log information to the
  239. * log window in the parent. This would require opening
  240. * a pipe between the parent and child. The child would
  241. * set close-on-exec. If the exec succeeds, the pipe will
  242. * be closed. If it fails, the child can write a message
  243. * to the parent.
  244. */
  245. _exit(255);
  246. default: /* parent */
  247. break;
  248. }
  249. }
  250. else if (!remote_allowed)
  251. {
  252. fprintf(stderr,
  253. "Can't remote start client ID '%s': only local supported\n",
  254. c->clientId);
  255. }
  256. else
  257. {
  258. /*
  259. * The client is being restarted on a remote machine.
  260. */
  261. snprintf (logtext, sizeof(logtext),
  262. "Restarting remotely on %s : ", restart_machine);
  263. for (pp = args; *pp; pp++)
  264. {
  265. strcat (logtext, *pp);
  266. strcat (logtext, " ");
  267. }
  268. strcat (logtext, "\n");
  269. add_log_text (logtext);
  270. remote_start (restart_protocol, restart_machine,
  271. program, args, cwd, env,
  272. non_local_display_env, non_local_session_env);
  273. }
  274. if (restart_protocol)
  275. XtFree (restart_protocol);
  276. if (restart_machine)
  277. XtFree (restart_machine);
  278. } else {
  279. fprintf(stderr, "Can't restart ID '%s': no program or no args\n",
  280. c->clientId);
  281. }
  282. if(args) XtFree((char *)args);
  283. if(env) XtFree((char *)env);
  284. }
  285. if (flag == RESTART_MANAGERS && !ran_manager)
  286. return (0);
  287. else
  288. return (1);
  289. }
  290. /*
  291. * Clone a client
  292. */
  293. void
  294. Clone(ClientRec *client, Bool useSavedState)
  295. {
  296. const char *cwd;
  297. char *program;
  298. char **args;
  299. char **env;
  300. char **pp;
  301. char *p;
  302. char *restart_service_prop;
  303. char *restart_protocol;
  304. char *restart_machine;
  305. Bool run_local;
  306. List *pl, *pj;
  307. if (verbose)
  308. {
  309. printf ("Cloning id '%s', useSavedState = %d...\n",
  310. client->clientId, useSavedState);
  311. printf ("Host = %s\n", client->clientHostname);
  312. }
  313. cwd = ".";
  314. env = NULL;
  315. program = NULL;
  316. args = NULL;
  317. restart_service_prop = NULL;
  318. for (pl = ListFirst (client->props); pl; pl = ListNext (pl))
  319. {
  320. Prop *pprop = (Prop *) pl->thing;
  321. List *vl = ListFirst (pprop->values);
  322. PropValue *pval = (PropValue *) vl->thing;
  323. if (strcmp (pprop->name, SmProgram) == 0)
  324. program = (char *) pval->value;
  325. else if (strcmp (pprop->name, SmCurrentDirectory) == 0)
  326. cwd = (char *) pval->value;
  327. else if (strcmp (pprop->name, "_XC_RestartService") == 0)
  328. restart_service_prop = (char *) pval->value;
  329. else if (
  330. (!useSavedState && strcmp (pprop->name, SmCloneCommand) == 0) ||
  331. (useSavedState && strcmp (pprop->name, SmRestartCommand) == 0))
  332. {
  333. args = (char **) XtMalloc (
  334. (ListCount (pprop->values) + 1) * sizeof (char *));
  335. pp = args;
  336. for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj))
  337. {
  338. pval = (PropValue *) pj->thing;
  339. *pp++ = (char *) pval->value;
  340. }
  341. *pp = NULL;
  342. }
  343. else if (strcmp (pprop->name, SmEnvironment) == 0)
  344. {
  345. env = (char **) XtMalloc (
  346. (ListCount (pprop->values) + 3 + 1) * sizeof (char *));
  347. pp = env;
  348. for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj))
  349. {
  350. pval = (PropValue *) pj->thing;
  351. p = (char *) pval->value;
  352. if ((display_env && strbw (p, "DISPLAY="))
  353. || (session_env && strbw (p, "SESSION_MANAGER="))
  354. || (audio_env && strbw (p, "AUDIOSERVER=")))
  355. continue;
  356. *pp++ = p;
  357. }
  358. if (display_env)
  359. *pp++ = display_env;
  360. if (session_env)
  361. *pp++ = session_env;
  362. if (audio_env)
  363. *pp++ = audio_env;
  364. *pp = NULL;
  365. }
  366. }
  367. if (program && args)
  368. {
  369. if (verbose)
  370. {
  371. printf("\t%s\n", program);
  372. printf("\t");
  373. for (pp = args; *pp; pp++)
  374. printf ("%s ", *pp);
  375. printf("\n");
  376. }
  377. GetRestartInfo (restart_service_prop, client->clientHostname,
  378. &run_local, &restart_protocol, &restart_machine);
  379. if (run_local)
  380. {
  381. /*
  382. * The client is being cloned on the local machine.
  383. */
  384. char msg[256];
  385. switch(fork()) {
  386. case -1:
  387. snprintf (msg, sizeof(msg),
  388. "%s: Can't fork() %s", Argv[0], program);
  389. add_log_text (msg);
  390. perror (msg);
  391. break;
  392. case 0: /* kid */
  393. chdir(cwd);
  394. if(env) environ = env;
  395. execvp(program, args);
  396. snprintf (msg, sizeof(msg),
  397. "%s: Can't execvp() %s", Argv[0], program);
  398. perror (msg);
  399. /*
  400. * TODO : We would like to send this log information to the
  401. * log window in the parent. This would require opening
  402. * a pipe between the parent and child. The child would
  403. * set close-on-exec. If the exec succeeds, the pipe will
  404. * be closed. If it fails, the child can write a message
  405. * to the parent.
  406. */
  407. _exit(255);
  408. default: /* parent */
  409. break;
  410. }
  411. }
  412. else if (!remote_allowed)
  413. {
  414. fprintf(stderr,
  415. "Can't remote clone client ID '%s': only local supported\n",
  416. client->clientId);
  417. }
  418. else
  419. {
  420. /*
  421. * The client is being cloned on a remote machine.
  422. */
  423. remote_start (restart_protocol, restart_machine,
  424. program, args, cwd, env,
  425. non_local_display_env, non_local_session_env);
  426. }
  427. if (restart_protocol)
  428. XtFree (restart_protocol);
  429. if (restart_machine)
  430. XtFree (restart_machine);
  431. }
  432. else
  433. {
  434. #ifdef XKB
  435. XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_Failure);
  436. #else
  437. XBell (XtDisplay (topLevel), 0);
  438. #endif
  439. fprintf(stderr, "Can't restart ID '%s': no program or no args\n",
  440. client->clientId);
  441. }
  442. if (args)
  443. XtFree ((char *)args);
  444. if (env)
  445. XtFree ((char *)env);
  446. }
  447. void
  448. StartDefaultApps (void)
  449. {
  450. FILE *f;
  451. char *buf, *p, filename[128];
  452. const char *home;
  453. int buflen, len;
  454. /*
  455. * First try ~/.xsmstartup, then system.xsm
  456. */
  457. home = getenv ("HOME");
  458. if (!home)
  459. home = ".";
  460. snprintf (filename, sizeof(filename), "%s/.xsmstartup", home);
  461. f = fopen (filename, "r");
  462. if (!f)
  463. {
  464. f = fopen (SYSTEM_INIT_FILE, "r");
  465. if (!f)
  466. {
  467. printf ("Could not find default apps file. Make sure you did\n");
  468. printf ("a 'make install' in the xsm build directory.\n");
  469. exit (1);
  470. }
  471. }
  472. buf = NULL;
  473. buflen = 0;
  474. while (getnextline(&buf, &buflen, f))
  475. {
  476. char logtext[256];
  477. if (buf[0] == '!')
  478. continue; /* a comment */
  479. if ((p = strchr (buf, '\n')))
  480. *p = '\0';
  481. snprintf (logtext, sizeof(logtext), "Starting locally : %s\n", buf);
  482. add_log_text (logtext);
  483. len = strlen (buf);
  484. buf[len] = '&';
  485. buf[len+1] = '\0';
  486. /* let the shell parse the stupid args */
  487. execute_system_command (buf);
  488. }
  489. if (buf)
  490. free (buf);
  491. }
  492. void
  493. StartNonSessionAwareApps(void)
  494. {
  495. char logtext[256];
  496. int i;
  497. for (i = 0; i < non_session_aware_count; i++)
  498. {
  499. /*
  500. * Let the shell parse the stupid args. We need to add an "&"
  501. * at the end of the command. We previously allocated an extra
  502. * byte for this.
  503. */
  504. snprintf (logtext, sizeof(logtext), "Restarting locally : %s\n",
  505. non_session_aware_clients[i]);
  506. add_log_text (logtext);
  507. strcat (non_session_aware_clients[i], "&");
  508. execute_system_command (non_session_aware_clients[i]);
  509. free ((char *) non_session_aware_clients[i]);
  510. }
  511. if (non_session_aware_clients)
  512. {
  513. free ((char *) non_session_aware_clients);
  514. non_session_aware_clients = NULL;
  515. }
  516. }