1 /*
2  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany
3  * Copyright 1993 by David Wexelblat <dwex@goblin.org>
4  * Copyright 1999 by David Holland <davidh@iquest.net>
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that copyright
9  * notice and this permission notice appear in supporting documentation, and
10  * that the names of the copyright holders not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  The copyright holders make no representations
13  * about the suitability of this software for any purpose.  It is provided "as
14  * is" without express or implied warranty.
15  *
16  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND IN NO
18  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22  * OF THIS SOFTWARE.
23  */
24 
25 #ifdef HAVE_XORG_CONFIG_H
26 #include <xorg-config.h>
27 #endif
28 
29 #include "xf86.h"
30 #include "xf86Priv.h"
31 #include "xf86_OSlib.h"
32 #ifdef HAVE_SYS_KD_H
33 #include <sys/kd.h>
34 #endif
35 
36 /*
37  * Applications see VT number as consecutive integers starting from 1.
38  * VT number			VT device
39  * -------------------------------------------------------
40  *     1             :          /dev/vt/0 (Alt + Ctrl + F1)
41  *     2             :          /dev/vt/2 (Alt + Ctrl + F2)
42  *     3             :          /dev/vt/3 (Alt + Ctrl + F3)
43  *  ... ...
44  */
45 #define	CONSOLE_VTNO	1
46 #define	SOL_CONSOLE_DEV	"/dev/console"
47 
48 static Bool KeepTty = FALSE;
49 static Bool UseConsole = FALSE;
50 
51 #ifdef HAS_USL_VTS
52 static int VTnum = -1;
53 static int xf86StartVT = -1;
54 static int vtEnabled = 0;
55 #endif
56 
57 /* Device to open as xf86Info.consoleFd */
58 static char consoleDev[PATH_MAX] = "/dev/fb";
59 
60 /* Set by -dev argument on CLI
61    Used by hw/xfree86/common/xf86AutoConfig.c for VIS_GETIDENTIFIER */
62 _X_HIDDEN char xf86SolarisFbDev[PATH_MAX] = "/dev/fb";
63 
64 static void
switch_to(int vt,const char * from)65 switch_to(int vt, const char *from)
66 {
67     int ret;
68 
69     SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_ACTIVATE, vt));
70     if (ret != 0)
71         xf86Msg(X_WARNING, "%s: VT_ACTIVATE failed: %s\n",
72                 from, strerror(errno));
73 
74     SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_WAITACTIVE, vt));
75     if (ret != 0)
76         xf86Msg(X_WARNING, "%s: VT_WAITACTIVE failed: %s\n",
77                 from, strerror(errno));
78 }
79 
80 void
xf86OpenConsole(void)81 xf86OpenConsole(void)
82 {
83     int i;
84 
85 #ifdef HAS_USL_VTS
86     int fd;
87     struct vt_mode VT;
88     struct vt_stat vtinfo;
89     MessageType from = X_PROBED;
90 #endif
91 
92     if (serverGeneration == 1) {
93         /* Check if we're run with euid==0 */
94         if (geteuid() != 0)
95             FatalError("xf86OpenConsole: Server must be suid root\n");
96 
97 #ifdef HAS_USL_VTS
98 
99         /*
100          * Setup the virtual terminal manager
101          */
102         if ((fd = open("/dev/vt/0", O_RDWR, 0)) == -1) {
103             xf86ErrorF("xf86OpenConsole: Cannot open /dev/vt/0 (%s)\n",
104                        strerror(errno));
105             vtEnabled = 0;
106         }
107         else {
108             if (ioctl(fd, VT_ENABLED, &vtEnabled) < 0) {
109                 xf86ErrorF("xf86OpenConsole: VT_ENABLED failed (%s)\n",
110                            strerror(errno));
111                 vtEnabled = 0;
112             }
113         }
114 #endif                          /*  HAS_USL_VTS */
115 
116         if (UseConsole) {
117             strlcpy(consoleDev, SOL_CONSOLE_DEV, sizeof(consoleDev));
118 
119 #ifdef HAS_USL_VTS
120             xf86Info.vtno = CONSOLE_VTNO;
121 
122             if (vtEnabled == 0) {
123                 xf86StartVT = 0;
124             }
125             else {
126                 if (ioctl(fd, VT_GETSTATE, &vtinfo) < 0)
127                     FatalError
128                         ("xf86OpenConsole: Cannot determine current VT\n");
129                 xf86StartVT = vtinfo.v_active;
130             }
131 #endif                          /*  HAS_USL_VTS */
132             goto OPENCONSOLE;
133         }
134 
135 #ifdef HAS_USL_VTS
136         if (vtEnabled == 0) {
137             /* VT not enabled - kernel too old or Sparc platforms
138                without visual_io support */
139             xf86Msg(from, "VT infrastructure is not available\n");
140 
141             xf86StartVT = 0;
142             xf86Info.vtno = 0;
143             strlcpy(consoleDev, xf86SolarisFbDev, sizeof(consoleDev));
144             goto OPENCONSOLE;
145         }
146 
147         if (ioctl(fd, VT_GETSTATE, &vtinfo) < 0)
148             FatalError("xf86OpenConsole: Cannot determine current VT\n");
149 
150         xf86StartVT = vtinfo.v_active;
151 
152         if (VTnum != -1) {
153             xf86Info.vtno = VTnum;
154             from = X_CMDLINE;
155         }
156         else if (xf86Info.ShareVTs) {
157             xf86Info.vtno = vtinfo.v_active;
158             from = X_CMDLINE;
159         }
160         else {
161             if ((ioctl(fd, VT_OPENQRY, &xf86Info.vtno) < 0) ||
162                 (xf86Info.vtno == -1)) {
163                 FatalError("xf86OpenConsole: Cannot find a free VT\n");
164             }
165         }
166 
167         xf86Msg(from, "using VT number %d\n\n", xf86Info.vtno);
168         snprintf(consoleDev, PATH_MAX, "/dev/vt/%d", xf86Info.vtno);
169 
170         if (fd != -1) {
171             close(fd);
172         }
173 
174 #endif                          /* HAS_USL_VTS */
175 
176  OPENCONSOLE:
177         if (!KeepTty)
178             setpgrp();
179 
180         if (((xf86Info.consoleFd = open(consoleDev, O_RDWR | O_NDELAY, 0)) < 0))
181             FatalError("xf86OpenConsole: Cannot open %s (%s)\n",
182                        consoleDev, strerror(errno));
183 
184         /* Change ownership of the vt or console */
185         chown(consoleDev, getuid(), getgid());
186 
187 #ifdef HAS_USL_VTS
188         if (xf86Info.ShareVTs)
189             return;
190 
191         if (vtEnabled) {
192             /*
193              * Now get the VT
194              */
195             switch_to(xf86Info.vtno, "xf86OpenConsole");
196 
197 #ifdef VT_SET_CONSUSER          /* added in snv_139 */
198             if (strcmp(display, "0") == 0)
199                 if (ioctl(xf86Info.consoleFd, VT_SET_CONSUSER) != 0)
200                     xf86Msg(X_WARNING,
201                             "xf86OpenConsole: VT_SET_CONSUSER failed\n");
202 #endif
203 
204             if (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) < 0)
205                 FatalError("xf86OpenConsole: VT_GETMODE failed\n");
206 
207             OsSignal(SIGUSR1, xf86VTAcquire);
208             OsSignal(SIGUSR2, xf86VTRelease);
209 
210             VT.mode = VT_PROCESS;
211             VT.acqsig = SIGUSR1;
212             VT.relsig = SIGUSR2;
213 
214             if (ioctl(xf86Info.consoleFd, VT_SETMODE, &VT) < 0)
215                 FatalError("xf86OpenConsole: VT_SETMODE VT_PROCESS failed\n");
216 
217             if (ioctl(xf86Info.consoleFd, VT_SETDISPINFO, atoi(display)) < 0)
218                 xf86Msg(X_WARNING, "xf86OpenConsole: VT_SETDISPINFO failed\n");
219         }
220 #endif
221 
222 #ifdef KDSETMODE
223         SYSCALL(i = ioctl(xf86Info.consoleFd, KDSETMODE, KD_GRAPHICS));
224         if (i < 0) {
225             xf86Msg(X_WARNING,
226                     "xf86OpenConsole: KDSETMODE KD_GRAPHICS failed on %s (%s)\n",
227                     consoleDev, strerror(errno));
228         }
229 #endif
230     }
231     else {                      /* serverGeneration != 1 */
232 
233 #ifdef HAS_USL_VTS
234         if (vtEnabled && !xf86Info.ShareVTs) {
235             /*
236              * Now re-get the VT
237              */
238             if (xf86Info.autoVTSwitch)
239                 switch_to(xf86Info.vtno, "xf86OpenConsole");
240 
241 #ifdef VT_SET_CONSUSER          /* added in snv_139 */
242             if (strcmp(display, "0") == 0)
243                 if (ioctl(xf86Info.consoleFd, VT_SET_CONSUSER) != 0)
244                     xf86Msg(X_WARNING,
245                             "xf86OpenConsole: VT_SET_CONSUSER failed\n");
246 #endif
247 
248             /*
249              * If the server doesn't have the VT when the reset occurs,
250              * this is to make sure we don't continue until the activate
251              * signal is received.
252              */
253             if (!xf86VTOwner())
254                 sleep(5);
255         }
256 #endif                          /* HAS_USL_VTS */
257 
258     }
259 }
260 
261 void
xf86CloseConsole(void)262 xf86CloseConsole(void)
263 {
264 #ifdef HAS_USL_VTS
265     struct vt_mode VT;
266 #endif
267 
268 #if !defined(__i386__) && !defined(__i386) && !defined(__x86)
269 
270     if (!xf86DoConfigure) {
271         int fd;
272 
273         /*
274          * Wipe out framebuffer just like the non-SI Xsun server does.  This
275          * could be improved by saving framebuffer contents in
276          * xf86OpenConsole() above and restoring them here.  Also, it's unclear
277          * at this point whether this should be done for all framebuffers in
278          * the system, rather than only the console.
279          */
280         if ((fd = open(xf86SolarisFbDev, O_RDWR, 0)) < 0) {
281             xf86Msg(X_WARNING,
282                     "xf86CloseConsole():  unable to open framebuffer (%s)\n",
283                     strerror(errno));
284         }
285         else {
286             struct fbgattr fbattr;
287 
288             if ((ioctl(fd, FBIOGATTR, &fbattr) < 0) &&
289                 (ioctl(fd, FBIOGTYPE, &fbattr.fbtype) < 0)) {
290                 xf86Msg(X_WARNING,
291                         "xf86CloseConsole():  unable to retrieve framebuffer"
292                         " attributes (%s)\n", strerror(errno));
293             }
294             else {
295                 void *fbdata;
296 
297                 fbdata = mmap(NULL, fbattr.fbtype.fb_size,
298                               PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
299                 if (fbdata == MAP_FAILED) {
300                     xf86Msg(X_WARNING,
301                             "xf86CloseConsole():  unable to mmap framebuffer"
302                             " (%s)\n", strerror(errno));
303                 }
304                 else {
305                     memset(fbdata, 0, fbattr.fbtype.fb_size);
306                     munmap(fbdata, fbattr.fbtype.fb_size);
307                 }
308             }
309 
310             close(fd);
311         }
312     }
313 
314 #endif
315 
316 #ifdef KDSETMODE
317     /* Reset the display back to text mode */
318     SYSCALL(ioctl(xf86Info.consoleFd, KDSETMODE, KD_TEXT));
319 #endif
320 
321 #ifdef HAS_USL_VTS
322     if (vtEnabled) {
323         if (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) != -1) {
324             VT.mode = VT_AUTO;  /* Set default vt handling */
325             ioctl(xf86Info.consoleFd, VT_SETMODE, &VT);
326         }
327 
328         /* Activate the VT that X was started on */
329         if (xf86Info.autoVTSwitch)
330             switch_to(xf86StartVT, "xf86CloseConsole");
331     }
332 #endif                          /* HAS_USL_VTS */
333 
334     close(xf86Info.consoleFd);
335 }
336 
337 int
xf86ProcessArgument(int argc,char ** argv,int i)338 xf86ProcessArgument(int argc, char **argv, int i)
339 {
340     /*
341      * Keep server from detaching from controlling tty.  This is useful when
342      * debugging, so the server can receive keyboard signals.
343      */
344     if (!strcmp(argv[i], "-keeptty")) {
345         KeepTty = TRUE;
346         return 1;
347     }
348 
349     /*
350      * Use /dev/console as the console device.
351      */
352     if (!strcmp(argv[i], "-C")) {
353         UseConsole = TRUE;
354         return 1;
355     }
356 
357 #ifdef HAS_USL_VTS
358 
359     if ((argv[i][0] == 'v') && (argv[i][1] == 't')) {
360         if (sscanf(argv[i], "vt%d", &VTnum) == 0) {
361             UseMsg();
362             VTnum = -1;
363             return 0;
364         }
365 
366         return 1;
367     }
368 
369 #endif                          /* HAS_USL_VTS */
370 
371     if ((i + 1) < argc) {
372         if (!strcmp(argv[i], "-dev")) {
373             strlcpy(xf86SolarisFbDev, argv[i + 1], sizeof(xf86SolarisFbDev));
374             return 2;
375         }
376     }
377 
378     return 0;
379 }
380 
381 void
xf86UseMsg(void)382 xf86UseMsg(void)
383 {
384 #ifdef HAS_USL_VTS
385     ErrorF("vtX                    Use the specified VT number\n");
386 #endif
387     ErrorF("-dev <fb>              Framebuffer device\n");
388     ErrorF("-keeptty               Don't detach controlling tty\n");
389     ErrorF("                       (for debugging only)\n");
390     ErrorF("-C                     Use /dev/console as the console device\n");
391 }
392