spc-exec.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * File: spc-exec.c $TOG: spc-exec.c /main/9 1998/10/26 17:22:38 mgreess $
  25. * Language: C
  26. *
  27. * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
  28. *
  29. * (c) Copyright 1993, 1994 Hewlett-Packard Company *
  30. * (c) Copyright 1993, 1994 International Business Machines Corp. *
  31. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
  32. * (c) Copyright 1993, 1994 Novell, Inc. *
  33. */
  34. #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
  35. #include <ctype.h>
  36. #include <errno.h>
  37. #include <signal.h>
  38. #include <sys/wait.h>
  39. #include <sys/param.h>
  40. #include <limits.h>
  41. #include <stdlib.h>
  42. #include <locale.h>
  43. #include <SPC/spcP.h>
  44. #include <bms/MemoryMgr.h>
  45. #include <SPC/spc-proto.h>
  46. #ifdef SVR4
  47. #include <unistd.h>
  48. #endif
  49. #include <Tt/tt_c.h>
  50. #include "DtSvcLock.h"
  51. /* Global vars. */
  52. SPC_Connection_Ptr write_terminator=NULL, read_terminator=NULL;
  53. /*
  54. * Forward declarations
  55. */
  56. static char *get_path_from_context (
  57. char *context );
  58. static int remove_variable(
  59. char *string );
  60. static void resolve_variable_reference(
  61. char **string );
  62. Boolean _path_search (
  63. XeString path, XeString filename, path_search_predicate p); /* XXX */
  64. /*
  65. * This array contains the process id's of the sub-processes
  66. * started by the daemon. When a sub-process terminates, its
  67. * entry will be set to SPCD_DEAD_PROCESS. This list of pid's
  68. * is kept beause when the exit timer expires, if the daemon
  69. * has no sub-processes running, it will exit.
  70. */
  71. pid_t *SPC_pid_list = NULL;
  72. /*
  73. * This global variable is set by the daemon when the client
  74. * connects.
  75. */
  76. int SPC_client_version_number = SPC_PROTOCOL_VERSION;
  77. /*
  78. * If this variable is not NULL, it will contain the name of
  79. * the mount point environment variable plus its value thus it
  80. * ready for 'putenv'.
  81. */
  82. char *SPC_mount_point_env_var = NULL;
  83. /* External definitions */
  84. extern XeChar spc_logging;
  85. extern XeString *environ;
  86. /*
  87. * Routines for handling Sub-Processes
  88. */
  89. /*
  90. **
  91. ** Initialize synchronous terminators.
  92. **
  93. */
  94. /*----------------------------------------------------------------------+*/
  95. int
  96. SPC_Setup_Synchronous_Terminator(void)
  97. /*----------------------------------------------------------------------+*/
  98. {
  99. int pipes[2];
  100. _DtSvcProcessLock();
  101. if(write_terminator) {
  102. _DtSvcProcessUnlock();
  103. return(TRUE);
  104. }
  105. if(pipe(pipes)<0) {
  106. SPC_Error(SPC_No_Pipe);
  107. _DtSvcProcessUnlock();
  108. return(SPC_ERROR);
  109. }
  110. if((write_terminator=SPC_Alloc_Connection())==SPC_ERROR) {
  111. _DtSvcProcessUnlock();
  112. return(SPC_ERROR);
  113. }
  114. SPC_Add_Connection(write_terminator);
  115. if((read_terminator=SPC_Alloc_Connection())==SPC_ERROR) {
  116. _DtSvcProcessUnlock();
  117. return(SPC_ERROR);
  118. }
  119. SPC_Add_Connection(read_terminator);
  120. write_terminator->sid=pipes[WRITE_SIDE];
  121. write_terminator->connected=TRUE;
  122. read_terminator->sid=pipes[READ_SIDE];
  123. read_terminator->connected=TRUE;
  124. SPC_XtAddInput(NULL, &read_terminator->termination_id, read_terminator->sid,
  125. SPC_Conditional_Packet_Handler, SPC_Terminator);
  126. _DtSvcProcessUnlock();
  127. return(TRUE);
  128. }
  129. /*----------------------------------------------------------------------+*/
  130. SPC_Connection_Ptr SPC_Channel_Terminator_Connection(SPC_Channel_Ptr channel)
  131. /*----------------------------------------------------------------------+*/
  132. {
  133. if(IS_REMOTE(channel))
  134. return(channel->connection);
  135. else
  136. return(read_terminator);
  137. }
  138. /*----------------------------------------------------------------------+*/
  139. void SPC_Close_Unused(void)
  140. /*----------------------------------------------------------------------+*/
  141. {
  142. /* Close any and all unused file descriptors */
  143. int fd;
  144. for (fd = STDERR + 1; fd < max_fds; fd++) spc_close(fd);
  145. }
  146. /*----------------------------------------------------------------------+*/
  147. int
  148. SPC_MakeSystemCommand(SPC_Channel_Ptr channel)
  149. /*----------------------------------------------------------------------+*/
  150. {
  151. XeString shell;
  152. XeString *argv;
  153. XeString *tmp_argv;
  154. XeChar newargtwo[_POSIX_ARG_MAX];
  155. int argtwolen=0, tmplen=0;
  156. /* Allocate our memory up front */
  157. argv=Alloc_Argv(4);
  158. newargtwo[argtwolen]=0;
  159. /* copy path into newargtwo */
  160. strncat(newargtwo, channel->path, _POSIX_ARG_MAX-1);
  161. strcat(newargtwo, (XeString)" ");
  162. argtwolen=strlen(newargtwo);
  163. /* copy argv into newargtwo */
  164. for(tmp_argv=channel->argv; tmp_argv && *tmp_argv; tmp_argv++) {
  165. tmplen=strlen(*tmp_argv)+1; /* Room for extra space */
  166. if((tmplen+argtwolen)<_POSIX_ARG_MAX-1) {
  167. strcat(newargtwo, *tmp_argv);
  168. strcat(newargtwo, (XeString)" ");
  169. argtwolen += tmplen;
  170. } else {
  171. XeChar *errbuf;
  172. errbuf = malloc(sizeof(XeChar) * 100);
  173. if (errbuf)
  174. {
  175. SPC_Free_Envp(argv);
  176. sprintf(errbuf,"(%d chars), max. length is %d",tmplen,_POSIX_ARG_MAX);
  177. SPC_Error(SPC_Arg_Too_Long, tmp_argv, _POSIX_ARG_MAX);
  178. free(errbuf);
  179. }
  180. return(SPC_ERROR);
  181. }
  182. }
  183. /* get a shell --
  184. First use the value of $SB_SHELL (if any),
  185. then try $SHELL,
  186. then use DEFAULT_SHELL
  187. */
  188. if(!(shell=getenv((XeString)"SB_SHELL")))
  189. if(!(shell=getenv((XeString)"SHELL")))
  190. shell = DEFAULT_SHELL;
  191. /* setup argv properly */
  192. argv[0]=SPC_copy_string(shell);
  193. argv[1]=SPC_copy_string((XeString)"-c");
  194. argv[2]=SPC_copy_string(newargtwo);
  195. argv[3]=NULL;
  196. channel->argv = argv;
  197. channel->IOMode |= SPCIO_DEALLOC_ARGV;
  198. /* Now set this shell as the path */
  199. channel->path = shell;
  200. return(TRUE);
  201. }
  202. /*
  203. * Routines for handling child process termination
  204. */
  205. /*----------------------------------------------------------------------+*/
  206. /* This is the right way according to the Spec 1170 */
  207. void SPC_Child_Terminated(int i)
  208. /*----------------------------------------------------------------------+*/
  209. {
  210. /* This catches signals for sub-process termination */
  211. int type, cause, status;
  212. pid_t wait_pid, pid;
  213. SPC_Channel_Ptr channel;
  214. protocol_request req, *prot;
  215. buffered_data data, *pdata;
  216. int length;
  217. int indx;
  218. int saved_errno = errno;
  219. prot = (&req);
  220. pdata = (&data);
  221. prot->dataptr=pdata;
  222. wait_pid = -1;
  223. while((pid = waitpid(wait_pid, &status, WNOHANG))) {
  224. if((pid == -1 && errno == ECHILD) || pid == 0) {
  225. /* no more children. Return */
  226. errno = saved_errno;
  227. return;
  228. }
  229. /* Okay, we got the process ID of a terminated child. Find the
  230. channel associated with this PID. */
  231. channel=SPC_Find_PID(pid);
  232. #ifdef DEBUG
  233. fprintf(stderr, (XeString)"got SIGCHLD, pid: %d, channel: %p\n", pid, channel);
  234. #endif
  235. if(!channel) {
  236. continue;
  237. }
  238. _DtSvcProcessLock();
  239. /*
  240. * Look for this process in the pid list. If found, mark it
  241. * as done.
  242. */
  243. if (SPC_pid_list != NULL) {
  244. for (indx=0; SPC_pid_list[indx] != 0; indx++)
  245. if (SPC_pid_list[indx] == pid) {
  246. SPC_pid_list[indx] = SPCD_DEAD_PROCESS;
  247. break;
  248. }
  249. }
  250. _DtSvcProcessUnlock();
  251. /* We have the channel. Mark it as being closed. */
  252. channel->status = status;
  253. /* If we this channel is set up for synchronous termination,
  254. write the protocol request to record that this guy died.
  255. Otherwise, call the termination handler directly. */
  256. if(IS_SPCIO_SYNC_TERM(channel->IOMode)) {
  257. /* This code is basically what SPC_Write_Protocol_Request does.
  258. It is replicated here because a call to SPC_W_P_R would have
  259. to be re-enterant if we called it here, and SPC_W_P_R is not
  260. re-enterant at this time. */
  261. SPC_Reset_Protocol_Ptr(prot, channel, APPLICATION_DIED, 0);
  262. pdata->len=WRITE_APPLICATION_DIED(pdata, status);
  263. length=WRITE_HEADER(pdata, channel->cid,
  264. prot->request_type,
  265. pdata->len,
  266. 0);
  267. pdata->data[length]=(XeChar)' ';
  268. length=pdata->len+REQUEST_HEADER_LENGTH;
  269. if(write(write_terminator->sid, pdata->data, length)==ERROR)
  270. SPC_Error(SPC_Internal_Error);
  271. pdata->offset=REQUEST_HEADER_LENGTH;
  272. print_protocol_request((XeString) (XeString)" <-- INTERNAL APPLICATION_DIED", prot);
  273. }
  274. else {
  275. SPC_Change_State(channel, 0, -1, 0);
  276. if(channel->Terminate_Handler) {
  277. XeSPCGetProcessStatus(channel, &type, &cause);
  278. (* channel->Terminate_Handler)
  279. (channel, channel->pid, type, cause, channel->Terminate_Data);
  280. }
  281. }
  282. /* Loop around & get another PID */
  283. }
  284. errno = saved_errno;
  285. }
  286. /*
  287. ***
  288. *** Check to see if a given path names an executable file. Thus, we
  289. *** need to know if the file exists. If it is a directory, we want
  290. *** to fail. Otherwise, we want to us the system rules for checking
  291. *** on the file, and thus the 'access' call.
  292. ***
  293. */
  294. static Boolean executable_predicate(XeString path, XeString dir, XeString file)
  295. {
  296. struct stat file_status;
  297. dir=dir;
  298. file=file;
  299. if(stat(path, &file_status) != 0)
  300. return(FALSE);
  301. if(S_ISDIR(file_status.st_mode))
  302. return(FALSE);
  303. return(access(path, X_OK | F_OK) == 0);
  304. }
  305. /*----------------------------------------------------------------------+*/
  306. int exec_proc_local_channel_object(SPC_Channel_Ptr channel)
  307. /*----------------------------------------------------------------------+*/
  308. {
  309. sigset_t newsigmask, oldsigmask;
  310. pid_t pid;
  311. int result;
  312. XeString *envp;
  313. XeString dir = XeString_NULL;
  314. int retval;
  315. int i, reuse_pid = 0;
  316. call_parent_method(channel, exec_proc, (channel), result);
  317. if(result==SPC_ERROR)
  318. return(SPC_ERROR);
  319. /* Check to see if the channel pathname points to a valid executable.
  320. We do this by using the _path_search function. If the channel
  321. has a PATH variable set in its local environment, use it,
  322. otherwise use the "global" environment. We can accomplish this
  323. by using the spc_getenv call in the _path_search call. If the
  324. channel doesn't have a PATH variable, then spc_getenv will
  325. return NULL, which indicates use of the global environment.
  326. */
  327. if(!_path_search(SPC_Getenv("PATH", channel->envp),
  328. channel->path,
  329. executable_predicate)) {
  330. SPC_Error(SPC_Cannot_Exec, channel->path);
  331. return(SPC_ERROR);
  332. }
  333. /* If we were passed a host:dir to cd to, make sure it exists. */
  334. /* We want to do this before we fork the child. */
  335. if((channel->context_dir) && (channel->context_dir[0])) {
  336. struct stat stat_info;
  337. Boolean ok = FALSE;
  338. _DtSvcProcessLock();
  339. if (SPC_client_version_number < SPC_PROTOCOL_VERSION_CDE_BASE)
  340. dir = get_path_from_context(channel->context_dir);
  341. else {
  342. /*
  343. * context_dir is actually a "netfile" so it needs to
  344. * be converted to a "real" path.
  345. */
  346. dir = (char *) tt_netfile_file (channel->context_dir);
  347. if (tt_ptr_error (dir) != TT_OK)
  348. dir = NULL;
  349. }
  350. _DtSvcProcessUnlock();
  351. if (dir == NULL)
  352. /* can't make connection ... */;
  353. else if (stat(dir,&stat_info) != 0)
  354. /* directory not there */;
  355. else if ((stat_info.st_mode & S_IFDIR) == 0)
  356. /* path is not a directory ... */;
  357. else
  358. ok = TRUE;
  359. if (!ok && IS_SPCIO_FORCE_CONTEXT(channel->IOMode)) {
  360. if (dir != NULL && (strcmp (dir, channel->context_dir) != 0))
  361. SPC_Error(SPC_cannot_Chdir, dir);
  362. SPC_Error(SPC_cannot_Chdir, channel->context_dir);
  363. XeFree(dir);
  364. dir = XeString_NULL;
  365. return(SPC_ERROR);
  366. }
  367. }
  368. if(mempf0(channel, pre_fork)==SPC_ERROR) {
  369. XeFree(dir);
  370. return(SPC_ERROR);
  371. }
  372. /* When using HP NLIO (xj0input) we have a problem. Namely, */
  373. /* the xj0 processs uses signal() to deal with SIGCLD which */
  374. /* is incompatible with sigaction/sigprogmask/etc. Even */
  375. /* though xj0 resets the signal handler, since the signal */
  376. /* routines are incompatible, our original handler gets lost. */
  377. /* Hence, we need to reset it. We do it here everytime we */
  378. /* fork a child just to be on the safe side. */
  379. SPC_ResetTerminator();
  380. sigemptyset(&newsigmask);
  381. sigemptyset(&oldsigmask);
  382. sigaddset(&newsigmask, SIGCHLD);
  383. if (sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask) == ERROR) {
  384. XeFree(dir);
  385. return(SPC_ERROR);
  386. }
  387. pid = channel->pid = fork();
  388. /*
  389. * Must save this pid so that when the daemon's timer goes off,
  390. * if there has been no activity and there are no sub-processes
  391. * running, the daemon can exit.
  392. */
  393. i = 0;
  394. _DtSvcProcessLock();
  395. if (SPC_pid_list == NULL)
  396. /*
  397. * Create the first block plus the NULL terminator.
  398. */
  399. SPC_pid_list = (pid_t *) malloc (2 * sizeof (pid_t));
  400. else {
  401. /*
  402. * If a dead pid entry exists, reuse it; otherwise, must create
  403. * room for the new pid.
  404. */
  405. for (i = 0; SPC_pid_list[i] != 0; i++)
  406. if (SPC_pid_list[i] == SPCD_DEAD_PROCESS) {
  407. SPC_pid_list[i] = pid;
  408. reuse_pid = 1;
  409. break;
  410. }
  411. if (!reuse_pid)
  412. SPC_pid_list = (pid_t *) realloc (SPC_pid_list,
  413. (i+2) * sizeof (pid_t));
  414. }
  415. if (!reuse_pid) {
  416. SPC_pid_list[i] = pid;
  417. SPC_pid_list[i+1] = 0;
  418. }
  419. _DtSvcProcessUnlock();
  420. if (pid) {
  421. XeFree(dir);
  422. /* Did we really fork? */
  423. if (pid == ERROR) {
  424. SPC_Error(SPC_Cannot_Fork);
  425. retval = SPC_ERROR;
  426. } else {
  427. /* Do any set up for the parent process here */
  428. mempf1(channel, post_fork, pid);
  429. retval = TRUE;
  430. }
  431. /* Reinstate the old signal mask (unblock SIGCLD). */
  432. sigprocmask(SIG_SETMASK, &oldsigmask, (sigset_t *)NULL);
  433. return(retval);
  434. }
  435. else {
  436. /* Child process: connect wires, make environment and exec sub-process */
  437. sigprocmask(SIG_SETMASK, &oldsigmask, (sigset_t *)NULL);
  438. /* Make sure the child is the process group leader. In the case of
  439. ptys, we also want to break the current terminal affiliation.
  440. We want to be the process group leader so XeSPCKillProcess (which
  441. does a kill(-pid, 9)) will kill all processes associated with us.
  442. For PTY's, we need to break the terminal affiliation so the next
  443. open (which will be a pty) will cause us to become affiliated with
  444. the pty. We do this so when the parent process closes the master
  445. side of the pty, the slave side processes get SIGHUP. If they
  446. ignore SIGHUP, they will never die. So it goes...
  447. */
  448. if(IS_SPCIO_PTY(channel->IOMode))
  449. setsid();
  450. else {
  451. pid_t tmppid = getpid();
  452. if(setpgid(tmppid, tmppid) == -1)
  453. fprintf(stderr, (XeString)"setpgid failed, errno: %d\n", errno);
  454. }
  455. /* Connect wires to sub-process standard files */
  456. result=mempf1(channel, post_fork, pid);
  457. if(result!=SPC_ERROR) {
  458. int indx = -1;
  459. int i;
  460. char **ppch;
  461. /*
  462. * Before adding in the list of environment variables
  463. * from the environment variable files, must search
  464. * the list for LANG definitions. If found, the
  465. * last definition must be putenv'ed to assure the
  466. * multi-byte parsing code is using the correct locale.
  467. */
  468. for (i = 0, ppch = channel->envp; *ppch; *ppch++, i++)
  469. if (!strncmp (*ppch, "LANG=", 5))
  470. indx = i;
  471. if (indx != -1)
  472. resolve_variable_reference (&channel->envp[indx]);
  473. _DtSvcProcessLock();
  474. if (!setlocale (LC_CTYPE, ""))
  475. /*
  476. * setlocale failed - log a message but execute
  477. * the command anyway.
  478. */
  479. if (SPC_Print_Protocol != NULL)
  480. (void) fprintf(SPC_Print_Protocol,
  481. "+++> Failed to 'setlocale'; LANG = %s\n",
  482. getenv("LANG"));
  483. /* Mix in the stashed environment */
  484. for(envp=channel->envp; *envp; envp++)
  485. resolve_variable_reference(&*envp);
  486. if (SPC_mount_point_env_var != NULL)
  487. /*
  488. * The mount point environment variable was
  489. * inherited by the daemon or was given to the
  490. * daemon via the command line. In either case
  491. * this subprocess must inherit the daemon's
  492. * value.
  493. */
  494. (void) putenv (SPC_mount_point_env_var);
  495. _DtSvcProcessUnlock();
  496. /* Connect to the context directory */
  497. /* We have already validated this guy exists */
  498. if(dir)
  499. Xechdir(dir);
  500. }
  501. XeFree(dir);
  502. if(result!=SPC_ERROR) {
  503. /* Execute */
  504. /* Compiler barfs without cast ? */
  505. #if defined(__hpux_8_0) || defined(__aix)
  506. result=execvp(channel->path, channel->argv);
  507. #else
  508. result=execvp(channel->path, channel->argv);
  509. #endif
  510. /* If we return from exec, it failed */
  511. SPC_Error(SPC_Cannot_Exec, channel->path);
  512. }
  513. /* We want to get rid of this child image (carefully) */
  514. _exit(42);
  515. }
  516. }
  517. /****************************************************************************
  518. *
  519. * get_path_from_context - given a 'context' string in the following form:
  520. *
  521. * [host:]path
  522. *
  523. * return the path component.
  524. *
  525. * NOTE - the caller must free the returned string.
  526. *
  527. * Parameters:
  528. *
  529. * char *context - the context string to parse
  530. *
  531. * Return Value:
  532. *
  533. * A NULL if a pathname cannot be constructed.
  534. *
  535. ****************************************************************************/
  536. static char *get_path_from_context (
  537. char *context)
  538. {
  539. char *host = NULL;
  540. char *file = NULL;
  541. char *netfile = NULL;
  542. char *path = NULL;
  543. char tmp[MAXPATHLEN];
  544. char *pch;
  545. /*
  546. * Break context into its host and file parts.
  547. */
  548. if (context == NULL)
  549. return (NULL);
  550. (void) strcpy (tmp, context);
  551. file = tmp;
  552. if ((pch = (char *) strchr (tmp, ':')) != NULL) {
  553. host = tmp;
  554. file = pch + 1;
  555. *pch = '\000';
  556. }
  557. if (!host)
  558. return (strdup (file));
  559. netfile = (char *) tt_host_file_netfile (host, file);
  560. if (tt_ptr_error (netfile) != TT_OK) {
  561. SPC_Error (SPC_Cannot_Create_Netfilename, context, host);
  562. return (NULL);
  563. }
  564. path = (char *) tt_netfile_file (netfile);
  565. tt_free (netfile);
  566. if (tt_ptr_error (path) != TT_OK) {
  567. SPC_Error (SPC_Cannot_Create_Netfilename, context, host);
  568. return (NULL);
  569. }
  570. return (path);
  571. }
  572. /**************************************************************************
  573. *
  574. * remove_variable ()
  575. *
  576. * This takes a string of the format:
  577. *
  578. * var_name=some_value | <remove_variable_keyword> var_name
  579. *
  580. * and if the second form is found, 'var_name' is removed from
  581. * the environment.
  582. *
  583. * Parameters:
  584. *
  585. * char *string see the format above.
  586. *
  587. * Return Value:
  588. *
  589. * int 0 if 'string' contains a 'remove variable' command
  590. * 1 if string does not contain a 'remove variable' command
  591. *
  592. * Modified:
  593. *
  594. * char **environ 'var_name' is removed from the environment
  595. *
  596. **************************************************************************/
  597. static int
  598. remove_variable(
  599. char *string)
  600. {
  601. char *pch;
  602. char **ppch;
  603. char **ppch2;
  604. char *tmp_var;
  605. int tmp_len;
  606. /*
  607. * If string contains some white space before the variable
  608. * or keyword, skip the white space.
  609. */
  610. pch = string;
  611. while (
  612. #ifdef NLS16
  613. ((mblen (pch, MB_CUR_MAX) == 1)) &&
  614. #endif /* NLS16 */
  615. isspace ((u_char)*pch))
  616. pch++;
  617. if (*pch == '\000')
  618. return (1);
  619. if (strncmp (pch, SPC_REMOVE_VAR, strlen (SPC_REMOVE_VAR)))
  620. return (1);
  621. /*
  622. * Skip the white space after the keyword and move to the
  623. * beginning of the variable.
  624. */
  625. pch = pch + strlen (SPC_REMOVE_VAR);
  626. while (
  627. #ifdef NLS16
  628. ((mblen (pch, MB_CUR_MAX) == 1)) &&
  629. #endif /* NLS16 */
  630. isspace ((u_char)*pch))
  631. pch++;
  632. if (*pch == '\000')
  633. return (1);
  634. /*
  635. * pch should now point to the variable to be removed.
  636. *
  637. * tmp_var will be equal to the variable with a trailing '='.
  638. * This is added so the future comparison will not match
  639. * against variables that start with 'tmp_var' but then
  640. * have something else.
  641. */
  642. tmp_var = malloc ((strlen (pch) + 2) * sizeof (char));
  643. (void) sprintf (tmp_var, "%s=", pch);
  644. tmp_len = strlen (tmp_var);
  645. /*
  646. * Scan 'environ' for 'tmp_var'
  647. */
  648. for (ppch = environ; *ppch; *ppch++) {
  649. if (!strncmp (tmp_var, *ppch, tmp_len)) {
  650. /*
  651. * Found the variable so remove it by moving all
  652. * variables after *ppch up.
  653. */
  654. for (ppch2 = ppch; *ppch2; *ppch2++) {
  655. *ppch++;
  656. *ppch2 = *ppch;
  657. }
  658. break;
  659. }
  660. }
  661. free ((char *) tmp_var);
  662. return (0);
  663. }
  664. /**************************************************************************
  665. *
  666. * resolve_variable_reference ()
  667. *
  668. * This function takes a string of the format:
  669. *
  670. * var_name=some_value
  671. *
  672. * and if 'some_value' contains a reference to an environment
  673. * variable, the reference is replaced with the value of the
  674. * variable.
  675. *
  676. * For example, if 'string' is
  677. *
  678. * FOO=$VFA_TOP/foo
  679. *
  680. * and $VFA_TOP is '/some_tree', then 'string' will be changed to:
  681. *
  682. * FOO=/some_tree/foo
  683. *
  684. * Notes:
  685. *
  686. * o 'putenv' will be invoked with argument 'string', even if 'string'
  687. * was not modified.
  688. *
  689. * o A valid variable name consists of alphanumerics and underscore
  690. *
  691. * Parameters:
  692. *
  693. * char **string MODIFIED - the environment variable
  694. * definition to be parsed
  695. *
  696. * Return Value:
  697. *
  698. * void
  699. *
  700. **************************************************************************/
  701. static void
  702. resolve_variable_reference(
  703. char **string ) /* MODIFIED */
  704. {
  705. char *string_end;
  706. char *var_start;
  707. char *pch;
  708. char *value;
  709. int n; /* number of bytes in a string */
  710. int len;
  711. int found_brace;
  712. char variable[256];
  713. char *buf = NULL;
  714. char *pbeg = *string;
  715. char *string_start = *string;
  716. if (!remove_variable (*string))
  717. return;
  718. pch = pbeg;
  719. buf = malloc(2048);
  720. while (*pbeg) {
  721. /*
  722. * Look for '$' - the beginning of a variable reference.
  723. * If a '$' character is not found, exit the loop
  724. */
  725. #ifdef NLS16
  726. while (*pch) {
  727. if (((len = mblen (pch, MB_CUR_MAX)) == 1) && (*pch == '$'))
  728. break;
  729. /*
  730. * Move past this char
  731. */
  732. if (len > 0)
  733. pch += len;
  734. else
  735. /*
  736. * pch is null or it points to an invalid mulit-byte
  737. * character.
  738. */
  739. break;
  740. }
  741. #else
  742. pch = strchr (pch, '$');
  743. #endif /* NLS16 */
  744. if (pch == NULL || *pch == '\000')
  745. /*
  746. * The string doesn't contain any (more) variables
  747. */
  748. break;
  749. string_start = *string;
  750. /*
  751. * Found a '$' - the beginning of an environment variable so
  752. * skip it and check the next char for '{' and if it is found
  753. * skip it and move to the real beginning of an env variable.
  754. */
  755. string_end = pch;
  756. found_brace = 0;
  757. pch++;
  758. #ifdef NLS16
  759. if ((mblen (pch, MB_CUR_MAX) == 1) && (*pch == '{')) {
  760. #else
  761. if (*pch == '{') {
  762. #endif /* NLS16 */
  763. pch++; /* input = ${ */
  764. found_brace = 1;
  765. }
  766. if (*pch == '\0') /* input = $\0 or ${\0 */
  767. break;
  768. /*
  769. * Find the end of the variable name - it is assumed to
  770. * be the first character that is not an alpha-numeric
  771. * or '_'.
  772. */
  773. var_start = pch;
  774. n = 0;
  775. while (*pch) {
  776. #ifdef NLS16
  777. if ((mblen (pch, MB_CUR_MAX) > 1) ||
  778. ((mblen (pch, MB_CUR_MAX) == 1) &&
  779. ((*pch == '_') || (isalnum (*pch))))) {
  780. #else
  781. if (isalnum (*pch) || *pch == '_') {
  782. #endif /* NLS16 */
  783. #ifdef NLS16
  784. len = mblen (pch, MB_CUR_MAX);
  785. #else
  786. len = 1;
  787. #endif /* NLS16 */
  788. n += len;
  789. pch += len;
  790. continue;
  791. }
  792. #ifdef NLS16
  793. if (found_brace && (mblen (pch, MB_CUR_MAX) == 1) && (*pch == '}'))
  794. #else
  795. if (found_brace && *pch == '}')
  796. #endif /* NLS16 */
  797. /*
  798. * Move past the closing brace
  799. */
  800. pch++;
  801. break;
  802. }
  803. if (n == 0) {
  804. /*
  805. * Nothing 'recognizable' follows the $ or ${
  806. */
  807. pbeg = pch;
  808. continue;
  809. }
  810. /*
  811. * Stuff the environment variable name in 'variable' and then
  812. * get its value. If the variable doesn't exist, leave its
  813. * name in the string.
  814. */
  815. (void) strncpy (variable, var_start, n);
  816. variable[n] = '\0';
  817. if ((value = getenv (variable)) == NULL) {
  818. /*
  819. * Leave what looks like an environment variable in place.
  820. */
  821. pbeg = pch;
  822. continue;
  823. }
  824. if (strlen (value) == 0) {
  825. pbeg = pch;
  826. continue;
  827. }
  828. /*
  829. * Need to replace the variable definition with the string
  830. * pointed to by 'value'. So create a string that contains the
  831. * characters before the environment variable, then the contents
  832. * of 'value' and finally, the characters after the environment
  833. * variable.
  834. */
  835. if (string_end == string_start)
  836. /*
  837. * There is nothing to prepend before 'value'.
  838. */
  839. buf[0] = '\0';
  840. else {
  841. (void) strncpy (buf, string_start, (string_end - string_start));
  842. buf[(string_end - string_start)] = '\0';
  843. }
  844. (void) strcat (buf, value);
  845. len = strlen (buf);
  846. if (*pch != '\0')
  847. (void) strcat (buf, pch);
  848. /*
  849. * Now put 'buf' into 'string'.
  850. */
  851. *string = realloc (*string, strlen (buf) + 1);
  852. (void) strcpy (*string, buf);
  853. pch = *string + len;
  854. pbeg = pch;
  855. }
  856. /*
  857. * Even if no substitutions were made, the variable must
  858. * be put in the environment.
  859. */
  860. (void) putenv (*string);
  861. if (buf) free(buf);
  862. }