2

I want to make centos show a tui (ncurses program) after boot and without login. I don't want the login prompt to be displayed.

Program functions: Network configuration, Reboot, Shutdown

Is there any to way to achieve that?

  • 1
    Sounds alarmingly insecure. – steve Oct 22 '16 at 21:57
  • It' just for end user (mostly windows users), the management will be done via ssh. – Gen Erike Oct 23 '16 at 19:44
4

You could do this by replacing the login program used for getty with your own program. For instance, on my Debian machine, the getty calls are in /etc/inittab:

# /sbin/getty invocations for the runlevels.
#
# The "id" field MUST be the same as the last
# characters of the device (after "tty").
#
# Format:
#  <id>:<runlevels>:<action>:<process>
#
# Note that on most Debian systems tty7 is used by the X Window System,
# so if you want to add more getty's go ahead but skip tty7 if you run X.
#
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6

# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100

# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3

while Debian actually uses agetty:

NAME   
       agetty - alternative Linux getty


SYNOPSIS
       agetty  [-8chiLmnsUw]  [-a  user]  [-f  issue_file] [-H login_host] [-I
       init] [-l login_program] [-t timeout] port baud_rate,...  [term]

and that can invoke a different program using the -l option:

   -l, --login-program login_program
          Invoke the specified login_program instead of /bin/login.   This
          allows the use of a non-standard login program (for example, one
          that asks for a dial-up password or that uses a different  pass‐
          word file).

Your special-purpose program could be made to run on each "tty". If you do this, you should give some attention to making sure that you can log directly into the machine for maintenance. That might be in single-user mode, or via ssh. The getty definitions do not apply to ssh.

With CentOS7, using systemd, things are organized differently, but the end result is the same. Using systemctl list-unit-files, the relevant service is getty@.service. Like any other service, this can be customized. Using locate to get clues:

/etc/selinux/targeted/modules/active/modules/getty.pp
/etc/systemd/system/getty.target.wants
/etc/systemd/system/getty.target.wants/getty@tty1.service
/usr/lib/systemd/system/console-getty.service
/usr/lib/systemd/system/container-getty@.service
/usr/lib/systemd/system/getty.target
/usr/lib/systemd/system/getty@.service
/usr/lib/systemd/system/serial-getty@.service
/usr/lib/systemd/system/multi-user.target.wants/getty.target
/usr/lib/systemd/system-generators/systemd-getty-generator

The files in /usr/lib/systemd/system/ contain the calls for agetty (which has a manual page on CentOS as well). You could modify those:

ExecStart=-/sbin/agetty --noclear --keep-baud pts/%I 115200,38400,9600 $TERM

The symbolic link /usr/lib/systemd/system/multi-user.target.wants/getty.target and its target getty.target do not contain calls to agetty.

CentOS6 is in between: my machine has mingetty and no systemd. From the manual page:

MINGETTY(8)                Linux Programmer's Manual               MINGETTY(8)


NAME   
       mingetty - minimal getty for consoles

SYNOPSIS
       mingetty  [--noclear] [--nonewline] [--noissue] [--nohangup] [--nohost-
       name]    [--long-hostname]     [--loginprog=/bin/login]     [--nice=10]
       [--delay=5]  [--chdir=/home]  [--chroot=/chroot] [--autologin username]
       [--loginpause] tty


DESCRIPTION
       mingetty is a minimal  getty  for  use  on  virtual  consoles.   Unlike
       agetty(8),  mingetty  is  not  suitable  for serial lines.  I recommend
       using mgetty(8) for this purpose.

Like agetty, it can be customized:

   --loginprog /bin/login
          Change the login app.

Start with its configuration file:

# tty - getty
#
# This service maintains a getty on the specified device.
#
# Do not edit this file directly. If you want to change the behaviour,
# please create a file tty.override and put your changes there.

stop on runlevel [S016]

respawn
instance $TTY
exec /sbin/mingetty $TTY
usage 'tty TTY=/dev/ttyX  - where X is console id'

That leads us to look for information about tty.override, which according to this

is a script which you provide in /etc/init/tty.override (it shows an example for autologon on tty1 from which you can get the general sense of what the script could do). The $TTY variable, by the way, is set in /etc/init/start-ttys.conf (the initscripts package of which these are a part does not have detailed documentation).

  • Thanks Thomas, it's a good approach I'll try it tomorrow. – Gen Erike Oct 22 '16 at 23:09
  • I'm using CentOS 6.8, the init scripts structure seems different: – Gen Erike Oct 23 '16 at 19:16
  • In CentOS 6.8 the /etc/inittab is empty (just comments) and there are additional files (tty.conf, start-ttys.conf ...) – Gen Erike Oct 23 '16 at 19:19
  • tty.conf is a default configuration; you can make your own script using the $TTY variable to identify to mingetty which terminal you want to use. – Thomas Dickey Oct 23 '16 at 20:06
2

M. Dickey's systemd answer is a little vague. Here are the details for a systemd operating system.

The service that presents the login prompt is an instance of the getty@.service template, getty@tty6.service for the login service on tty6 for example. To replace this with your own service on such a terminal device, you need to do two things.

Create the service definition.

This is fairly easy:

# /etc/systemd/system/my-terminal-ui@.service

[Unit]
Description=Custom user interface on %I
Documentation=https://unix.stackexchange.com/a/318336/5132
Conflicts=getty@%I.service
Before=getty.target

[Service]
ExecStart=/usr/local/sbin/my-custom-user-interface
StandardInput=tty
StandardOutput=tty
Restart=always
RestartSec=1
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
SendSIGHUP=yes

