Logo Search packages:      
Sourcecode: fbgetty version File versions  Download package

issue.c

/*
 * issue.c : read the issue file
 *
 * Part of fbgetty 
 * Copyright (C) 1999 2000 2001, Yann Droneaud <ydroneaud@meuh.eu.org>. 
 *
 * fbgetty is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * fbgetty is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
 *
 */

#include <fbgetty/global.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <string.h>

#include <ctype.h>
#include <errno.h>

#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <termios.h>

#if defined(USE_SECURE_MODE) && defined(SECURE_USERNAME)
#include <pwd.h>
#include <grp.h>
#endif

#include <fbgetty/errors.h>
#include <fbgetty/options.h>
#include <fbgetty/prompt.h>
#include <fbgetty/utmp.h>
#include <fbgetty/issue.h>
#include <fbgetty/sysinfos.h>

void print_issue(void);

void output_escape (FILE *in);
void output_special (FILE *in);

void output_long(FILE *fd);
void output_long_special(int tag, char *argv[]);   
void output_environment(FILE *fd);
void output_exec(FILE *fd);

static int isarg(int c);
static int isname(int c);
static int isissuetoken(int c);
static int isexecarg(int c);

static char *read_var_name(FILE *fd, int (*isseparator)(int));

static void issue_verbatim(int argc, char *argv[]);
static void issue_include(int argc, char *argv[]);
static void issue_include_verbatim(int argc, char *argv[]);
static void issue_ftime(int argc, char *argv[]);

static FILE *open_issue(const char *);

static pid_t exec_pid;

#define EXEC_DELIMITER '`'

#define LONGTAG_ARG_SHIFT  8  /* the lower 8bit arry the argument number */

/* the tag did not have any arguments */
#define LONGTAG_ARG_NONE   (0x00 << LONGTAG_ARG_SHIFT)

/* the tag can have 0 or more arguments */
#define LONGTAG_ARG_OPTION (0x01 << LONGTAG_ARG_SHIFT)

/* the tag can have 1 or more arguments */
#define LONGTAG_ARG_VAR    (0x02 << LONGTAG_ARG_SHIFT)

/* the tag can have a fixed number arguments (in the low byte) */
#define LONGTAG_ARG_FIXED  (0x04 << LONGTAG_ARG_SHIFT)

#define LONGTAG_ARG_MAX    ((0x01 << (LONGTAG_ARG_SHIFT)) - 1)  /* set maximum of arguments to 255 (0xff) */
#define LONGTAG_ARG_MASK   (~LONGTAG_ARG_MAX)  /* set the mask (0xffffff00) */

static struct longtag
{
  const char *name;
  int need_arg;
  int special;
  void (*output_long_special)(int argc, char *argv[]);

} 
longtags[] =
{
  /* standart (well known tags) */
  { "system"  ,     LONGTAG_ARG_NONE, 's', NULL },

  { "version" ,     LONGTAG_ARG_NONE, 'v', NULL },

  { "release" ,     LONGTAG_ARG_NONE, 'r', NULL },

  { "architecture", LONGTAG_ARG_NONE, 'm', NULL },
  { "arch",         LONGTAG_ARG_NONE, 'm', NULL },
  { "machine",      LONGTAG_ARG_NONE, 'm', NULL },

  { "tty",          LONGTAG_ARG_NONE, 'l', NULL },
  { "vt",           LONGTAG_ARG_NONE, 'l', NULL },
  { "line",         LONGTAG_ARG_NONE, 'l', NULL },

  { "speed",        LONGTAG_ARG_NONE, 'b', NULL },
  { "baud",         LONGTAG_ARG_NONE, 'b', NULL },

  { "framebuffer",  LONGTAG_ARG_NONE, 'f', NULL },
  { "fb",           LONGTAG_ARG_NONE, 'f', NULL },

  { "hostname",     LONGTAG_ARG_NONE, 'n', NULL },
  { "host",         LONGTAG_ARG_NONE, 'n', NULL },

  { "domain",       LONGTAG_ARG_NONE, 'o', NULL },
  { "domainname",   LONGTAG_ARG_NONE, 'o', NULL },

  { "fqdn",         LONGTAG_ARG_NONE, 'F', NULL },
  { "FQDN",         LONGTAG_ARG_NONE, 'F', NULL },
  
  { "user",         LONGTAG_ARG_NONE, 'u', NULL },

  { "users",        LONGTAG_ARG_NONE, 'U', NULL },

  { "date",         LONGTAG_ARG_NONE, 'd', NULL },
 
  { "time",         LONGTAG_ARG_NONE, 't', NULL },

  { "include",      LONGTAG_ARG_VAR, 0, issue_include },

  { "color",        LONGTAG_ARG_VAR, 0, NULL },

  { "ftime",        LONGTAG_ARG_VAR, 0, issue_ftime },
  
  { "verb",         LONGTAG_ARG_VAR, 0, issue_verbatim },
  { "verbatim",     LONGTAG_ARG_VAR, 0, issue_verbatim },

  { "cat",          LONGTAG_ARG_VAR, 0, issue_include_verbatim },
  { "dump",         LONGTAG_ARG_VAR, 0, issue_include_verbatim },
  { "include_verbatim",
                    LONGTAG_ARG_VAR, 0, issue_include_verbatim },

  { NULL,           0,  0, NULL}
};

