xref: /illumos-gate/usr/src/lib/krb5/ss/listen.c (revision e41409bfa05152ed1ac94578d69a0444e4ab6904)
17c478bd9Sstevel@tonic-gate /*
26d084746S  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
356a424ccSmp153739  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Listener loop for subsystem library libss.a.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  *	util/ss/listen.c
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * Copyright 1987, 1988 by MIT Student Information Processing Board
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * For copyright information, see copyright.h.
147c478bd9Sstevel@tonic-gate  */
157c478bd9Sstevel@tonic-gate 
167c478bd9Sstevel@tonic-gate #include "copyright.h"
177c478bd9Sstevel@tonic-gate #include "ss_internal.h"
187c478bd9Sstevel@tonic-gate #include <stdio.h>
197c478bd9Sstevel@tonic-gate #include <setjmp.h>
207c478bd9Sstevel@tonic-gate #include <signal.h>
2156a424ccSmp153739 #include <termios.h>
227c478bd9Sstevel@tonic-gate #include <libintl.h>
237c478bd9Sstevel@tonic-gate #include <sys/param.h>
246d084746S /* Solaris Kerberos */
256d084746S #include <libtecla.h>
266d084746S 
276d084746S #define	MAX_LINE_LEN BUFSIZ
286d084746S #define	MAX_HIST_LEN 8192
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate static ss_data *current_info;
317c478bd9Sstevel@tonic-gate static jmp_buf listen_jmpb;
327c478bd9Sstevel@tonic-gate 
print_prompt()337c478bd9Sstevel@tonic-gate static RETSIGTYPE print_prompt()
347c478bd9Sstevel@tonic-gate {
3556a424ccSmp153739     struct termios termbuf;
3656a424ccSmp153739 
3756a424ccSmp153739     if (tcgetattr(STDIN_FILENO, &termbuf) == 0) {
3856a424ccSmp153739 	termbuf.c_lflag |= ICANON|ISIG|ECHO;
3956a424ccSmp153739 	tcsetattr(STDIN_FILENO, TCSANOW, &termbuf);
407c478bd9Sstevel@tonic-gate     }
417c478bd9Sstevel@tonic-gate     (void) fputs(current_info->prompt, stdout);
427c478bd9Sstevel@tonic-gate     (void) fflush(stdout);
437c478bd9Sstevel@tonic-gate }
447c478bd9Sstevel@tonic-gate 
listen_int_handler(signo)457c478bd9Sstevel@tonic-gate static RETSIGTYPE listen_int_handler(signo)
467c478bd9Sstevel@tonic-gate     int signo;
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate     putc('\n', stdout);
497c478bd9Sstevel@tonic-gate     longjmp(listen_jmpb, 1);
507c478bd9Sstevel@tonic-gate }
516d084746S /* Solaris Kerberos */
526d084746S typedef struct _ss_commands {
536d084746S 	int sci_idx;
546d084746S 	const char **cmd;
556d084746S 	unsigned int count;
566d084746S } ss_commands;
576d084746S 
586d084746S /*
596d084746S  * Solaris Kerberos
606d084746S  * get_commands fills out a ss_commands structure with pointers
616d084746S  * to the top-level commands (char*) that a program supports.
626d084746S  * count reflects the number of commands cmd holds. Memory must
636d084746S  * be allocated by the caller.
646d084746S  */
get_commands(ss_commands * commands)656d084746S void get_commands(ss_commands *commands) {
666d084746S 	const char * const *cmd;
676d084746S 	ss_request_table **table;
686d084746S 	ss_request_entry *request;
696d084746S 	ss_data *info;
706d084746S 
716d084746S 	commands->count = 0;
726d084746S 
736d084746S 	info = ss_info(commands->sci_idx);
746d084746S 	for (table = info->rqt_tables; *table; table++) {
756d084746S 		for (request = (*table)->requests;
766d084746S 		    request->command_names != NULL; request++) {
776d084746S 			for (cmd = request->command_names;
786d084746S 			    cmd != NULL && *cmd != NULL; cmd++) {
796d084746S 				if (commands->cmd != NULL)
806d084746S 					commands->cmd[commands->count] = *cmd;
816d084746S 				commands->count++;
826d084746S 			}
836d084746S 		}
846d084746S 	}
856d084746S }
866d084746S 
876d084746S /*
886d084746S  * Solaris Kerberos
896d084746S  * Match function used by libtecla for tab-completion.
906d084746S  */
CPL_MATCH_FN(cmdmatch)916d084746S CPL_MATCH_FN(cmdmatch) {
926d084746S 	int argc, len, ws, i;
936d084746S 	char **argv, *l;
946d084746S 	ss_commands *commands = data;
956d084746S 	int ret = 0;
966d084746S 
976d084746S 	/* Dup the line as ss_parse will modify the string */
986d084746S 	l = strdup(line);
996d084746S 	if (l == NULL)
1006d084746S 		return (ret);
1016d084746S 
1026d084746S 	/* Tab-completion may happen in the middle of a line */
1036d084746S 	if (word_end != strlen(l))
1046d084746S 		l[word_end] = '\0';
1056d084746S 
1066d084746S 	if (ss_parse(commands->sci_idx, l, &argc, &argv, 1)) {
1076d084746S 		free (l);
1086d084746S 		return (ret);
1096d084746S 	}
1106d084746S 
1116d084746S 	/* Don't bother if the arg count is not 1 or 0 */
1126d084746S 	if (argc < 2) {
1136d084746S 		len = argc ? strlen(argv[0]) : 0;
1146d084746S 		ws = word_end - len;
1156d084746S 
1166d084746S 		for (i = 0; i < commands->count; i++) {
1176d084746S 			if (strncmp(commands->cmd[i], line + ws, len) == 0) {
1186d084746S 				ret = cpl_add_completion(cpl, line, ws,
1196d084746S 				    word_end, commands->cmd[i] + len, "", " ");
1206d084746S 				if (ret)
1216d084746S 					break;
1226d084746S 			}
1236d084746S 		}
1246d084746S 	}
1256d084746S 
1266d084746S 	free(argv);
1276d084746S 	free(l);
1286d084746S 	return (ret);
1296d084746S }
1307c478bd9Sstevel@tonic-gate 
ss_listen(sci_idx)1317c478bd9Sstevel@tonic-gate int ss_listen (sci_idx)
1327c478bd9Sstevel@tonic-gate     int sci_idx;
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate     register char *cp;
1357c478bd9Sstevel@tonic-gate     register ss_data *info;
1367c478bd9Sstevel@tonic-gate     char buffer[BUFSIZ];
13756a424ccSmp153739     char *volatile end = buffer;
1387c478bd9Sstevel@tonic-gate     int code;
1396d084746S 
1406d084746S     /* Solaris Kerberos */
1416d084746S     char *input;
1426d084746S     GetLine *gl;
1436d084746S     GlReturnStatus ret;
1446d084746S     ss_commands commands;
1456d084746S 
1467c478bd9Sstevel@tonic-gate     jmp_buf old_jmpb;
1477c478bd9Sstevel@tonic-gate     ss_data *old_info = current_info;
1487c478bd9Sstevel@tonic-gate #ifdef POSIX_SIGNALS
1497c478bd9Sstevel@tonic-gate     struct sigaction isig, csig, nsig, osig;
1507c478bd9Sstevel@tonic-gate     sigset_t nmask, omask;
1517c478bd9Sstevel@tonic-gate #else
1527c478bd9Sstevel@tonic-gate     register RETSIGTYPE (*sig_cont)();
1537c478bd9Sstevel@tonic-gate     RETSIGTYPE (*sig_int)(), (*old_sig_cont)();
1547c478bd9Sstevel@tonic-gate     int mask;
1557c478bd9Sstevel@tonic-gate #endif
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate     current_info = info = ss_info(sci_idx);
1587c478bd9Sstevel@tonic-gate     info->abort = 0;
1597c478bd9Sstevel@tonic-gate 
1606d084746S     /* Solaris Kerberos */
1616d084746S     gl = new_GetLine(MAX_LINE_LEN, MAX_HIST_LEN);
1626d084746S     if (gl == NULL) {
1636d084746S 	ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
1646d084746S             "new_GetLine() failed.\n"));
1656d084746S 	current_info = old_info;
1666d084746S 	return (SS_ET_TECLA_ERR);
1676d084746S     }
1686d084746S 
1696d084746S     commands.sci_idx = sci_idx;
1706d084746S     commands.cmd = NULL;
1716d084746S 
1726d084746S     /* Find out how many commands there are */
1736d084746S     get_commands(&commands);
1746d084746S 
1756d084746S     /* Alloc space for them */
1766d084746S     commands.cmd = malloc(sizeof (char *) * commands.count);
1776d084746S     if (commands.cmd == NULL) {
1786d084746S 	current_info = old_info;
1796d084746S 	gl = del_GetLine(gl);
1806d084746S 	return (ENOMEM);
1816d084746S     }
1826d084746S 
1836d084746S     /* Fill-in commands.cmd */
1846d084746S     get_commands(&commands);
1856d084746S 
1866d084746S     if (gl_customize_completion(gl, &commands, cmdmatch) != 0 ) {
1876d084746S 	ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
1886d084746S             "failed to register completion function.\n"));
1896d084746S 	free(commands.cmd);
1906d084746S 	current_info = old_info;
1916d084746S 	gl = del_GetLine(gl);
1926d084746S 	return (SS_ET_TECLA_ERR);
1936d084746S     }
1946d084746S 
1957c478bd9Sstevel@tonic-gate #ifdef POSIX_SIGNALS
1967c478bd9Sstevel@tonic-gate     csig.sa_handler = (RETSIGTYPE (*)())0;
1977c478bd9Sstevel@tonic-gate     sigemptyset(&nmask);
1987c478bd9Sstevel@tonic-gate     sigaddset(&nmask, SIGINT);
1997c478bd9Sstevel@tonic-gate     sigprocmask(SIG_BLOCK, &nmask, &omask);
2007c478bd9Sstevel@tonic-gate #else
2017c478bd9Sstevel@tonic-gate     sig_cont = (RETSIGTYPE (*)())0;
2027c478bd9Sstevel@tonic-gate     mask = sigblock(sigmask(SIGINT));
2037c478bd9Sstevel@tonic-gate #endif
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate     memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate #ifdef POSIX_SIGNALS
2087c478bd9Sstevel@tonic-gate     nsig.sa_handler = listen_int_handler;
2097c478bd9Sstevel@tonic-gate     sigemptyset(&nsig.sa_mask);
2107c478bd9Sstevel@tonic-gate     nsig.sa_flags = 0;
2117c478bd9Sstevel@tonic-gate     sigaction(SIGINT, &nsig, &isig);
2127c478bd9Sstevel@tonic-gate #else
2137c478bd9Sstevel@tonic-gate     sig_int = signal(SIGINT, listen_int_handler);
2147c478bd9Sstevel@tonic-gate #endif
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate     setjmp(listen_jmpb);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate #ifdef POSIX_SIGNALS
2197c478bd9Sstevel@tonic-gate     sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
2207c478bd9Sstevel@tonic-gate #else
2217c478bd9Sstevel@tonic-gate     (void) sigsetmask(mask);
2227c478bd9Sstevel@tonic-gate #endif
2236d084746S 
2246d084746S     /*
2256d084746S      * Solaris Kerberos:
2266d084746S      * Let libtecla deal with SIGINT when it's doing its own processing
2276d084746S      * otherwise the input line won't be cleared on SIGINT.
2286d084746S      */
229*e41409bfSToomas Soome     if (gl_trap_signal(gl, SIGINT, GLS_DONT_FORWARD, GLS_ABORT, 0)) {
2306d084746S         ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
2316d084746S             "Failed to trap SIGINT.\n"));
2326d084746S 	code = SS_ET_TECLA_ERR;
2336d084746S 	goto egress;
2346d084746S     }
2356d084746S 
2367c478bd9Sstevel@tonic-gate     while(!info->abort) {
2377c478bd9Sstevel@tonic-gate 	print_prompt();
2387c478bd9Sstevel@tonic-gate 	*end = '\0';
2397c478bd9Sstevel@tonic-gate #ifdef POSIX_SIGNALS
2407c478bd9Sstevel@tonic-gate 	nsig.sa_handler = listen_int_handler;	/* fgets is not signal-safe */
2417c478bd9Sstevel@tonic-gate 	osig = csig;
2427c478bd9Sstevel@tonic-gate 	sigaction(SIGCONT, &nsig, &csig);
2437c478bd9Sstevel@tonic-gate 	if ((RETSIGTYPE (*)())csig.sa_handler==(RETSIGTYPE (*)())listen_int_handler)
2447c478bd9Sstevel@tonic-gate 	    csig = osig;
2457c478bd9Sstevel@tonic-gate #else
2467c478bd9Sstevel@tonic-gate 	old_sig_cont = sig_cont;
2477c478bd9Sstevel@tonic-gate 	sig_cont = signal(SIGCONT, print_prompt);
2487c478bd9Sstevel@tonic-gate 	if (sig_cont == print_prompt)
2497c478bd9Sstevel@tonic-gate 	    sig_cont = old_sig_cont;
2507c478bd9Sstevel@tonic-gate #endif
2516d084746S 
2526d084746S         /* Solaris Kerberos */
2536d084746S         input = gl_get_line(gl, info->prompt, NULL, -1);
2546d084746S         ret = gl_return_status(gl);
2556d084746S 
2566d084746S         switch (ret) {
2576d084746S             case (GLR_SIGNAL):
2586d084746S                 gl_abandon_line(gl);
2596d084746S                 continue;
2606d084746S             case (GLR_EOF):
2616d084746S                 info->abort = 1;
2626d084746S                 continue;
2636d084746S             case (GLR_ERROR):
2646d084746S                 ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
2656d084746S                     "Failed to read line: %s\n"), gl_error_message(gl, NULL, 0));
2666d084746S                 info->abort = 1;
2676d084746S 		code = SS_ET_TECLA_ERR;
2687c478bd9Sstevel@tonic-gate 		goto egress;
2697c478bd9Sstevel@tonic-gate         }
2707c478bd9Sstevel@tonic-gate 	cp = strchr(input, '\n');
2717c478bd9Sstevel@tonic-gate 	if (cp) {
2727c478bd9Sstevel@tonic-gate 	    *cp = '\0';
2737c478bd9Sstevel@tonic-gate 	    if (cp == input)
2747c478bd9Sstevel@tonic-gate 		continue;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate #ifdef POSIX_SIGNALS
2777c478bd9Sstevel@tonic-gate 	sigaction(SIGCONT, &csig, (struct sigaction *)0);
2787c478bd9Sstevel@tonic-gate #else
2797c478bd9Sstevel@tonic-gate 	(void) signal(SIGCONT, sig_cont);
2807c478bd9Sstevel@tonic-gate #endif
2817c478bd9Sstevel@tonic-gate 	for (end = input; *end; end++)
2827c478bd9Sstevel@tonic-gate 	    ;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	code = ss_execute_line (sci_idx, input);
2857c478bd9Sstevel@tonic-gate 	if (code == SS_ET_COMMAND_NOT_FOUND) {
2867c478bd9Sstevel@tonic-gate 	    register char *c = input;
2877c478bd9Sstevel@tonic-gate 	    while (*c == ' ' || *c == '\t')
2887c478bd9Sstevel@tonic-gate 		c++;
2897c478bd9Sstevel@tonic-gate 	    cp = strchr (c, ' ');
2907c478bd9Sstevel@tonic-gate 	    if (cp)
2917c478bd9Sstevel@tonic-gate 		*cp = '\0';
2927c478bd9Sstevel@tonic-gate 	    cp = strchr (c, '\t');
2937c478bd9Sstevel@tonic-gate 	    if (cp)
2947c478bd9Sstevel@tonic-gate 		*cp = '\0';
2957c478bd9Sstevel@tonic-gate 	    ss_error (sci_idx, 0, dgettext(TEXT_DOMAIN,
2967c478bd9Sstevel@tonic-gate 		    "Unknown request \"%s\".  Type \"?\" for a request list."),
2977c478bd9Sstevel@tonic-gate 		       c);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate     }
3007c478bd9Sstevel@tonic-gate     code = 0;
3017c478bd9Sstevel@tonic-gate egress:
3026d084746S 
3036d084746S     /* Solaris Kerberos */
3046d084746S     free(commands.cmd);
3056d084746S     gl = del_GetLine(gl);
3066d084746S 
3077c478bd9Sstevel@tonic-gate #ifdef POSIX_SIGNALS
3087c478bd9Sstevel@tonic-gate     sigaction(SIGINT, &isig, (struct sigaction *)0);
3097c478bd9Sstevel@tonic-gate #else
3107c478bd9Sstevel@tonic-gate     (void) signal(SIGINT, sig_int);
3117c478bd9Sstevel@tonic-gate #endif
3127c478bd9Sstevel@tonic-gate     memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
3137c478bd9Sstevel@tonic-gate     current_info = old_info;
3147c478bd9Sstevel@tonic-gate     return code;
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
ss_abort_subsystem(sci_idx,code)3177c478bd9Sstevel@tonic-gate void ss_abort_subsystem(sci_idx, code)
3187c478bd9Sstevel@tonic-gate     int sci_idx;
3197c478bd9Sstevel@tonic-gate     int code;
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate     ss_info(sci_idx)->abort = 1;
3227c478bd9Sstevel@tonic-gate     ss_info(sci_idx)->exit_status = code;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
ss_quit(argc,argv,sci_idx,infop)3257c478bd9Sstevel@tonic-gate void ss_quit(argc, argv, sci_idx, infop)
3267c478bd9Sstevel@tonic-gate     int argc;
32756a424ccSmp153739     char const * const *argv;
3287c478bd9Sstevel@tonic-gate     int sci_idx;
3297c478bd9Sstevel@tonic-gate     pointer infop;
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate     ss_abort_subsystem(sci_idx, 0);
3327c478bd9Sstevel@tonic-gate }
333