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