/* used to initialise the array */
#define SPEED(value) { value, B ## value }
static struct baud_entry
{
  long speed;
  unsigned int code;
} bauds[] = {
  SPEED(0), /* hangup */
  SPEED(50),
  SPEED(75),
  SPEED(110),
  SPEED(134),
  SPEED(150),
  SPEED(200),
  SPEED(300),
  SPEED(600),
  SPEED(1200),
  SPEED(1800),
  SPEED(2400),
  SPEED(4800),
  SPEED(9600),
#ifdef B19200
  SPEED(19200),
#endif
#ifdef EXTA
  { 19200, EXTA },
#endif
#ifdef B38400
  SPEED(38400),
#endif
#ifdef EXTB
  { 38400, EXTB },
#endif
#ifdef B57600
  SPEED(57600),
#endif
#ifdef B115200
  SPEED(115200),
#endif
  { -1, 0 },
};

static
void print_baud(void)
{
  int i;
  unsigned int baud;
  struct termios term;

  if (tcgetattr(STDIN_FILENO, &term) != -1)
    {
      baud = term.c_cflag & CBAUD;
      for (i = 0; bauds[i].speed != -1; i++)
      if (bauds[i].code == baud)
        {
          printf("%lu", bauds[i].speed);
          return;
        }
    }

  printf("(undetermined)");
}

/* output verbatim the argument */
static void
issue_verbatim(int argc, char *argv[])
{
  int i;

  for(i = 0; i < argc && argv[i] != NULL; i ++)
    {
      fputs(argv[i], stdout);
    }
}

/* dump a file */
static void
issue_include_verbatim(int argc, char *argv[])
{
  char buffer[4096];
  FILE *fd;
  int i;
  size_t len;

  for(i = 0; i < argc && argv[i] != NULL ; i++)
    {
      fd = fopen(argv[i], "r");
      if (fd != NULL)
      {
        while(!feof(fd))
          {
            len = fread(buffer, sizeof(char), 4096, fd);
            if (len > 0) fwrite(buffer, sizeof(char), len, stdout);
          }
        fclose(fd);
      }
    }
}

/* parse another file */
static void
issue_include(int argc, char *argv[])
{
  FILE *fd;
  int i;

  for(i = 0; i < argc && argv[i] != NULL ; i++)
    {
      fd = open_issue(argv[i]);
      if (fd != NULL)
      fclose(fd);
    }
}

/* print a formatted struct tm, with format like date(1) */
static void
issue_ftime(int argc, char *argv[])
{
  int i;

  for(i = 0; i < argc && argv[i] != NULL; i ++)
    {
      printf_time(stdout, argv[i], &sysinfos);
    }

}     

/* handle this form of tag:
 *  @a_name
 *  @a_name=an_option
 *  @a_name=opt1,opt2,opt3
 */
