2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A/*
2N/A * Listener loop for subsystem library libss.a.
2N/A *
2N/A * util/ss/listen.c
2N/A *
2N/A * Copyright 1987, 1988 by MIT Student Information Processing Board
2N/A *
2N/A * For copyright information, see copyright.h.
2N/A */
2N/A
2N/A#include "copyright.h"
2N/A#include "ss_internal.h"
2N/A#include <stdio.h>
2N/A#include <setjmp.h>
2N/A#include <signal.h>
2N/A#include <termios.h>
2N/A#include <libintl.h>
2N/A#include <sys/param.h>
2N/A/* Solaris Kerberos */
2N/A#include <libtecla.h>
2N/A
2N/A#define MAX_LINE_LEN BUFSIZ
2N/A#define MAX_HIST_LEN 8192
2N/A
2N/Astatic ss_data *current_info;
2N/Astatic jmp_buf listen_jmpb;
2N/A
2N/Astatic RETSIGTYPE print_prompt()
2N/A{
2N/A struct termios termbuf;
2N/A
2N/A if (tcgetattr(STDIN_FILENO, &termbuf) == 0) {
2N/A termbuf.c_lflag |= ICANON|ISIG|ECHO;
2N/A tcsetattr(STDIN_FILENO, TCSANOW, &termbuf);
2N/A }
2N/A (void) fputs(current_info->prompt, stdout);
2N/A (void) fflush(stdout);
2N/A}
2N/A
2N/Astatic RETSIGTYPE listen_int_handler(signo)
2N/A int signo;
2N/A{
2N/A putc('\n', stdout);
2N/A longjmp(listen_jmpb, 1);
2N/A}
2N/A/* Solaris Kerberos */
2N/Atypedef struct _ss_commands {
2N/A int sci_idx;
2N/A const char **cmd;
2N/A unsigned int count;
2N/A} ss_commands;
2N/A
2N/A/*
2N/A * Solaris Kerberos
2N/A * get_commands fills out a ss_commands structure with pointers
2N/A * to the top-level commands (char*) that a program supports.
2N/A * count reflects the number of commands cmd holds. Memory must
2N/A * be allocated by the caller.
2N/A */
2N/Avoid get_commands(ss_commands *commands) {
2N/A const char * const *cmd;
2N/A ss_request_table **table;
2N/A ss_request_entry *request;
2N/A ss_data *info;
2N/A
2N/A commands->count = 0;
2N/A
2N/A info = ss_info(commands->sci_idx);
2N/A for (table = info->rqt_tables; *table; table++) {
2N/A for (request = (*table)->requests;
2N/A request->command_names != NULL; request++) {
2N/A for (cmd = request->command_names;
2N/A cmd != NULL && *cmd != NULL; cmd++) {
2N/A if (commands->cmd != NULL)
2N/A commands->cmd[commands->count] = *cmd;
2N/A commands->count++;
2N/A }
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos
2N/A * Match function used by libtecla for tab-completion.
2N/A */
2N/ACPL_MATCH_FN(cmdmatch) {
2N/A int argc, len, ws, i;
2N/A char **argv, *l;
2N/A ss_commands *commands = data;
2N/A int ret = 0;
2N/A
2N/A /* Dup the line as ss_parse will modify the string */
2N/A l = strdup(line);
2N/A if (l == NULL)
2N/A return (ret);
2N/A
2N/A /* Tab-completion may happen in the middle of a line */
2N/A if (word_end != strlen(l))
2N/A l[word_end] = '\0';
2N/A
2N/A if (ss_parse(commands->sci_idx, l, &argc, &argv, 1)) {
2N/A free (l);
2N/A return (ret);
2N/A }
2N/A
2N/A /* Don't bother if the arg count is not 1 or 0 */
2N/A if (argc < 2) {
2N/A len = argc ? strlen(argv[0]) : 0;
2N/A ws = word_end - len;
2N/A
2N/A for (i = 0; i < commands->count; i++) {
2N/A if (strncmp(commands->cmd[i], line + ws, len) == 0) {
2N/A ret = cpl_add_completion(cpl, line, ws,
2N/A word_end, commands->cmd[i] + len, "", " ");
2N/A if (ret)
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A free(argv);
2N/A free(l);
2N/A return (ret);
2N/A}
2N/A
2N/Aint ss_listen (sci_idx)
2N/A int sci_idx;
2N/A{
2N/A register char *cp;
2N/A register ss_data *info;
2N/A char buffer[BUFSIZ];
2N/A char *volatile end = buffer;
2N/A int code;
2N/A
2N/A /* Solaris Kerberos */
2N/A char *input;
2N/A GetLine *gl;
2N/A GlReturnStatus ret;
2N/A ss_commands commands;
2N/A
2N/A jmp_buf old_jmpb;
2N/A ss_data *old_info = current_info;
2N/A#ifdef POSIX_SIGNALS
2N/A struct sigaction isig, csig, nsig, osig;
2N/A sigset_t nmask, omask;
2N/A#else
2N/A register RETSIGTYPE (*sig_cont)();
2N/A RETSIGTYPE (*sig_int)(), (*old_sig_cont)();
2N/A int mask;
2N/A#endif
2N/A
2N/A current_info = info = ss_info(sci_idx);
2N/A info->abort = 0;
2N/A
2N/A /* Solaris Kerberos */
2N/A gl = new_GetLine(MAX_LINE_LEN, MAX_HIST_LEN);
2N/A if (gl == NULL) {
2N/A ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
2N/A "new_GetLine() failed.\n"));
2N/A current_info = old_info;
2N/A return (SS_ET_TECLA_ERR);
2N/A }
2N/A
2N/A commands.sci_idx = sci_idx;
2N/A commands.cmd = NULL;
2N/A
2N/A /* Find out how many commands there are */
2N/A get_commands(&commands);
2N/A
2N/A /* Alloc space for them */
2N/A commands.cmd = malloc(sizeof (char *) * commands.count);
2N/A if (commands.cmd == NULL) {
2N/A current_info = old_info;
2N/A gl = del_GetLine(gl);
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A /* Fill-in commands.cmd */
2N/A get_commands(&commands);
2N/A
2N/A if (gl_customize_completion(gl, &commands, cmdmatch) != 0 ) {
2N/A ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
2N/A "failed to register completion function.\n"));
2N/A free(commands.cmd);
2N/A current_info = old_info;
2N/A gl = del_GetLine(gl);
2N/A return (SS_ET_TECLA_ERR);
2N/A }
2N/A
2N/A#ifdef POSIX_SIGNALS
2N/A csig.sa_handler = (RETSIGTYPE (*)())0;
2N/A sigemptyset(&nmask);
2N/A sigaddset(&nmask, SIGINT);
2N/A sigprocmask(SIG_BLOCK, &nmask, &omask);
2N/A#else
2N/A sig_cont = (RETSIGTYPE (*)())0;
2N/A mask = sigblock(sigmask(SIGINT));
2N/A#endif
2N/A
2N/A memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
2N/A
2N/A#ifdef POSIX_SIGNALS
2N/A nsig.sa_handler = listen_int_handler;
2N/A sigemptyset(&nsig.sa_mask);
2N/A nsig.sa_flags = 0;
2N/A sigaction(SIGINT, &nsig, &isig);
2N/A#else
2N/A sig_int = signal(SIGINT, listen_int_handler);
2N/A#endif
2N/A
2N/A setjmp(listen_jmpb);
2N/A
2N/A#ifdef POSIX_SIGNALS
2N/A sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
2N/A#else
2N/A (void) sigsetmask(mask);
2N/A#endif
2N/A
2N/A /*
2N/A * Solaris Kerberos:
2N/A * Let libtecla deal with SIGINT when it's doing its own processing
2N/A * otherwise the input line won't be cleared on SIGINT.
2N/A */
2N/A if (gl_trap_signal(gl, SIGINT, GLS_DONT_FORWARD, GLS_ABORT, NULL)) {
2N/A ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
2N/A "Failed to trap SIGINT.\n"));
2N/A code = SS_ET_TECLA_ERR;
2N/A goto egress;
2N/A }
2N/A
2N/A while(!info->abort) {
2N/A print_prompt();
2N/A *end = '\0';
2N/A#ifdef POSIX_SIGNALS
2N/A nsig.sa_handler = listen_int_handler; /* fgets is not signal-safe */
2N/A osig = csig;
2N/A sigaction(SIGCONT, &nsig, &csig);
2N/A if ((RETSIGTYPE (*)())csig.sa_handler==(RETSIGTYPE (*)())listen_int_handler)
2N/A csig = osig;
2N/A#else
2N/A old_sig_cont = sig_cont;
2N/A sig_cont = signal(SIGCONT, print_prompt);
2N/A if (sig_cont == print_prompt)
2N/A sig_cont = old_sig_cont;
2N/A#endif
2N/A
2N/A /* Solaris Kerberos */
2N/A input = gl_get_line(gl, info->prompt, NULL, -1);
2N/A ret = gl_return_status(gl);
2N/A
2N/A switch (ret) {
2N/A case (GLR_SIGNAL):
2N/A gl_abandon_line(gl);
2N/A continue;
2N/A case (GLR_EOF):
2N/A info->abort = 1;
2N/A continue;
2N/A case (GLR_ERROR):
2N/A ss_error(sci_idx, 0, dgettext(TEXT_DOMAIN,
2N/A "Failed to read line: %s\n"), gl_error_message(gl, NULL, 0));
2N/A info->abort = 1;
2N/A code = SS_ET_TECLA_ERR;
2N/A goto egress;
2N/A }
2N/A cp = strchr(input, '\n');
2N/A if (cp) {
2N/A *cp = '\0';
2N/A if (cp == input)
2N/A continue;
2N/A }
2N/A#ifdef POSIX_SIGNALS
2N/A sigaction(SIGCONT, &csig, (struct sigaction *)0);
2N/A#else
2N/A (void) signal(SIGCONT, sig_cont);
2N/A#endif
2N/A for (end = input; *end; end++)
2N/A ;
2N/A
2N/A code = ss_execute_line (sci_idx, input);
2N/A if (code == SS_ET_COMMAND_NOT_FOUND) {
2N/A register char *c = input;
2N/A while (*c == ' ' || *c == '\t')
2N/A c++;
2N/A cp = strchr (c, ' ');
2N/A if (cp)
2N/A *cp = '\0';
2N/A cp = strchr (c, '\t');
2N/A if (cp)
2N/A *cp = '\0';
2N/A ss_error (sci_idx, 0, dgettext(TEXT_DOMAIN,
2N/A "Unknown request \"%s\". Type \"?\" for a request list."),
2N/A c);
2N/A }
2N/A }
2N/A code = 0;
2N/Aegress:
2N/A
2N/A /* Solaris Kerberos */
2N/A free(commands.cmd);
2N/A gl = del_GetLine(gl);
2N/A
2N/A#ifdef POSIX_SIGNALS
2N/A sigaction(SIGINT, &isig, (struct sigaction *)0);
2N/A#else
2N/A (void) signal(SIGINT, sig_int);
2N/A#endif
2N/A memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
2N/A current_info = old_info;
2N/A return code;
2N/A}
2N/A
2N/Avoid ss_abort_subsystem(sci_idx, code)
2N/A int sci_idx;
2N/A int code;
2N/A{
2N/A ss_info(sci_idx)->abort = 1;
2N/A ss_info(sci_idx)->exit_status = code;
2N/A
2N/A}
2N/A
2N/A/* Solaris Kerberos - errors are now returned. */
2N/Aint ss_quit(argc, argv, sci_idx, infop)
2N/A int argc;
2N/A char const * const *argv;
2N/A int sci_idx;
2N/A pointer infop;
2N/A{
2N/A ss_abort_subsystem(sci_idx, 0);
2N/A return 0;
2N/A}