aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/openvt.c
blob: 3cc97daa00cf5a171a35c5a8847f69be95bc551f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/* openvt.c - Run a program on a new VT
 *
 * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com>
 *
 * No Standard

USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))

config OPENVT
  bool "openvt"
  default n
  depends on TOYBOX_FORK
  help
    usage: openvt [-c NUM] [-sw] [COMMAND...]

    Start a program on a new virtual terminal.

    -c NUM  Use VT NUM
    -s    Switch to new VT
    -w    Wait for command to exit

    Together -sw switch back to originating VT when command completes.

config DEALLOCVT
  bool "deallocvt"
  default n
  help
    usage: deallocvt [NUM]

    Deallocate unused virtual terminals, either a specific /dev/ttyNUM, or all.
*/

#define FOR_openvt
#include "toys.h"
#include <linux/vt.h>
#include <linux/kd.h>

GLOBALS(
  long c;
)

int open_console(void)
{
  char arg = 0, *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
  int i, fd;

  for (i = 0; i < ARRAY_LEN(console_name); i++) {
    if (0>(fd = open(console_name[i], O_RDWR))) continue;
    if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
    close(fd);
  }
  for (fd = 0; fd < 3; fd++) if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
  error_exit("can't open console");
}

void openvt_main(void)
{
  struct vt_stat vstate;
  int fd;
  pid_t pid;

  // find current console
  if (-1 == (ioctl(fd = open_console(), VT_GETSTATE, &vstate)) ||
      (!TT.c && 0>=(TT.c = xioctl(fd, VT_OPENQRY, &fd))))
    perror_exit("can't find open VT");

  sprintf(toybuf, "/dev/tty%ld", TT.c);
  close(0);  //new vt becomes stdin
  dup2(dup2(xopen_stdio(toybuf, O_RDWR), 1), 2);
  if (FLAG(s)) {
    ioctl(0, VT_ACTIVATE, (int)TT.c);
    ioctl(0, VT_WAITACTIVE, (int)TT.c);
  }

  if (!(pid = xfork())) {
    setsid();
    ioctl(0, TIOCSCTTY, 0);
    if (fd>2) close(fd);
    xexec(toys.optargs);
  }

  if (FLAG(w)) {
    while (-1 == waitpid(pid, NULL, 0) && errno == EINTR);
    if (FLAG(s)) {
      ioctl(fd, VT_ACTIVATE, vstate.v_active);
      ioctl(fd, VT_WAITACTIVE, vstate.v_active);
      ioctl(fd, VT_DISALLOCATE, (int)TT.c);
    }
  }
  close(fd);
}

void deallocvt_main(void)
{
  int fd, vt_num = 0; // 0 = all

  if (*toys.optargs) vt_num = atolx_range(*toys.optargs, 1, 63);
  if (-1 == ioctl(fd = open_console(), VT_DISALLOCATE, vt_num))
    perror_exit("%d", vt_num);
  close(fd);
}