void
output_long(FILE *fd)
{
  int c;
  char *long_tag;
  char *tag_argv[LONGTAG_ARG_MAX + 1]; /* 255 options + a NULL entry */ 

  int i;
  int tag_argc = 0;

  tag_argv[0] = NULL;

  long_tag = read_var_name(fd, isname);
  if (long_tag != NULL)
    {
      if (*long_tag != '\0')
      {
          c = getc(fd);
        if (c != '=')
          {
            /* no arguments */
            ungetc(c, fd);
          }
        else
          {
            /* read the arguments */
            do
            {
              tag_argv[tag_argc] = read_var_name(fd, isarg);
              if (tag_argv[tag_argc] == NULL)
                break;
              
              if (*(tag_argv[tag_argc]) == '\0')
                {
                  c = getc(fd);
                  if (c != ',')
                  {
                    /* the list is finished */
                    free(tag_argv[tag_argc]);
                    tag_argv[tag_argc] = NULL;
                    ungetc(c, fd);
                    break;
                  }
                }
              else
                {
                  tag_argc ++;
                  tag_argv[tag_argc] = NULL;
                }

            }
            while(tag_argc <= LONGTAG_ARG_MAX);
          }


        /* search the name */
        for(i = 0; longtags[i].name != NULL; i ++)
          {
            if (strcmp(longtags[i].name, long_tag) == 0)
            break;
          }

        if (longtags[i].name != NULL)
          {
            if ((longtags[i].need_arg & LONGTAG_ARG_MASK) == LONGTAG_ARG_NONE)
            {
              if (tag_argc == 0)
                print_special(longtags[i].special);
#ifdef FB_GETTY_DEBUG
              else
                {
                  error("too many arguments for: '%s'", longtags[i].name );
                }
#endif
              goto output_long_leave;
            }

            if ((longtags[i].need_arg & LONGTAG_ARG_MASK) == LONGTAG_ARG_FIXED)
            {
              if (tag_argc == (longtags[i].need_arg & ~LONGTAG_ARG_MASK))
                longtags[i].output_long_special(tag_argc, tag_argv);
#ifdef FB_GETTY_DEBUG
              else
                {
                  error("wrong number of argument for : '%s'", longtags[i].name );
                }
#endif
              goto output_long_leave;
            }

            if ((longtags[i].need_arg & LONGTAG_ARG_MASK) == LONGTAG_ARG_VAR)
            {
              if (tag_argc > 0)
                longtags[i].output_long_special(tag_argc, tag_argv);
#ifdef FB_GETTY_DEBUG
              else
                {
                  error("at least an argument need argument for : '%s'", longtags[i].name );
                }
#endif
              goto output_long_leave;
            }


            if ((longtags[i].need_arg & LONGTAG_ARG_MASK) == LONGTAG_ARG_OPTION)
            {
              longtags[i].output_long_special(tag_argc, tag_argv);
              goto output_long_leave;
            }
            
#ifdef FB_GETTY_DEBUG
            error("something wrong happened during parsing argument for : '%s'", longtags[i].name);
#endif
          }

#ifdef FB_GETTY_DEBUG
        else
          {
            error("unknown tag: '%s'", long_tag);
          }
#endif
      }

    output_long_leave:

      /* free the argument vector */
      for(; tag_argc >= 0; tag_argc --)
      {
        if (tag_argv[tag_argc] != NULL)
          free(tag_argv[tag_argc]);
      }

      free(long_tag);
      long_tag = NULL;
    }
}

static int
isexecarg(int c)
{
  return(!isspace(c) && c !='`');
}

/* the whole token list */
static int
isissuetoken(int c)
{
  switch(c)
    {
    case '@':
    case '%':
    case '`':
    case '$':
    case '\\':
      return(1);  /* notice that '=' and ',' are not start of something */
    }
  return(0);
}

static int
isarg(int c)
{
  /* all except issue token */
  return(!isspace(c) && !isissuetoken(c) && c != ',' );
}

/* use for environment $name and long tag @name , but not for arg */
static int
isname(int c)
{
  /*   c != ',' && c != '@' && c != '%' && c != '`' && c != '$' && c != '=' && c != '\\' */
  return(!isspace(c) && (!ispunct(c) || c == '_'));
}

