f5c980005bf93087e27b70af33ad06d8c31012a4
[gdbmicli.git] / libmigdb / src / get_free_vt.c
1 /**[txh]********************************************************************
2
3   Copyright (c) 2004 by Salvador E. Tropea.
4   Covered by the GPL license.
5
6   Module: Linux VT.
7   Comments:
8   Helper to find a free VT. That's 100% Linux specific.@p
9   The code comes from "lconsole.c" from Allegro project and was originally
10 created by Marek Habersack and then modified by George Foot. I addapted it
11 to my needs and changed license from giftware to GPL.@p
12   
13 ***************************************************************************/
14
15 #define _GNU_SOURCE
16 #include <string.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/ioctl.h>
21 #ifdef __APPLE__
22 #include <util.h>
23 #endif /* __APPLE__ */
24
25 #include "mi_gdb.h"
26
27 #if !defined(__linux__)
28
29 int mi_look_for_free_vt()
30 {
31  return -1;
32 }
33
34 mi_aux_term *gmi_look_for_free_vt()
35 {
36  return NULL;
37 }
38
39 #else
40
41 #include <linux/vt.h>
42
43 /**[txh]********************************************************************
44
45   Description:
46   Look for a free and usable Linux VT. Low level, use
47 @x{gmi_look_for_free_vt}.
48   
49   Return: The VT number or <0 on error.
50   
51 ***************************************************************************/
52
53 int mi_look_for_free_vt()
54 {/* Code from Allegro. */
55  int tty, console_fd, fd;
56  unsigned short mask;
57  char tty_name[16];
58  struct vt_stat vts; 
59
60  /* Now we need to find a VT we can use.  It must be readable and
61   * writable by us, if we're not setuid root.  VT_OPENQRY itself
62   * isn't too useful because it'll only ever come up with one 
63   * suggestion, with no guarrantee that we actually have access 
64   * to it.
65   *
66   * At some stage I think this is a candidate for config
67   * file overriding, but for now we'll stat the first N consoles
68   * to see which ones we can write to (hopefully at least one!),
69   * so that we can use that one to do ioctls.  We used to use 
70   * /dev/console for that purpose but it looks like it's not 
71   * always writable by enough people.
72   *
73   * Having found and opened a writable device, we query the state
74   * of the first sixteen (fifteen really) consoles, and try 
75   * opening each unused one in turn.
76   */
77
78  console_fd=open("/dev/console",O_WRONLY);
79  if (console_fd<0)
80    {
81     int n;
82     /* Try some ttys instead... */
83     for (n=1; n<=24; n++)
84        {
85         snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",n);
86         console_fd=open(tty_name,O_WRONLY);
87         if (console_fd>=0)
88            break;
89        }
90     if (n>24)
91        return -1;
92    }
93
94  /* Get the state of the console -- in particular, the free VT field */
95  if (ioctl(console_fd,VT_GETSTATE,&vts))
96     return -2;
97  close(console_fd);
98
99  /* We attempt to set our euid to 0; if we were run with euid 0 to
100   * start with, we'll be able to do this now.  Otherwise, we'll just
101   * ignore the error returned since it might not be a problem if the
102   * ttys we look at are owned by the user running the program. */
103  seteuid(0);
104
105  /* tty0 is not really a console, so start counting at 2. */
106  fd=-1;
107  for (tty=1, mask=2; mask; tty++, mask<<=1)
108      if (!(vts.v_state & mask))
109        {
110         snprintf(tty_name,sizeof(tty_name),"/dev/tty%d",tty);
111         fd=open(tty_name,O_RDWR);
112         if (fd!=-1)
113           {
114            close(fd);
115            break;
116           }
117        }
118
119  seteuid(getuid());
120
121  if (!mask)
122     return -3;
123
124  return tty;
125 }
126
127 /**[txh]********************************************************************
128
129   Description:
130   Look for a free and usable Linux VT to be used by the child.
131   
132   Return: A new mi_aux_term structure, you can use @x{gmi_end_aux_term} to
133 release it.
134   
135 ***************************************************************************/
136
137 mi_aux_term *gmi_look_for_free_vt()
138 {
139  int vt=mi_look_for_free_vt();
140  mi_aux_term *res;
141
142  if (vt<0)
143     return NULL;
144  res=(mi_aux_term *)malloc(sizeof(mi_aux_term));
145  if (!res)
146     return NULL;
147  res->pid=-1;
148  asprintf(&res->tty,"/dev/tty%d",vt);
149  return res;
150 }
151
152 #endif
153