[Install]
WantedBy=multi-user.target

This is a template service unit, which will be instantiated with the name of a kernel virtual terminal device as its template parameter.

Ensure that your service is automatically started on bootstrap.

This is the more complex part.

For starters, you need to decide which kernel virtual terminal device this is going to run on. Several pieces of information come into play here:

  • In the Fedora world, since 2008, the graphical user interface uses the first kernel virtual terminal device, tty1. You must choose between not using that virtual terminal device and not using (or manually adjusting) the graphical user interface.
  • systemd's logind attempts to demand-start login services on kernel virtual terminals up to the maximum set in NAutoVTs in the logind.conf configuration file. This is tty1 to tty6 by default.
  • That leaves tty7 free in the Fedora world. But in the Debian world, even though Debian is now a systemd operating system, the graphical user interface uses tty7. You might want to take porting to Debian into consideration.
  • The systemd world tries to make kernel virtual terminal #6 the login prompt that is "always there", the one that muscle memory has you hitting Control+Alt+F6 for.

Let's say that you pick tty5.

You need to stop logind from demand-starting the autovt@tty5.service, which is another name for getty@tty5.service, whenever the user switches to kernel virtual terminal #5. You can do this by lowering the NAutoVTs setting in logind.conf from 6 to (say) 4.

You need to make sure that your service is automatically started at system bootstrap, i.e. that it is "enabled":

systemctl enable my-terminal-ui@tty5.service

Alternatives

There are other ways of doing this.

a non-templated service

Instead of my-terminal-ui@.service have my-terminal-ui.service and hardwire the terminal device name in the unit by replacing %I with (say) tty5.

I've given this as a template definition because that makes it easier to make a choice different to tty5.

using one of autovt@ttyN instead of your own name

You could decide to use /etc/systemd/system/autovt@tty5.service as the name of your service definition. This would override the instantiation of the autovt@.service template.

The advantage of this approach is that you then don't need to bother with NAutoVTs and enabling the service at all, and can just leave logind to demand-start your service whenever the user switches to kernel virtual terminal #5.

The disadvantage is that the demand-start mechanism was designed not to run login processes on unused kernel virtual terminals. As such, your service will not be run at system bootstrap, but will only be run the first time that you activate kernel virtual terminal #5. This on-demand startup may not be what you want. Other parts of your custom system may be expecting your service to be already running from bootstrap onwards, for example.

editing a getty@ttyN

People steeped in the ways of /etc/ttys and /etc/inittab see modifying getty@tty5.service as the way to do things. They run commands like

systemctl edit getty@tty5.service

and add an override that states

[Service]
# This blank assignment is not a mis-print.
ExecStart=
ExecStart=/usr/local/sbin/my-custom-user-interface

This has several problems.

Making a service that is named getty not run an {a,min,f}getty program is not a terrifically maintainable idea. Years from now, when you've forgotten what you've done here, or when someone else comes to take over administration of such a system, it won't be obvious that "getty" services don't always run a getty utility.

Don't think of getty@.service as a space for whatever is run on that terminal, to be modified as needed. That's not really the systemd way of thinking about this. getty@.service runs a "getty" program. A service that runs an entirely different program that doesn't run anything like a "getty" service should be a separate service definition in its own right.

Moreover: A separate service definition allows one to not define the service as anything like a "getty" service. The aforegiven service definition copies most of the behaviour of the "getty" service, including trying hard to clean your screen (as the world wants you to do). But you might not want, say, TTYReset=yes or any fiddling around with utmpx going on on a service like yours which really isn't a "login" service and might not want its screen cleared quite so aggressively.

Furthermore: A separate service definition is simpler to change in the future. Changing from tty5 (if that is not satisfactory) to tty8 is simple with the aforegiven template. Just instantiate it on tty8 instead of on tty5. It's somewhat harder to un-pick a set of local customizations from getty@tty5.service and then re-make them against getty@tty8.service.

aliasing autovt@tty5 to my-terminal-ui@tty5

This is the logical progression from editing getty@tty5.service, as obviously the autovt@ttyN aliases are a whatever is meant to be started here mechanism that permits substituting other things for getty@ttyN.

But it suffers from the same aforementioned disadvantages as using the autovt@tty5.service name directly, in that it becomes involved with logind's attempts to not start login services which may not be what you want. It is actually whatever is meant to be demand-started here by logind.

Further reading

  • I appreciate your help but I found that systemd works only for CentOS 7, and I'm working with CentOS 6.8 – Gen Erike Oct 23 '16 at 19:20
0

So, after some googling I found two solutions:

https://serverfault.com/questions/323289/replacing-tty-with-a-script-in-centos-6

and

https://www.centos.org/forums/viewtopic.php?t=2414

Finally I come up with the following:

1) Create '/etc/init/launch.conf' with this content:

start on stopped rc RUNLEVEL=[2345]
stop on runlevel [S016]
respawn
console owner
exec /usr/bin/openvt -c 1 -w -f -- /usr/sbin/setup

In this example it runs text mode setup tool

2) Edit '/etc/init/start-ttys.conf' to replace the tty with launch:

start on stopped rc RUNLEVEL=[2345]

env ACTIVE_CONSOLES=/dev/tty[1-6]
env X_TTY=/dev/tty1
task
script
    . /etc/sysconfig/init
    for tty in $(echo $ACTIVE_CONSOLES) ; do
        [ "$RUNLEVEL" = "5" -a "$tty" = "$X_TTY" ] && continue
        #initctl start tty TTY=$tty
        initctl start launch TTY=$tty
    done
end script

I don't know if this is the best solution, but it's working and the setup program is displayed after boot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.