/*
 * put all char in the var name until isseparator() return true
 *
 * variable could be in form: VAR "VAR" {VAR}
 */
static 
struct
{
  char begin;
  char end;
} var_delimiters[] = 
{
  { '"', '"' },
  { '{', '}' },
  {   0, 0 }
};

static char *
read_var_name(FILE *fd, int (*isseparator)(int))
{

#define VAR_NAME_SIZE 32

  char *var_name;
  char *new;
  int c;

  int size = VAR_NAME_SIZE; /* size of the buffer */
  int skip = 0;             /* store char read or not */

  int i = 0;                /* index */

  int in_string = 0;

  var_name = (char *) malloc(size + 1);
  if (var_name != NULL)
    {
      *var_name = '\0';
      
      /* is a string */
      c = getc(fd);
      for(in_string = 0;
        var_delimiters[in_string].begin != '\0' && var_delimiters[in_string].begin != c ;
        in_string ++);

      in_string = var_delimiters[in_string].end;

      if (in_string == 0)
      ungetc(c, fd);

      do
      {
        c = getc (fd);

        if (c != EOF)
          {
            /* allocate more room for name */
            if (i >= size)
            {
              size += VAR_NAME_SIZE;
              new = (char *) realloc(var_name, size + 1);
              if (new != NULL)
                var_name = new;
              else
                skip = 1;  /* continue to read the name, but did not save them */
            }

            if (in_string != 0)
            {
              /* escape */
              if (c == '\\')
                {
                  /* read next */
                  c = getc(fd);
                  c = convert_escape(c);
                } 
              else
                {
                  if (c == in_string) /* end of string */
                  c = EOF;
                }
            }
            else
            {
              /* escape */
              if (c == '\\')
                {
                  /* read next */
                  c = getc(fd);
                  c = convert_escape(c);
                } 
              else
                {
                  if (!isseparator(c))
                  {
                    /* this is the end of the name, the readed char is not part of it, so put it back to issue */
                    ungetc(c,fd);
                    c = EOF;
                  }
                }

            }
            
            if (c != EOF && skip == 0)
            {
              var_name[i++] = (char) c;
              var_name[i] = '\0';
            }
          }
      }
      while(c != EOF);
    }   
 
  return(var_name);

#undef  VAR_NAME_SIZE
}


/*
 * print $VAR
 *
 */
void
output_environment(FILE *fd)
{
  char *var_name;
  char *var_value;

  var_name = read_var_name(fd, isname);
  
  if (var_name != NULL)
    {
      if (*var_name != '\0' && ((var_value = getenv(var_name)) != NULL))
      printf("%s",var_value);
      
      free(var_name);
    }
#ifdef FB_GETTY_DEBUG
  else
  {
    error("no more memory or syntax error while parsing issue");
  }
#endif              

}

#ifdef USE_SECURE_MODE

static RETSIGTYPE 
exec_sigalarm(int sig)
{
#ifdef FB_GETTY_DEBUG
  if (sig != SIGALRM)
    error("unknown signal received: %d",sig);
#endif

  kill(exec_pid, SIGTERM);
  error("SIGTERM sent to %d",exec_pid);

  sleep(1); /* give some time to the program */
  kill(exec_pid, SIGKILL);
  error("SIGKILL sent to %d",exec_pid);
}
#endif

/*
 * execute a program
 */
