2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * File: main.c $TOG: main.c /main/8 1999/09/30 15:31:41 mgreess $
27 * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
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. *
35 #include <bms/sbport.h>
37 #include <time.h> /* ctime() */
41 #include <unistd.h> /* initgroups() */
42 #include <string.h> /* basename() on DEC */
44 # include <libgen.h> /* basename() everywhere else. */
46 #include <sys/param.h> /* MAXPATHLEN */
49 #include <bms/MemoryMgr.h>
50 #include <bms/XeUserMsg.h>
51 #include <bms/usersig.h>
55 #include <SPC/spc-proto.h>
56 #include <XlationSvc.h>
57 #include <LocaleXlate.h>
61 #include "spcd_event.h"
63 static char *MOUNT_POINT = "DTMOUNTPOINT";
65 /* Forward declarations */
66 /** ------------------ **/
67 static void Merge_Lang_Var(SPC_Channel_Ptr channel);
69 void SPCD_Handle_Client_Data(void *channel, int *source, SbInputId *id );
70 int SPCD_Initialize(void);
71 void SPCD_Exit(int exitval);
72 void SPCD_Handle_Application_Data(void *chn, XeString text, int size, int conn_type );
73 void SPCD_Termination_Handler(SPC_Channel_Ptr channel, int pid, int type, int cause, void *data );
74 int Client_Abort(protocol_request_ptr prot);
75 int Client_Register(protocol_request_ptr prot);
76 int Client_Unregister(protocol_request_ptr prot);
77 int Client_Channel_Open(protocol_request_ptr prot);
78 int Client_Channel_Close(protocol_request_ptr prot);
79 int Client_Channel_Reset(protocol_request_ptr prot);
80 int Client_Channel_Attach(protocol_request_ptr prot);
81 int Client_Application_Spawn(protocol_request_ptr prot);
82 int Client_Application_Signal(protocol_request_ptr prot);
83 int Client_Application_Data(protocol_request_ptr prot);
84 int Client_Server_Debug(protocol_request_ptr prot);
85 int Client_Environ_Reset(protocol_request_ptr prot);
86 int Client_Reply_Devices(protocol_request_ptr prot);
87 int Client_Reply_Logfile(protocol_request_ptr prot);
88 int Client_Delete_Logfile(protocol_request_ptr prot);
89 int Client_Reset_Termio(protocol_request_ptr prot);
90 int Client_Reset_Termios(protocol_request_ptr prot);
91 int Client_Protocol_Version(protocol_request_ptr prot);
92 int Client_Reply_Protocol(protocol_request_ptr prot);
93 int Client_Reply_Hostinfo(protocol_request_ptr prot);
95 /* New B.00 methods */
97 int Client_Send_EOF(protocol_request_ptr prot);
98 int Client_Channel_Termios(protocol_request_ptr prot);
99 int Client_Enhanced_Spawn(protocol_request_ptr prot);
101 #if defined(_AIX) || defined(DEC)
102 # define SA_HANDLER_INT_ARG
103 #endif /* _AIX || DEC */
105 void conditional_putenv(XeString env_str);
106 void SPCD_Reply(SPC_Connection_Ptr connection, protocol_request_ptr prot, int retval, int errval );
107 #ifdef SA_HANDLER_INT_ARG
108 void SPCD_Alarm_Handler (int);
110 void SPCD_Alarm_Handler (void);
111 #endif /* SA_HANDLER_INT_ARG */
115 protocol_request_handler spcd_protocol_dispatch_table[NREQS]={
116 Client_Application_Data, /* APPLICATION_DATA */
117 NULL, /* APPLICATION_STDOUT */
118 NULL, /* APPLICATION_STDERR */
119 Client_Abort, /* ABORT */
120 Client_Register, /* REGISTER */
121 Client_Unregister, /* UNREGISTER */
122 Client_Channel_Open, /* CHANNEL_OPEN */
123 Client_Channel_Close, /* CHANNEL_CLOSE */
124 Client_Channel_Reset, /* CHANNEL_RESET */
125 Client_Channel_Attach, /* CHANNEL_ATTACH */
126 Client_Application_Spawn, /* APPLICATION_SPAWN */
127 Client_Application_Signal, /* APPLICATION_SIGNAL */
128 NULL, /* APPLICATION_DIED */
129 NULL, /* SERVER_ERROR */
131 Client_Server_Debug, /* SERVER_DEBUG */
132 Client_Environ_Reset, /* ENVIRON_RESET */
133 Client_Reply_Devices, /* QUERY_DEVICES */
134 NULL, /* DEVICE_REPLY */
135 Client_Reply_Logfile, /* QUERY_LOGFILE */
136 NULL, /* LOGFILE_REPLY */
137 Client_Delete_Logfile, /* DELETE_LOGFILE */
138 Client_Reset_Termio, /* RESET_TERMIO (obsolete) */
139 Client_Reset_Termios, /* RESET_TERMIOS */
140 Client_Send_EOF, /* CHANNEL_SEND_EOF */
141 Client_Channel_Termios, /* CHANNEL_TERMIOS */
142 Client_Enhanced_Spawn, /* APP_B00_SPAWN */
146 * HomeDir will be set to "HOME=pwent->pw_dir".
148 * ShellDir will be set to "SHELL=pwent->pw_shell".
150 XeChar HomeDir[MAXPATHLEN + 6];
151 XeChar ShellDir[MAXPATHLEN + 7];
152 XeString *default_environment;
154 int client_validated=NULL;
155 int SPCD_Abort_Okay = FALSE;
157 SPC_Connection_Ptr client_connection;
159 SPC_Channel client_channel;
162 * This variable contains the number of minutes in the daemon's
163 * exit timer. If the daemon has no activity within this period
164 * of time and there are no sub-processes running, the daemon
167 static int exit_timeout = SPCD_DEFAULT_TIMEOUT;
170 * The following variable is used by the timer code to indicate
171 * if a request is currently being serviced. This is necessary
172 * because of the following scenario:
174 * t0 - a request is made
175 * t1 - the request is serviced
176 * t2 - the timer expires
177 * t3 - the timer handler sees no sub-processes running so it exits
178 * t4 - request is done, reply to client
180 * This variable is set to SPCD_REQUEST_PENDING at t0 and to
181 * SPCD_NO_REQUST_PENDING at t4. If at t3 the variable is set
182 * to SPCD_REQUEST_PENDING, the alarm will be reset and the
183 * daemon will continue.
185 static int request_pending = SPCD_NO_REQUEST_PENDING;
187 /*----------------------------------------------------------------------+*/
188 int main(unsigned int argc, XeString *argv)
189 /*----------------------------------------------------------------------+*/
191 /* Parse the command line and set globals accordingly. */
192 XeString log_path = NULL;
193 Boolean terminate_flag = FALSE;
195 struct sigaction alarm_vector;
200 * The SPC library needs to know this is a SPC 'daemon' process
201 * to ensure 'SPC_Initialize()' installs a SIGCLD handler.
203 SPC_who_am_i = SPC_I_AM_A_DAEMON;
204 SPCD_Authentication_Dir = NULL;
206 /* set up log file path */
207 log_path = XeSBTempPath((XeString)"DTSPCD.log");
209 freopen("/dev/null", "w", stderr);
211 /* Process arguments and set flags. */
212 for (i=1; i < argc; i++) {
214 if (!strcmp ("-log", argv[i])) {
215 /* Log mode. Print information to a log file */
216 /* Open an error log with whatever name the library wants to use */
217 SPC_Open_Log(log_path, FALSE);
220 else if (!strcmp ("-debug", argv[i])) {
221 /* Debug mode. Print protocol information to a log file */
222 /* Open an error log with whatever name the library wants to use */
223 SPC_Open_Log(log_path, FALSE);
224 SPC_Print_Protocol = spc_logF;
225 freopen(log_path, "a", stderr);
226 setbuf(stderr, NULL);
229 else if (!strcmp ("-auth_dir", argv[i])) {
231 * Used to override the default directory for authentication file
235 SPC_Format_Log((XeString)"Authentication directory set to '%s'.",
237 SPCD_Authentication_Dir = strdup (argv[i]);
241 else if (!strcmp ("-mount_point", argv[i])) {
243 * Mount point for the filename mapping system.
247 (void) sprintf (tmp, "%s=%s", MOUNT_POINT, argv[i]);
248 if (putenv (tmp) == 0) {
249 SPC_Format_Log((XeString)"Mount point set to '%s'.", argv[i]);
250 SPC_mount_point_env_var = (char *) malloc (strlen (tmp) + 1);
251 (void) strcpy (SPC_mount_point_env_var, tmp);
254 SPC_Format_Log((XeString)"Failed to add the mount point '%s' to the environment.", tmp);
258 else if (!strcmp ("-timeout", argv[i])) {
260 * The timeout is specified, so use it instead of the default.
264 exit_timeout = atoi(argv[i]);
265 SPC_Format_Log((XeString)"Setting the exit timer to '%s' minutes.",
272 * Unknown command option
274 SPC_Format_Log((XeString)"Command line option '%s' unrecognized.",
279 /* free strings allocated for path */
283 * Initialize the i/o function pointers.
285 SbAddInput_hookfn = SPCD_AddInput;
286 SbAddException_hookfn = SPCD_AddException;
287 SbRemoveInput_hookfn = SPCD_RemoveInput;
288 SbRemoveException_hookfn = SPCD_RemoveException;
289 SbMainLoopUntil_hookfn = SPCD_MainLoopUntil;
290 SbBreakMainLoop_hookfn = SPCD_BreakMainLoop;
292 /* Initialization Commands */
293 if (SPCD_Initialize()==SPC_ERROR)
296 client_connection=SPC_Start_Daemon(FALSE);
297 if(client_connection==SPC_ERROR)
300 client_channel.connection = client_connection;
302 SPC_XtAddInput(&client_channel,
303 &client_connection->termination_id,
304 client_connection->sid,
305 SPCD_Handle_Client_Data,
308 if (exit_timeout != SPCD_NO_TIMER) {
309 alarm_vector.sa_handler = SPCD_Alarm_Handler;
310 alarm_vector.sa_flags = 0;
311 (void) sigaction (SIGALRM, &alarm_vector, (struct sigaction *)NULL);
312 (void) alarm (exit_timeout * 60);
316 * The daemon's mount point environment variable needs to be
317 * saved. It will be used to override the client's mount point
318 * setting or the mount point specified in any of the environment
321 if (SPC_mount_point_env_var == NULL)
322 if ((pch = getenv (MOUNT_POINT)) != NULL) {
323 SPC_mount_point_env_var = (char *) malloc (strlen (pch) +
324 strlen (MOUNT_POINT) + 2);
325 (void) sprintf (SPC_mount_point_env_var, "%s=%s", MOUNT_POINT, pch);
328 XeCall_SbMainLoopUntil(&terminate_flag);
332 /*----------------------------------------------------------------------+*/
333 void SPCD_Handle_Client_Data(void *channel,
334 int *UNUSED_PARM(source),
335 SbInputId *UNUSED_PARM(id))
336 /*----------------------------------------------------------------------+*/
338 protocol_request_ptr prot;
340 SPC_Connection_Ptr connection=((SPC_Channel_Ptr)channel)->connection;
342 request_pending = SPCD_REQUEST_PENDING;
344 prot=SPC_Read_Protocol(connection);
348 /* Check for valid client (in other words, that we have registered
351 if((!client_validated) && (prot->request_type != REGISTER)) {
352 SPC_Error(SPC_Client_Not_Valid);
353 if (exit_timeout != SPCD_NO_TIMER)
354 (void) alarm (exit_timeout * 60);
355 request_pending = SPCD_REQUEST_PENDING;
359 SPCD_Abort_Okay = TRUE;
360 retval=SPC_Dispatch_Protocol(prot, spcd_protocol_dispatch_table);
361 SPCD_Abort_Okay = FALSE;
362 if(REPLY_EXPECTED(prot->request_type, TRUE) != NO_REPLY_VAL)
363 SPCD_Reply(connection, prot, retval, errno);
364 SPC_Free_Protocol_Ptr(prot);
367 * Reset the alarm and go back to select.
369 if (exit_timeout != SPCD_NO_TIMER)
370 (void) alarm (exit_timeout * 60);
372 request_pending = SPCD_NO_REQUEST_PENDING;
375 /*----------------------------------------------------------------------+*/
376 int SPCD_Initialize(void)
377 /*----------------------------------------------------------------------+*/
379 XeString sys_env_file = NULL;
381 /* Do initialization for SPC */
382 if(SPC_Initialize()==SPC_ERROR)
385 /* Do Daemon specific initialization */
389 XeProgName=SPCD_PROG_NAME;
392 (XeString *) malloc(DEFAULT_ENVP_SIZE * sizeof(XeString));
393 default_environment[0]=NULL;
396 * First add the installed environment file.
398 sys_env_file = (XeString) malloc (strlen(SPCD_ENV_INSTALL_DIRECTORY) +
399 strlen(SPCD_ENV_FILE) + 3);
400 (void) sprintf (sys_env_file, "%s/%s",
401 SPCD_ENV_INSTALL_DIRECTORY,
403 default_environment=SPC_Add_Env_File(sys_env_file,default_environment);
406 * Now add the configured environment file.
408 sys_env_file = (XeString) realloc (sys_env_file,
409 strlen(SPCD_ENV_CONFIG_DIRECTORY) +
410 strlen(SPCD_ENV_FILE) + 3);
411 (void) sprintf (sys_env_file, "%s/%s",
412 SPCD_ENV_CONFIG_DIRECTORY,
415 default_environment=SPC_Add_Env_File(sys_env_file,default_environment);
422 /*----------------------------------------------------------------------+*/
423 void SPCD_Exit(int exitval)
424 /*----------------------------------------------------------------------+*/
428 if (SPC_logfile_list != NULL)
429 for (i = 0; SPC_logfile_list[i] != NULL; i++)
430 (void) unlink (SPC_logfile_list[i]);
432 SPC_Format_Log((XeString)"Exiting server. Retval: %d", exitval);
438 /*----------------------------------------------------------------------+*/
439 void SPCD_Handle_Application_Data(void * chn,
443 /*----------------------------------------------------------------------+*/
445 SPC_Channel_Ptr channel= (SPC_Channel_Ptr) chn;
446 SPC_Write_Protocol_Request(client_connection, channel,
447 CONNECTOR_TO_PROT(conn_type), text, size);
451 /*----------------------------------------------------------------------+*/
452 void SPCD_Termination_Handler(SPC_Channel_Ptr channel,
453 int UNUSED_PARM(pid),
454 int UNUSED_PARM(type),
455 int UNUSED_PARM(cause),
456 void * UNUSED_PARM(data))
457 /*----------------------------------------------------------------------+*/
459 /* Write a termination protocol request */
461 SPC_Write_Protocol_Request(client_connection, channel,
462 APPLICATION_DIED, channel->status);
464 /* That's all, folks! */
469 *** Protocol request handlers
473 /*----------------------------------------------------------------------+*/
474 int Client_Abort(protocol_request_ptr prot)
475 /*----------------------------------------------------------------------+*/
477 return(print_protocol_request((XeString)"--> ABORT", prot));
480 #define FREE_USER_PASS(a, b) free(a); free(b);
482 /*----------------------------------------------------------------------+*/
483 int Client_Register(protocol_request_ptr prot)
484 /*----------------------------------------------------------------------+*/
490 struct passwd *pwent;
491 XeString tmpfile, tmppath;
492 XeChar buffer[MAXPATHLEN * 2];
495 int free_netfile = 0;
496 char *spc_prefix = "/.SPC_";
498 char tmpnam_buf[L_tmpnam + 1];
500 print_protocol_request((XeString)"--> REGISTER", prot);
503 READ_REGISTER(prot->dataptr, username, passwd, proto_ver, hostinfo);
505 if(strcmp(username, "") != 0) {
506 SPC_Format_Log ( "+++> Starting authentication for user '%s'\n from host '%s'.",
509 * We have a username so generate a temp filename and send it
510 * back to the client after creating the proper path for the file.
512 if(SPCD_Authentication_Dir)
514 * Use the directory specified on the command line.
516 tmppath = strdup(SPCD_Authentication_Dir);
519 * Use the $HOME directory if it can be retrieved from the
522 if(!(pwent=getpwnam(username))) {
523 SPC_Format_Log ("+++> FAILURE: username '%s' is unknown.", username);
524 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
525 FAILED_FILE_NAME, NULL, NULL);
526 FREE_USER_PASS(username, passwd);
527 SPC_Error(SPC_Bad_Username);
531 tmppath = (XeString)(pwent->pw_dir);
533 if ((lstat (tmppath, &buf) != 0) ||
534 (!S_ISDIR(buf.st_mode)) ||
535 (!(buf.st_mode & S_IRUSR)))
537 * Use the default directory.
539 tmppath = XeSBTempPath(XeString_NULL);
544 * tempnam(3) has side effects caused by permissions of the directory
545 * given or the TMPDIR envirnoment variable. Because of these side
546 * effects, the function may return "/tmp/.SPC_xxxxxx" and ignore
547 * tmppath. The protocol will fail when this occurs. The fix is
548 * to construct the tmpfile name.
551 spc_suffix = basename(tmpnam_buf); /* Don't free result - not alloc'd! */
553 /* Allocate space for tmppath, spc_prefix, and spc_suffix. */
554 tmpfile = (char *)malloc((strlen(tmppath) + strlen(spc_prefix) +
555 strlen(spc_suffix) + 1) * sizeof(char));
556 sprintf(tmpfile, "%s%s%s", tmppath, spc_prefix, spc_suffix);
561 * No username was supplied (this could happen with pre-CDE
562 * clients) so generate a temp filename.
564 if(SPCD_Authentication_Dir)
565 tmppath = strdup(SPCD_Authentication_Dir);
567 tmppath = XeSBTempPath(XeString_NULL);
568 tmpfile = tempnam(tmppath, ".SPC_" );
572 SPC_Format_Log ("+++> FAILURE: NULL username.");
573 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
574 FAILED_FILE_NAME, NULL, NULL);
575 FREE_USER_PASS(username, passwd);
576 SPC_Error(SPC_Bad_Username);
582 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
583 FAILED_FILE_NAME, NULL, NULL);
584 SPC_Format_Log("+++> FAILURE: cannot malloc.");
585 SPC_Error(SPC_Out_Of_Memory);
590 * Store info about the client (protocol version & host type)
591 * For Pre A.01, this will be defaulted to (hpux 7.0 s300)
593 client_connection->hostinfo = hostinfo;
596 (void) sscanf(proto_ver, "%d", &client_connection->protocol_version);
597 SPC_client_version_number = client_connection->protocol_version;
601 /* The client didn't send a protocol_version so set it to "1". */
602 SPC_client_version_number = 1;
604 SPC_Format_Log(" Client protocol version is '%d'.",
605 SPC_client_version_number);
606 SPC_Format_Log("+++> Authentication file is '%s'.", tmpfile);
609 * For non-CDE clients, the clients expect the daemon to send
610 * a "real" file name. Beginning with 'SPC_PROTOCOL_VERSION_CDE_BASE'
611 * the clients are expecting a "netfile" name.
615 if (SPC_client_version_number >= SPC_PROTOCOL_VERSION_CDE_BASE) {
616 netfile = tt_file_netfile (tmpfile);
618 if (tt_ptr_error (netfile) != TT_OK) {
619 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
620 FAILED_FILE_NAME, NULL, NULL);
621 SPC_Format_Log("+++> FAILURE: cannot create a cannonical file name for the authentication file.\n (%s)",
622 tt_status_message(tt_pointer_error(netfile)));
624 SPC_Error(SPC_Bad_Authentication);
628 SPC_Format_Log(" Authentication 'netfile' is '%s'.", netfile);
631 /* As we send the next packet, include protocol and host info about */
632 /* us (the server). If going to a pre A.02 client, it will be */
635 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
636 netfile, SPC_PROTOCOL_VERSION_STR,
637 SPC_LocalHostinfo());
639 prot=SPC_Filter_Connection(client_connection, NULL, REGISTER, TRUE);
642 sprintf(buffer, (XeString)"--> REGISTER (%s)", netfile);
643 print_protocol_request(buffer, prot);
644 SPC_Free_Protocol_Ptr(prot);
646 /* Was the client able to create the authentication */
647 /* file in the temp directory? */
649 if(lstat(tmpfile, &buf)==ERROR) {
650 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
651 FAILED_FILE_NAME, NULL, NULL);
652 SPC_Format_Log("+++> FAILURE: stat authentication file '%s'.", tmpfile);
656 SPC_Error(SPC_Bad_Authentication);
661 * If the file does not have the setuid bit set then return failure.
663 * Note that if the protocol_version is < 2, this bit will
664 * not be set and the client will not be able to connect.
666 if(!(buf.st_mode & S_ISUID)) {
667 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
668 FAILED_FILE_NAME, NULL, NULL);
669 SPC_Format_Log("+++> FAILURE: authentication file '%s' does not have the setuid bit set.",
674 SPC_Error(SPC_Bad_Permission);
682 * Is uid associated with the authentication file created by the
683 * client present in our password file?
685 if(!(pwent=getpwuid(buf.st_uid))) {
686 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
687 FAILED_FILE_NAME, NULL, NULL);
688 SPC_Format_Log("+++> FAILURE: the authentication file created by the client has a uid '%d'\n and this uid is not in the password file.",
690 SPC_Error(SPC_Bad_Username);
697 * Comapre the user name in the request with the user name in
698 * the passwd file. They must be the same to continue.
700 if (strcmp (pwent->pw_name, username) != 0) {
701 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
702 FAILED_FILE_NAME, NULL, NULL);
703 SPC_Format_Log("+++> FAILURE: the request is for username '%s' with uid '%d'\n but this uid has name '%s' in the password file.",
707 SPC_Error(SPC_Bad_Password);
713 client_validated=TRUE;
716 * Need to initialize the group access list if a username
717 * was supplied in the request.
719 if ((initgroups(username, pwent->pw_gid)) == -1) {
720 SPC_Format_Log("+++> FAILURE: initgroups ('%s', '%s')",
725 /* We have authenticated ourselves. Set the process identifiers of
726 this process to the looked up ones. */
727 setgid(pwent->pw_gid);
728 setuid(pwent->pw_uid);
730 Xechdir(pwent->pw_dir);
731 sprintf(HomeDir, (XeString)"HOME=%s", pwent->pw_dir);
732 sprintf(ShellDir, (XeString)"SHELL=%s", pwent->pw_shell);
736 spc_user_environment_file=(XeString)XeMalloc(MAXPATHLEN);
737 sprintf(spc_user_environment_file, (XeString)"%s/%s/%s", pwent->pw_dir,
738 SPCD_ENV_HOME_DIRECTORY, SPCD_ENV_FILE);
740 SPC_Add_Env_File(spc_user_environment_file, default_environment);
742 SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
743 PASSED_FILE_NAME, NULL, NULL);
748 /*----------------------------------------------------------------------+*/
749 int Client_Unregister(protocol_request_ptr prot)
750 /*----------------------------------------------------------------------+*/
752 return(print_protocol_request((XeString)"--> UNREGISTER", prot));
755 /*----------------------------------------------------------------------+*/
756 int Client_Channel_Open(protocol_request_ptr prot)
757 /*----------------------------------------------------------------------+*/
760 SPC_Channel_Ptr channel;
762 print_protocol_request((XeString)"--> CHANNEL_OPEN", prot);
763 READ_OPEN(prot->dataptr, iomode);
765 /* Don't ever wanna wait, do line-oriented reads,
766 use the toolkit, or execute as a system command */
768 /* We don't do system commands because the client side has
769 already converted the channel into the proper form for us */
771 iomode &= ~(SPCIO_WAIT | SPCIO_LINEORIENTED |
772 SPCIO_USE_XTOOLKIT | SPCIO_SYSTEM);
774 /* However, we do always want our termination to be synchronous */
776 iomode |= SPCIO_SYNC_TERMINATOR;
778 channel=XeSPCOpen(NULL, iomode);
779 if(channel==SPC_ERROR)
782 XeSPCAddInput(channel, SPCD_Handle_Application_Data, channel);
783 XeSPCRegisterTerminator(channel, SPCD_Termination_Handler, channel);
785 return((int) channel);
788 /*----------------------------------------------------------------------+*/
789 int Client_Channel_Close(protocol_request_ptr prot)
790 /*----------------------------------------------------------------------+*/
792 SPC_Channel_Ptr channel=prot->channel;
794 print_protocol_request((XeString)"--> CHANNEL_CLOSE", prot);
796 if(IS_ACTIVE(channel)) {
799 Uh-oh. We have recieved a close request, but the channel is
800 active. We kill the process, and explicitly wait for the
801 process to terminate.
804 XeSPCSignalProcess(channel, SIGKILL);
805 SPC_Wait_For_Termination(channel);
808 return(XeSPCClose(channel));
811 /*----------------------------------------------------------------------+*/
812 int Client_Channel_Reset(protocol_request_ptr prot)
813 /*----------------------------------------------------------------------+*/
815 SPC_Channel_Ptr channel=prot->channel;
817 print_protocol_request((XeString)"--> CHANNEL_RESET", prot);
819 return(XeSPCReset(channel));
822 /*----------------------------------------------------------------------+*/
823 int Client_Channel_Attach(protocol_request_ptr prot)
824 /*----------------------------------------------------------------------+*/
826 SPC_Channel_Ptr channel=prot->channel;
829 print_protocol_request((XeString)"--> ATTACH", prot);
831 READ_ATTACH(prot->dataptr, pid);
832 return(XeSPCAttach(channel, pid));
836 Merge_Lang_Var(SPC_Channel_Ptr channel)
840 if ((stdLang = SPC_Getenv((XeString)"LANG", channel->envp))
843 _DtXlateDb db = NULL;
844 char platform[_DtPLATFORM_MAX_LEN];
850 if (_DtLcxOpenAllDbs(&db) == 0)
852 if ((_DtXlateGetXlateEnv(db, platform, &execVer, &compVer) == 0) &&
853 (_DtLcxXlateStdToOp(db, platform, compVer, DtLCX_OPER_SETLOCALE,
854 stdLang, NULL, NULL, NULL, &myLang) == 0))
856 if ((langBuf = (XeChar *)malloc((strlen(myLang) + 6)
860 sprintf(langBuf, "LANG=%s", myLang);
861 channel->envp = SPC_Putenv(langBuf, channel->envp);
873 /*----------------------------------------------------------------------+*/
874 int Client_Application_Spawn(protocol_request_ptr prot)
875 /*----------------------------------------------------------------------+*/
877 SPC_Channel_Ptr channel=prot->channel;
880 print_protocol_request((XeString)"--> APPLICATION_SPAWN", prot);
881 READ_APPLICATION_SPAWN(prot->dataptr,
883 channel->context_dir,
884 channel->argv, channel->envp);
886 Merge_Lang_Var(channel);
888 channel->IOMode |= SPCIO_DEALLOC_ARGV;
890 channel->envp=SPC_Merge_Envp(channel->envp, default_environment);
892 retval=XeSPCExecuteProcess(channel);
893 if(retval==SPC_ERROR)
896 return(channel->pid);
899 /*----------------------------------------------------------------------+*/
900 int Client_Application_Signal(protocol_request_ptr prot)
901 /*----------------------------------------------------------------------+*/
905 SPC_Channel_Ptr channel=prot->channel;
907 print_protocol_request((XeString)"--> APPLICATION_SIGNAL", prot);
908 READ_STRING_NO_COPY(prot->dataptr, signame);
910 if (client_connection->protocol_version >= 2) {
911 if ( (sig = XeNameToSignal( signame )) == XE_SIG_NOT_IN_TABLE ) {
912 SPC_Error(SPC_Bad_Signal_Name, signame);
916 /* Must be the old 1.0, 1.1 protocol, assume its a number. */
917 /* Note however, that this is not portable as the signal numbers */
918 /* differ from system to system. This should really be an error */
920 /* 1.0 code allowed signal 0 (check if process alive), but its */
921 /* part of XPG3 so we don't honor it .. nobody ever used it anyway */
923 int ok = sscanf(signame, "%x", &sig); /* WRITE_INT (%x) was used */
924 if ( (ok == EOF) || (sig == 0) ) {
925 SPC_Error(SPC_Bad_Signal_Format, signame);
930 return(XeSPCSignalProcess(channel, sig));
933 /*----------------------------------------------------------------------+*/
934 int Client_Application_Data(protocol_request_ptr prot)
935 /*----------------------------------------------------------------------+*/
937 SPC_Channel_Ptr channel=prot->channel;
938 buffered_data_ptr pdata=prot->dataptr;
940 print_protocol_request((XeString)"--> APPLICATION_DATA", prot);
942 return(XeSPCWrite(channel,
943 pdata->data+REQUEST_HEADER_LENGTH,
947 /*----------------------------------------------------------------------+*/
948 int Client_Server_Debug(protocol_request_ptr prot)
949 /*----------------------------------------------------------------------+*/
951 SPC_Channel_Ptr channel=prot->channel;
952 buffered_data_ptr pdata=prot->dataptr;
953 XeChar filename[MAXPATHLEN];
956 print_protocol_request((XeString)"--> SERVER_DEBUG", prot);
957 READ_DEBUG(pdata, filename);
959 if(SPC_Print_Protocol)
960 fclose(SPC_Print_Protocol);
962 SPC_Print_Protocol=fopen(filename, (XeString)"a+");
964 if(!SPC_Print_Protocol)
967 setbuf(SPC_Print_Protocol, NULL);
970 fprintf(SPC_Print_Protocol, (XeString)"Begin protocol filedump: %s", ctime(&timeval));
976 *** The purpose of this routine is to filter out environment variables
977 *** which should not get put into the environment.
981 /*----------------------------------------------------------------------+*/
982 void conditional_putenv(XeString env_str)
983 /*----------------------------------------------------------------------+*/
985 if(strncmp(env_str, (XeString)"HOME=", 5) && /* HOME may be different */
986 strncmp(env_str, (XeString)"PWD=", 4) /* PWD set by chdir, may change */
987 /* Should SHELL be on this list? */
994 /*----------------------------------------------------------------------+*/
995 int Client_Environ_Reset(protocol_request_ptr prot)
996 /*----------------------------------------------------------------------+*/
1004 READ_ENVIRON_RESET(prot->dataptr, num_vars);
1008 ret = SPC_Get_Multi_Packet(client_connection, prot,
1010 ENVIRON_RESET, "--> ENVIRON_RESET");
1015 for(i=0; i<outlen; i++)
1016 if(ret[i] && *ret[i])
1017 conditional_putenv(ret[i]);
1025 /*----------------------------------------------------------------------+*/
1026 int Client_Reply_Devices(protocol_request_ptr prot)
1027 /*----------------------------------------------------------------------+*/
1029 SPC_Channel_Ptr channel=prot->channel;
1031 print_protocol_request((XeString)"--> QUERY_DEVICES", prot);
1033 SPC_Write_Protocol_Request(client_connection, channel, DEVICE_REPLY,
1034 channel->wires[STDIN]->master_name,
1035 channel->wires[STDIN]->slave_name,
1036 channel->wires[STDOUT]->master_name,
1037 channel->wires[STDOUT]->slave_name,
1038 channel->wires[STDERR]->master_name,
1039 channel->wires[STDERR]->slave_name);
1043 /*----------------------------------------------------------------------+*/
1044 int Client_Reply_Logfile(protocol_request_ptr prot)
1045 /*----------------------------------------------------------------------+*/
1048 SPC_Channel_Ptr channel=prot->channel;
1050 print_protocol_request((XeString)"--> QUERY_LOGFILE", prot);
1052 if (SPC_client_version_number >= SPC_PROTOCOL_VERSION_CDE_BASE &&
1053 IS_SPCIO_USE_LOGFILE(channel->IOMode)) {
1054 netfile = tt_file_netfile (channel->logfile);
1056 if (tt_ptr_error (netfile) != TT_OK) {
1057 SPC_Format_Log("+++> FAILURE: cannot create a 'netfile' name for the logfile.\n (%s)",
1058 tt_status_message(tt_pointer_error(netfile)));
1062 SPC_Write_Protocol_Request(client_connection, channel, LOGFILE_REPLY,
1063 netfile, NULL, NULL);
1067 SPC_Write_Protocol_Request(client_connection, channel, LOGFILE_REPLY,
1068 channel->logfile, NULL, NULL);
1073 /*----------------------------------------------------------------------+*/
1074 int Client_Delete_Logfile(protocol_request_ptr prot)
1075 /*----------------------------------------------------------------------+*/
1077 SPC_Channel_Ptr channel=prot->channel;
1079 print_protocol_request((XeString)"--> DELETE_LOGFILE", prot);
1081 return(XeSPCRemoveLogfile(channel));
1084 /*----------------------------------------------------------------------+*/
1085 int Client_Reset_Termio(protocol_request_ptr prot)
1086 /*----------------------------------------------------------------------+*/
1088 /* This handles old 1.0 versions of the SPC code. We used to send */
1089 /* an hp-ux version of the termio struct in a non-portable manner */
1090 /* We need to be able to "eat" such an request if we get one. */
1092 print_protocol_request((XeString)"--> RESET_TERMIO", prot);
1094 return(SPC_Get_Termio(prot));
1097 /*----------------------------------------------------------------------+*/
1098 int Client_Reset_Termios(protocol_request_ptr prot)
1099 /*----------------------------------------------------------------------+*/
1101 print_protocol_request((XeString)"--> RESET_TERMIOS", prot);
1103 return(SPC_Get_Termios(prot));
1106 /* New B.00 methods */
1108 /*----------------------------------------------------------------------+*/
1109 int Client_Send_EOF(protocol_request_ptr prot)
1110 /*----------------------------------------------------------------------+*/
1112 SPC_Channel_Ptr channel=prot->channel;
1114 print_protocol_request((XeString)"--> SEND_EOF", prot);
1116 return(XeSPCSendEOF(channel));
1119 int Client_Channel_Termios(protocol_request_ptr prot)
1121 SPC_Channel_Ptr channel=prot->channel;
1123 int connection, side;
1127 print_protocol_request((XeString)"--> CHANNEL_TERMIOS", prot);
1129 READ_TERMIOS(prot->dataptr, connection, side, buffer);
1130 SPC_Encode_Termios(buffer, &t);
1133 return(XeSPCSetTermio(channel, connection, side, &t));
1136 int Client_Enhanced_Spawn(protocol_request_ptr prot)
1138 SPC_Channel_Ptr channel = prot->channel;
1143 int return_value, outlen, i;
1146 READ_ENVIRON_RESET(prot->dataptr, num_vars);
1150 ret = SPC_Get_Multi_Packet(client_connection, prot,
1152 APP_B00_SPAWN, "--> APP_B00_SPAWN");
1157 channel->path = strdup(ret[0]);
1158 channel->context_dir = strdup(ret[1]);
1160 numarg = atoi(ret[2]);
1161 numenv = atoi(ret[3]);
1164 channel->argv = NULL;
1166 channel->argv = &ret[4];
1167 ret[numarg+3] = NULL;
1171 channel->envp = NULL;
1173 channel->envp = (char **)XeMalloc((numenv+1)*sizeof(char *));
1174 channel->envp[0] = NULL;
1175 channel->envp = SPC_Merge_Envp(channel->envp, &ret[numarg+4]);
1177 Merge_Lang_Var(channel);
1179 channel->envp = SPC_Merge_Envp(channel->envp, default_environment);
1182 return_value = XeSPCExecuteProcess(channel);
1184 /* Make the world safe for freeing the channel */
1186 channel->argv = NULL;
1187 if(channel->envp == &ret[numarg+4])
1188 channel->envp = NULL;
1190 for(i=0; i<outlen; i++)
1197 if(return_value==SPC_ERROR)
1200 return(channel->pid);
1203 /*----------------------------------------------------------------------+*/
1204 void SPCD_Reply(SPC_Connection_Ptr connection,
1205 protocol_request_ptr prot,
1208 /*----------------------------------------------------------------------+*/
1210 if(retval==SPC_ERROR)
1211 retval= (-XeSPCErrorNumber);
1213 SPC_Write_Reply(connection, prot, retval, errval);
1216 /*----------------------------------------------------------------------+*/
1218 * This function is invoked when the exit timer expires.
1219 * If sub-processes are running, return to select;
1222 #ifdef SA_HANDLER_INT_ARG
1223 void SPCD_Alarm_Handler(int not_used)
1225 void SPCD_Alarm_Handler()
1226 #endif /* SA_HANDLER_INT_ARG */
1227 /*----------------------------------------------------------------------+*/
1231 if (exit_timeout == SPCD_NO_TIMER)
1234 if (SPC_pid_list != NULL)
1235 for (i=0; SPC_pid_list[i] != NULL; i++) {
1236 if (SPC_pid_list[i] != SPCD_DEAD_PROCESS) {
1238 * Have at least one sub- process running so reset the
1239 * alarm and return to select.
1241 (void) alarm (exit_timeout * 60);
1247 * There are no sub-processes running. Exit if a request is not pending
1249 if (request_pending != SPCD_REQUEST_PENDING) {
1250 SPC_Format_Log((XeString)
1251 "Exit timer expired after '%d' minutes of no activity.",