/[gxemul]/trunk/src/console.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/console.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 21 by dpavlin, Mon Oct 8 16:19:23 2007 UTC revision 22 by dpavlin, Mon Oct 8 16:19:37 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: console.c,v 1.10 2005/11/23 02:17:00 debug Exp $   *  $Id: console.c,v 1.15 2006/02/18 13:42:38 debug Exp $
29   *   *
30   *  Generic console support functions.   *  Generic console support functions.
31   *   *
32   *  This is used by individual device drivers, for example serial controllers,   *  This module is used by individual device drivers, for example serial
33   *  to attach stdin/stdout of the host system to a specific device.   *  controllers, keyboards, or other devices which need to attach to the
34     *  emulator's real stdin/stdout.
35   *   *
36   *  NOTE: This stuff is non-reentrant.   *  The idea is that several input and output streams (console handles) are
37     *  allowed. As long as the number of input streams is <= 1, then everything
38     *  can be done in the emulator's default terminal window.
39     *
40     *  If the number of inputs is more than 1, it is necessary to open up slave
41     *  xterm windows for each input. (Otherwise the behaviour is undefined; i.e.
42     *  which of two emulated serial controllers would get keyboard input?)
43     *
44     *  (If the -x command line option is NOT used, then slaves are not opened up.
45     *  Instead, a warning message is printed, and input is not allowed.)
46     *
47     *  Note that console handles that _allow_ input but are not yet used for
48     *  output are not counted. This allows a machine to have, say, 2 serial ports
49     *  which can be used for both input and output, and it will still be possible
50     *  to run in the default terminal window as long as only one of those serial
51     *  ports is actually used.
52     *
53     *  xterms are opened up "on demand", when output is sent to them.
54     *
55     *  The MAIN console handle (fixed as handle nr 0) is the one used by the
56     *  default terminal window. A machine which registers a serial controller,
57     *  which should be used as the main way of communicating with guest operating
58     *  systems running on that machine, should set machine->main_console_handle
59     *  to the handle of the correct port on that controller.
60     *
61     *
62     *  NOTE: The code in this module is mostly non-reentrant.
63   */   */
64    
65  #include <errno.h>  #include <errno.h>
# Line 52  Line 79 
79    
80    
81  extern char *progname;  extern char *progname;
82    extern int verbose;
83    
84    
85  static struct termios console_oldtermios;  static struct termios console_oldtermios;
# Line 82  static int allow_slaves = 0; Line 110  static int allow_slaves = 0;
110    
111  struct console_handle {  struct console_handle {
112          int             in_use;          int             in_use;
113            int             in_use_for_input;
114          int             using_xterm;          int             using_xterm;
115          int             inputonly;          int             inputonly;
116            int             outputonly;
117            int             warning_printed;
118    
119            char            *machine_name;
120          char            *name;          char            *name;
121    
122          int             w_descriptor;          int             w_descriptor;
# Line 143  void console_sigcont(int x) Line 175  void console_sigcont(int x)
175  /*  /*
176   *  start_xterm():   *  start_xterm():
177   *   *
178   *  When using X11, this routine tries to start up an xterm, with another   *  When using X11 (well, when allow_slaves is set), this routine tries to
179   *  copy of gxemul inside. The other gxemul copy is given arguments   *  start up an xterm, with another copy of gxemul inside. The other gxemul
180   *  that will cause it to run console_slave().   *  copy is given arguments that will cause it to run console_slave().
181     *
182     *  TODO: This is ugly and hardcoded. Clean it up.
183   */   */
184  static void start_xterm(int handle)  static void start_xterm(int handle)
185  {  {
186          int filedes[2];          int filedes[2];
187          int filedesB[2];          int filedesB[2];
188          int res;          int res;
189            size_t mlen;
190          char **a;          char **a;
191          pid_t p;          pid_t p;
192    
# Line 173  static void start_xterm(int handle) Line 208  static void start_xterm(int handle)
208          /*  NOTE/warning: Hardcoded max nr of args!  */          /*  NOTE/warning: Hardcoded max nr of args!  */
209          a = malloc(sizeof(char *) * 20);          a = malloc(sizeof(char *) * 20);
210          if (a == NULL) {          if (a == NULL) {
211                  fprintf(stderr, "console_start_slave(): out of memory\n");                  fprintf(stderr, "start_xterm(): out of memory\n");
212                  exit(1);                  exit(1);
213          }          }
214    
# Line 183  static void start_xterm(int handle) Line 218  static void start_xterm(int handle)
218          a[1] = "-geometry";          a[1] = "-geometry";
219          a[2] = "80x25";          a[2] = "80x25";
220          a[3] = "-title";          a[3] = "-title";
221          a[4] = console_handles[handle].name;          mlen = strlen(console_handles[handle].name) +
222                strlen(console_handles[handle].machine_name) + 30;
223            a[4] = malloc(mlen);
224            snprintf(a[4], mlen, "GXemul: %s %s",
225                console_handles[handle].machine_name,
226                console_handles[handle].name);
227          a[5] = "-e";          a[5] = "-e";
228          a[6] = progname;          a[6] = progname;
229          a[7] = malloc(80);          a[7] = malloc(80);
# Line 192  static void start_xterm(int handle) Line 232  static void start_xterm(int handle)
232    
233          p = fork();          p = fork();
234          if (p == -1) {          if (p == -1) {
235                  printf("[ console_start_slave(): ERROR while trying to "                  printf("[ start_xterm(): ERROR while trying to "
236                      "fork(): %i ]\n", errno);                      "fork(): %i ]\n", errno);
237                  exit(1);                  exit(1);
238          } else if (p == 0) {          } else if (p == 0) {
# Line 201  static void start_xterm(int handle) Line 241  static void start_xterm(int handle)
241    
242                  p = setsid();                  p = setsid();
243                  if (p < 0)                  if (p < 0)
244                          printf("[ console_start_slave(): ERROR while trying "                          printf("[ start_xterm(): ERROR while trying "
245                              "to do a setsid(): %i ]\n", errno);                              "to do a setsid(): %i ]\n", errno);
246    
247                  res = execvp(a[0], a);                  res = execvp(a[0], a);
248                  printf("[ console_start_slave(): ERROR while trying to "                  printf("[ start_xterm(): ERROR while trying to "
249                      "execvp(\"");                      "execvp(\"");
250                  while (a[0] != NULL) {                  while (a[0] != NULL) {
251                          printf("%s", a[0]);                          printf("%s", a[0]);
# Line 214  static void start_xterm(int handle) Line 254  static void start_xterm(int handle)
254                          a++;                          a++;
255                  }                  }
256                  printf("\"): %i ]\n", errno);                  printf("\"): %i ]\n", errno);
257                    if (errno == ENOENT)
258                            printf("[ Most probably you don't have xterm"
259                                " in your PATH. Try again. ]\n");
260                  exit(1);                  exit(1);
261          }          }
262    
# Line 278  void console_makeavail(int handle, char Line 321  void console_makeavail(int handle, char
321   */   */
322  static int console_stdin_avail(int handle)  static int console_stdin_avail(int handle)
323  {  {
324            if (!console_handles[handle].in_use_for_input)
325                    return 0;
326    
327          if (!allow_slaves)          if (!allow_slaves)
328                  return d_avail(STDIN_FILENO);                  return d_avail(STDIN_FILENO);
329    
# Line 359  void console_putchar(int handle, int ch) Line 405  void console_putchar(int handle, int ch)
405  {  {
406          char buf[1];          char buf[1];
407    
408            if (!console_handles[handle].in_use_for_input &&
409                !console_handles[handle].outputonly)
410                    console_change_inputability(handle, 1);
411    
412          if (!allow_slaves) {          if (!allow_slaves) {
413                  /*  stdout:  */                  /*  stdout:  */
414                  putchar(ch);                  putchar(ch);
# Line 608  static struct console_handle *console_ne Line 658  static struct console_handle *console_ne
658          memset(chp, 0, sizeof(struct console_handle));          memset(chp, 0, sizeof(struct console_handle));
659    
660          chp->in_use = 1;          chp->in_use = 1;
661            chp->machine_name = "";
662          chp->name = strdup(name);          chp->name = strdup(name);
663          if (chp->name == NULL) {          if (chp->name == NULL) {
664                  printf("console_new_handle(): out of memory\n");                  printf("console_new_handle(): out of memory\n");
# Line 633  static struct console_handle *console_ne Line 684  static struct console_handle *console_ne
684   *   *
685   *  consolename should be something like "serial 0".   *  consolename should be something like "serial 0".
686   *   *
687     *  If use_for_input is 1, input is allowed right from the start. (This
688     *  can be upgraded later from 0 to 1 using the console_change_inputability()
689     *  function.)
690     *
691     *  If use_for_input is CONSOLE_OUTPUT_ONLY, then this is an output-only stream.
692     *
693   *  On success, an integer >= 0 is returned. This can then be used as a   *  On success, an integer >= 0 is returned. This can then be used as a
694   *  'handle' when writing to or reading from an emulated console.   *  'handle' when writing to or reading from an emulated console.
695   *   *
696   *  On failure, -1 is returned.   *  On failure, -1 is returned.
697   */   */
698  int console_start_slave(struct machine *machine, char *consolename)  int console_start_slave(struct machine *machine, char *consolename,
699            int use_for_input)
700  {  {
         int handle;  
         size_t mlen;  
701          struct console_handle *chp;          struct console_handle *chp;
702            int handle;
703    
704          if (machine == NULL || consolename == NULL) {          if (machine == NULL || consolename == NULL) {
705                  printf("console_start_slave(): NULL ptr\n");                  printf("console_start_slave(): NULL ptr\n");
# Line 650  int console_start_slave(struct machine * Line 707  int console_start_slave(struct machine *
707          }          }
708    
709          chp = console_new_handle(consolename, &handle);          chp = console_new_handle(consolename, &handle);
710            chp->in_use_for_input = use_for_input;
711          mlen = strlen(machine->name) + strlen(consolename) + 40;          if (use_for_input == CONSOLE_OUTPUT_ONLY) {
712          chp->name = malloc(mlen);                  chp->outputonly = 1;
713          if (chp->name == NULL) {                  chp->in_use_for_input = 0;
                 printf("out of memory\n");  
                 exit(1);  
714          }          }
715          snprintf(chp->name, mlen, "GXemul: '%s' %s",          chp->machine_name = strdup(machine->machine_name);
716              machine->name, consolename);          chp->name = strdup(consolename);
717    
718  #if 0          if (allow_slaves)
719          if (!machine->use_x11) {                  chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
                 return handle;  
         }  
 #endif  
         chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;  
720    
721          return handle;          return handle;
722  }  }
# Line 683  int console_start_slave(struct machine * Line 734  int console_start_slave(struct machine *
734   *   *
735   *  On failure, -1 is returned.   *  On failure, -1 is returned.
736   */   */
737  int console_start_slave_inputonly(struct machine *machine, char *consolename)  int console_start_slave_inputonly(struct machine *machine, char *consolename,
738            int use_for_input)
739  {  {
740          struct console_handle *chp;          struct console_handle *chp;
741          int handle;          int handle;
         size_t mlen;  
742    
743          if (machine == NULL || consolename == NULL) {          if (machine == NULL || consolename == NULL) {
744                  printf("console_start_slave(): NULL ptr\n");                  printf("console_start_slave(): NULL ptr\n");
# Line 696  int console_start_slave_inputonly(struct Line 747  int console_start_slave_inputonly(struct
747    
748          chp = console_new_handle(consolename, &handle);          chp = console_new_handle(consolename, &handle);
749          chp->inputonly = 1;          chp->inputonly = 1;
750            chp->in_use_for_input = use_for_input;
751            chp->machine_name = strdup(machine->name);
752            chp->name = strdup(consolename);
753    
754          mlen = strlen(machine->name) + strlen(consolename) + 40;          return handle;
755          chp->name = malloc(mlen);  }
756          if (chp->name == NULL) {  
757                  printf("out of memory\n");  
758    /*
759     *  console_change_inputability():
760     *
761     *  Sets whether or not a console handle can be used for input. Return value
762     *  is 1 if the change took place, 0 otherwise.
763     */
764    int console_change_inputability(int handle, int inputability)
765    {
766            int old;
767    
768            if (handle < 0 || handle >= n_console_handles) {
769                    fatal("console_change_inputability(): bad handle %i\n",
770                        handle);
771                  exit(1);                  exit(1);
772          }          }
         snprintf(chp->name, mlen, "GXemul: '%s' %s",  
             machine->name, consolename);  
773    
774          return handle;          old = console_handles[handle].in_use_for_input;
775            console_handles[handle].in_use_for_input = inputability;
776    
777            if (inputability != 0) {
778                    if (console_warn_if_slaves_are_needed(0)) {
779                            console_handles[handle].in_use_for_input = old;
780                            if (!console_handles[handle].warning_printed) {
781                                    fatal("%%\n%%  WARNING! Input to console ha"
782                                        "ndle \"%s\" wasn't enabled,\n%%  because "
783                                        "it", console_handles[handle].name);
784                                    fatal(" would interfere with other inputs,\n"
785                                        "%%  and you did not use the -x command "
786                                        "line option!\n%%\n");
787                            }
788                            console_handles[handle].warning_printed = 1;
789                            return 0;
790                    }
791            }
792    
793            return 1;
794  }  }
795    
796    
797  /*  /*
798   *  console_init_main():   *  console_init_main():
799   *   *
800   *  Put host's console into single-character (non-canonical) mode.   *  Puts the host's console into single-character (non-canonical) mode.
801   */   */
802  void console_init_main(struct emul *emul)  void console_init_main(struct emul *emul)
803  {  {
# Line 763  void console_init_main(struct emul *emul Line 847  void console_init_main(struct emul *emul
847    
848    
849  /*  /*
850     *  console_debug_dump():
851     *
852     *  Dump debug info, if verbose >= 2.
853     */
854    void console_debug_dump(struct machine *machine)
855    {
856            int i, iadd = DEBUG_INDENTATION, listed_main = 0;
857    
858            if (verbose < 2)
859                    return;
860    
861            debug("console slaves (xterms): %s\n", allow_slaves?
862                "yes" : "no");
863    
864            debug("console handles:\n");
865            debug_indentation(iadd);
866    
867            for (i=0; i<n_console_handles; i++) {
868                    if (!console_handles[i].in_use)
869                            continue;
870                    debug("%i: \"%s\"", i, console_handles[i].name);
871                    if (console_handles[i].using_xterm)
872                            debug(" [xterm]");
873                    if (console_handles[i].inputonly)
874                            debug(" [inputonly]");
875                    if (console_handles[i].outputonly)
876                            debug(" [outputonly]");
877                    if (i == machine->main_console_handle) {
878                            debug(" [MAIN CONSOLE]");
879                            listed_main = 1;
880                    }
881                    debug("\n");
882            }
883    
884            debug_indentation(-iadd);
885    
886            if (!listed_main)
887                    fatal("WARNING! no main console handle?\n");
888    }
889    
890    
891    /*
892   *  console_allow_slaves():   *  console_allow_slaves():
893   *   *
894   *  This function tells the console subsystem whether or not to open up   *  This function tells the console subsystem whether or not to open up
# Line 788  int console_are_slaves_allowed(void) Line 914  int console_are_slaves_allowed(void)
914  /*  /*
915   *  console_warn_if_slaves_are_needed():   *  console_warn_if_slaves_are_needed():
916   *   *
917   *  Prints a warning if slave xterms are needed (i.e. there is more than one   *  Prints an error (during startup of the emulator) if slave xterms are needed
918   *  console handle in use), but they are not currently allowed.   *  (i.e. there is more than one console handle in use which is used for
919     *  INPUT), but they are not currently allowed.
920     *
921     *  This function should be called during startup (with init = 1), and every
922     *  time a console handle changes/upgrades its in_use_for_input from 0 to 1.
923     *
924     *  If init is non-zero, this function doesn't return if there was a warning.
925     *
926     *  If init is zero, no warning is printed. 1 is returned if there were more
927     *  than one input, 0 otherwise.
928   */   */
929  void console_warn_if_slaves_are_needed(void)  int console_warn_if_slaves_are_needed(int init)
930  {  {
931          int i, n = 0;          int i, n = 0;
932    
933            if (allow_slaves)
934                    return 0;
935    
936          for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)          for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
937                  if (console_handles[i].in_use &&                  if (console_handles[i].in_use &&
938                        console_handles[i].in_use_for_input &&
939                      !console_handles[i].using_xterm)                      !console_handles[i].using_xterm)
940                          n ++;                          n ++;
941    
942          if (!allow_slaves && n > 1) {          if (n > 1) {
943                  fatal("#\n#  WARNING! More than one console output is in use,"                  if (init) {
944                      "\n#  but xterm slaves are not enabled. Behaviour will\n"                          fatal("#\n#  ERROR! More than one console input is "
945                      "#  be undefined.  (Use -x to enable slave xterms.)\n#\n");                              "in use,\n#  but xterm slaves are not enabled.\n"
946                  for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)                              "#\n");
947                          if (console_handles[i].in_use &&                          fatal("#  Use -x to enable slave xterms.)\n#\n");
948                              !console_handles[i].using_xterm)                          for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
949                                  fatal("#  console handle %i: '%s'\n",                                  if (console_handles[i].in_use &&
950                                      i, console_handles[i].name);                                      console_handles[i].in_use_for_input &&
951                  fatal("#\n");                                      !console_handles[i].using_xterm)
952                                            fatal("#  console handle %i: '%s'\n",
953                                                i, console_handles[i].name);
954                            fatal("#\n");
955                            exit(1);
956                    }
957                    return 1;
958          }          }
959    
960            return 0;
961  }  }
962    
963    
# Line 830  void console_init(void) Line 978  void console_init(void)
978                      " console 0: handle = %i\n", handle);                      " console 0: handle = %i\n", handle);
979                  exit(1);                  exit(1);
980          }          }
981    
982            chp->in_use_for_input = 1;
983  }  }
984    

Legend:
Removed from v.21  
changed lines
  Added in v.22

  ViewVC Help
Powered by ViewVC 1.1.26