void 
output_exec(FILE *fd)
{
  pid_t pid,pgid;

  struct stat st;
#define NR_ARGS 32
  char *exec_argv[NR_ARGS];
  int exec_argc;
  int c;
  struct sigaction sa;
  struct sigaction oldsachld;

  struct termios term_attr;

#ifdef USE_SECURE_MODE
  struct sigaction oldsaalarm;
  uid_t exec_uid;
  gid_t exec_gid;

#ifdef SECURE_USERNAME
  struct passwd *pw;
#ifdef SECURE_GROUPNAME
  struct group *gr;
#endif /* SECURE_GROUPNAME */
#endif /* SECURE_USERNAME */
#endif

  exec_argc = 0;
  exec_argv[exec_argc] = NULL;

  do
    {
      exec_argv[exec_argc] = read_var_name(fd, isexecarg);
      
      if (exec_argv[exec_argc] == NULL)
      goto output_exec_loop_out;

      if (*(exec_argv[exec_argc]) == '\0') /* is a separator or whitespace */
      {
        free(exec_argv[exec_argc]);
        exec_argv[exec_argc] = NULL;

        /* skip spaces between arg */
        do
          c = getc(fd);
        while(isspace(c));

        if (c != EOF)
          {
            if (c == EXEC_DELIMITER)
            goto output_exec_loop_out;
            else
            ungetc(c, fd);
          }
        else
          {
            error("syntax error while parsing program argument, missing \"%c\"", EXEC_DELIMITER);
            goto output_exec_leave;
          }

      }
      else
      {
        exec_argc ++;
        exec_argv[exec_argc] = NULL;
      }
    }
  while(exec_argc < NR_ARGS);

 output_exec_loop_out:

  /* check if there is something to do ... */
  if (exec_argc <= 0 || *(exec_argv[0]) == '\0')
    goto output_exec_leave;

#ifdef USE_SECURE_MODE
  /* get the user and group used to run the program */

# if defined(SECURE_USER) && defined(SECURE_GROUP)
  /* fixed uid/gid */
  exec_gid = SECURE_GROUP;
  exec_uid = SECURE_USER;
# else /* !(SECURE_USER && SECURE_GROUP) */
#  ifdef SECURE_USERNAME
  /* fixed username, get info from user name */
  pw = getpwnam(SECURE_USERNAME);
  if (pw == NULL)
    {
      error("username '%s' invalid, secure exec stopped", SECURE_USERNAME);
      goto output_exec_leave;
    }
#ifdef FB_GETTY_DEBUG
  error("name=%s", pw->pw_name);
  error("uid=%d", pw->pw_uid);
  error("gid=%d", pw->pw_gid);
#endif
  exec_gid = pw->pw_gid;
  exec_uid = pw->pw_uid;
  
#   ifdef SECURE_GROUPNAME
  /* optionnaly use another group name */
  gr = getgrnam(SECURE_GROUPNAME);
  if (gr == NULL)
    {
      error("groupname '%s' invalid, secure exec stopped", SECURE_GROUPNAME);
      goto output_exec_leave;
    }
  exec_gid = gr->gr_gid;
  
#   endif /* SECURE_GROUPNAME */ 
#  else /* ! SECURE_USERNAME */
#   error "Secure exec is enabled but no user/group provided"
#  endif /* ! SECURE_USERNAME */
# endif  /* ! (SECURE_USER && SECURE_GROUP) */
#endif /* USE_SECURE_MODE */

  /* save fbgetty env */
  pid = getpid();
  pgid = getpgid(pid);

  /* save sane terminal settings */
  tcgetattr(fgoptions->tty_fd, &term_attr);

#ifdef FB_GETTY_DEBUG
  error("pid = %d", pid);
  error("pgid = %d", pgid);
#endif
  
  /* set handler for sigchld */
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = SIG_IGN;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = SA_NOMASK | SA_RESTART;
  sigaction(SIGCHLD, &sa, &oldsachld);

  /* ignoring job control signals */
  signal (SIGTSTP, SIG_IGN);
  signal (SIGTTIN, SIG_IGN);
  signal (SIGTTOU, SIG_IGN);
  
  exec_pid = fork();
  switch(exec_pid)
    {
    case -1: /* error */
      error("fork() failed for '%s': %s", exec_argv[0], strerror(errno));
      break;
      
    case 0: /* child code */
      fgoptions->master = FALSE; /* not controlling tty */

      /* update value */
      pid = getpid();
      pgid = getpgid(pid);

      /* loop until the process group is in foreground on the controlling terminal  */
      while (tcgetpgrp (fgoptions->tty_fd) != (pgid = getpgid (pid)))
      {
        kill (- pgid, SIGTTIN);
      }
      
#ifdef FB_GETTY_DEBUG
      error("pid = %d", pid);
      error("pgid = %d", pgid);
#endif

      /* check if father had already create our own process group */
      if (pgid != pid)
      {
        /* create the new process group */
#ifdef DEBUG_JOB_CONTROL
        if (setpgid(pid, pid) == -1)
          error("setpgid(%d, %d) failed: %s", pid, pid, strerror(errno));
#else
        setpgid(pid, pid);
#endif
      }

      /* update new pgid */
      pgid = getpgid(pid);

      /* check if child is already in forground */
      if (tcgetpgrp(fgoptions->tty_fd) != pgid)
      {
        /* put father in background, put this process to foreground */
#ifdef DEBUG_JOB_CONTROL
        if (tcsetpgrp(fgoptions->tty_fd, pgid) == -1)
          error("tcsetpgrp(%d) failed: %s", pgid, strerror(errno));
#else
        tcsetpgrp(fgoptions->tty_fd, pgid);
#endif
      }
   
#ifdef USE_SECURE_MODE      
      /* allow user to write to the tty */
      chmod(fgoptions->tty_device, 0666);

      /* set supplementary groups */
# if defined(HAVE_INITGROUPS) && defined(SECURE_USERNAME) && !defined(SECURE_GROUPNAME)
      /* don't use this if a specific group was specified */
      initgroups(SECURE_USERNAME, exec_gid);
# elif defined(HAVE_SETGROUPS)
      setgroups(1, &exec_gid);
# endif /* HAVE_SETGROUPS */
      /* set gid before uid, because after changing uid we are not allowed to change gid ! */
      setgid(exec_gid);
      setuid(exec_uid);
#endif /* USE_SECURE_MODE */
      
      /* clean the memory ... */
      fgcleanup();
      free(fgoptions_free(fgoptions));
      
      /* find program in the path, so user can put a path on the fbgetty command line
       fbgetty PATH=/bin:/sbin:/usr/bin:/usr/sbin */
      execvp(exec_argv[0],exec_argv);
      fprintf(stderr,"'%s': %s", exec_argv[0], strerror(errno));
      
      _exit(EXIT_FAILURE); /* not fgexit(), because it call exit(), 
                        and exit() will flush some buffers we don't want */
      break;
      
    default: /* in father, wait for the child */

      /* new process group */
      if (getpgid(exec_pid) != exec_pid)
      {
#ifdef DEBUG_JOB_CONTROL
        if (setpgid(exec_pid, exec_pid) == -1)
          error("setpgid(%d, %d) failed: %s", exec_pid, exec_pid, strerror(errno));
#else
        setpgid(exec_pid, exec_pid);
#endif
      }

      /* put fbgetty in background, put the new process to foreground */
      if (tcgetpgrp(fgoptions->tty_fd) != exec_pid)
      {
#ifdef DEBUG_JOB_CONTROL
        if (tcsetpgrp (fgoptions->tty_fd, exec_pid) == -1)
          error("tcsetpgrp(%d) failed: %s", exec_pid, strerror(errno));
#else
        tcsetpgrp (fgoptions->tty_fd, exec_pid);
#endif
      }

#ifdef USE_SECURE_MODE
      /* enable the timeout handler */
      memset(&sa, 0, sizeof(struct sigaction));
      sa.sa_handler = exec_sigalarm;
      sigemptyset(&sa.sa_mask);
      sa.sa_flags = SA_NOMASK | SA_RESTART;
      sigaction(SIGALRM, &sa, &oldsaalarm);
      
      alarm(5); /* timeout is 5 sec, if a program take more time, 
               it will be killed */
#endif
      
#ifdef HAVE_WAITPID
      waitpid(-1, NULL, 0);
#else
      wait(NULL); /* wait any child to finish */
#endif

      /* be sure our child didn't change our process group */
      if (getpgid(pid) != pgid)
      {
#ifdef DEBUG_JOB_CONTROL
        if (setpgid(pid, pgid) == -1)
          error("setpgid(%d, %d) failed: %s", pid, pgid, strerror(errno));
#else
        setpgid(pid, pgid);
#endif
      }

      /* fbgetty back to foreground */
      if (tcgetpgrp (fgoptions->tty_fd) != pgid)
      {
#ifdef DEBUG_JOB_CONTROL
        /* put fbgetty back in foreground */
        if (tcsetpgrp (fgoptions->tty_fd, pgid) == -1)
          error("tcsetpgrp(%d) failed: %s", pgid, strerror(errno));
#else
        tcsetpgrp (fgoptions->tty_fd, pgid);
#endif
      }

      /* restore sane terminal settings */
      tcsetattr (fgoptions->tty_fd, TCSADRAIN, &term_attr);

      /* regain rights on tty */
      if (stat (fgoptions->tty_device, &st) == -1) 
      fatal_error("stat(%s) failed: %s",fgoptions->tty_device, strerror(errno));
      
      chown(fgoptions->tty_device, 0, st.st_gid);
      chmod(fgoptions->tty_device, 0600); /* or 0620 to allow message to be sent to the tty */
      
#ifdef USE_SECURE_MODE
      alarm(0); /* disable alarm */
      sigaction(SIGALRM, &oldsaalarm, NULL);
#endif
      break;
    }

  /* no more ignoring SIGCHLD */
  sigaction(SIGCHLD, &oldsachld, NULL);

 output_exec_leave:

  /* free the argument vector */
  while(exec_argc >= 0)
    {
      if (exec_argv[exec_argc] != NULL)
      free(exec_argv[exec_argc]);
      exec_argc --;
    }
}

/*
 * The issue parser
 *  it reads the file, search for special token and call the
 *  related function.
 *  If it's not a special token, just echo it
 *
 */
void
parse_issue(FILE *fd)
{
  int c;

#ifdef FB_GETTY_DEBUG
  error("- parsing issue");
#endif

  while ((c = getc (fd)) != EOF) 
    {
      /* be sure we can't ouput on vt */
      if (refresh_screen_check() == FALSE)
      return;

      switch(c)
      {
      case '\\':
        output_escape(fd);
        break;

      case '%':
        output_special(fd);
        break;

      case '@':
        output_long(fd);
        break;

      case '$': /* output an environment variable */
        output_environment(fd);
        break;

#ifdef USE_EXEC_SUPPORT
      case EXEC_DELIMITER: /* run a program `name [args...]` */
        output_exec(fd);
        break;
#endif /* USE_EXEC_SUPPORT */

      default:
        putchar (c);
        break;
      }
    }
}

FILE *
open_issue(const char *filename)
{
  FILE *fd;

  fd = fopen (filename, "r");
  if (fd != NULL)
    {
      parse_issue(fd);
    }

  return(fd);
}


/* the wrapper function.
 * This function is the only one used by other module (eg: prompt.c)
 *
 */
void
print_issue(void)
{
  FILE *fd;

  if (fgoptions->issue_filename != NULL)
    {
      fd = open_issue(fgoptions->issue_filename);
      if (fd == NULL) 
      {
        /* can't open issue file: disable issue */
        error("Can't open issue file (%s): %m",fgoptions->issue_filename);
        free(fgoptions->issue_filename);
        fgoptions->issue_filename = NULL;
      }
      else
      {
        fclose (fd);
      }
    }

  if (refresh_screen_check() != FALSE)
    fflush (stdout);
}

/*
 * convert %token to the corresponding text
 */
void
print_special(int c)
{

  switch (c) 
    {
    case 's': /* print system name (on GNU/Linux: print linux) */
      printf ("%s", sysinfos.uts.sysname);
      break;

    case 'r': /* print system release (on GNU/Linux: kernel version) */
      printf ("%s", sysinfos.uts.release);
      break;

    case 'v': /* print system version (on GNU/Linux: kernel build information) */
      printf ("%s", sysinfos.uts.version);
      break;

    case 'm': /* print system architecture */
      printf ("%s", sysinfos.uts.machine);
      break;

    case 'n': /* print hostname */
#if 0
      printf ("%s", sysinfos.uts.nodename);
#else
      printf ("%s", sysinfos.hostname);
#endif
      break;

    case 'o': /* print domain name (YP/NIS) */
#ifdef __USE_GNU
      printf ("%s", sysinfos.uts.domainname);
#else
      printf ("%s", sysinfos.uts.__domainname);
#endif
      break;

    case 'F': /* print fully qualified domain name */
      printf ("%s", sysinfos.fqdn);
      break;

    case 'd': /* print the date */
      printf_time(stdout, "%a %b %d %Y", &sysinfos);
      break;

    case 't': /* print the time */
      printf_time(stdout, "%X", &sysinfos);
      break;
      
    case 'l': /* print the tty line (device) */
      printf ("%s", strchr(fgoptions->tty_device + 1, '/') + 1);
      break;

    case 'b': /* print baud rate */
      print_baud();
      break;
      
#ifdef USE_FRAME_BUFFER
    case 'f': /* print framebuffer device */
      printf ("%s", (fgoptions->fb_device != NULL) ? (strchr(fgoptions->fb_device + 1, '/') + 1) : "none");
      break;
#endif
      
    case 'u': /* print number of users currenctly connected */
      printf ("%d", sysinfos.users);
      break;

    case 'U': /* print number of users currenctly connected + prefix */
      printf ((sysinfos.users > 1) ? "%d users" : "%d user", sysinfos.users);
      break;

    case EOF:
      break;
      
    default: /* simply echo the character */
      putchar (c);
      break;
    }

}


/*
 * handle short tag
 */
void
output_special (FILE *in)
{
  int c;

  c = getc(in);

  switch(c)
    {
    case '%': /* handle %% */
      putchar('%');
      break;
    
    case EOF:  /* erreur de syntaxe */
      break;

    default:
      print_special(c);
      break;
    }

}

int 
convert_escape(int c)
{
  switch (c)
    {
    case 'a':  /* alert (bell) */
      c = '\a'; /* WARNING: the meaning of \a is changed is -traditional is used */ 
      break;

    case 'v': /* vertical tab */
      c = '\v'; 
      break;

    case 'b': /* backspace */
      c = '\b'; 
      break;

    case 'e': /* escape -- non-ANSI */
    case 'E':         
      c = '\033'; 
      break;

    case 'f': /* formfeed */
      c = '\f'; 
      break;

    case 'n': /* new line */
      c = '\n'; 
      break;

    case 'r': /* carriage return */
      c = '\r'; 
      break;

    case 't': /* tabulation */
      c = '\t'; 
      break;

    default: /* by default return c */
      break;
    }

  return c;
}


/*
 * print escaped character
 */
void
print_escape (int c)
{
  if (c == '\n')  /* use to continue a line like this \
                 ...  */ 

    return;

  putchar(convert_escape(c));

}

int
convert_hex_char(int c)
{
  if (c >= 'a' && c <= 'f')
    return c - 'a' + 10; 

  if (c >= 'A' && c <= 'F')
    return c - 'A' + 10; 

  if (c >= '0' && c <= '9')
    return c - '0';

  return -1;
}

#ifndef HAVE_ISODIGIT
int
isodigit(int c)
{
  return (c >= '0' && c <= '7');
}
#endif

int
convert_oct_char(int c)
{
  if (c >= '0' && c <= '7')
    return c - '0';

  return -1;
}

/*
 * print escaped character
 */
void
output_escape (FILE *in)
{
  int c;
  int number = 0;

  c = getc(in);

  switch(c)
    {
    case 'x': /* handle hexa */
      do
      {
        c = getc(in);

        if (!isxdigit(c))
          {
            putchar(number);
            
            if (c != EOF)
            ungetc(c, in);
            return;
          }

        number *= 16;
        number += convert_hex_char(c);
      }
      while(1);
      break;

    case '0': /* handle octal */ 
    case 'o':
      do
      {
        c = getc(in);

        if (!isodigit(c))
          {
            putchar(number);

            if (c != EOF)
            ungetc(c, in);
            return;
          }

        number *= 8;
        number += convert_oct_char(c);
      }
      while(1);
      break;

    case EOF: /* syntaxe error */
      break;

    default:
      print_escape(c);
      break;
    }
}

Generated by  Doxygen 1.6.0   Back to index