背景

在嵌入式系统经常需要自动登录tty,以实现业务程序开机启动的效果。
网上有篇文章ubuntu自动登录tty1(shell,text)配置转发挺多,但我弄明白原理后,觉得可以进一步简化,经测试,简化成功。

自动登录原理

修改/etc/init/tty1.conf

Ubuntu默认的tty1.conf内容如下

# tty1 - getty
#
# This service maintains a getty on tty1 from the point the system is
# started until it is shut down again.

start on stopped rc RUNLEVEL=[2345] and (
            not-container or
            container CONTAINER=lxc or
            container CONTAINER=lxc-libvirt)

stop on runlevel [!2345]

respawn
exec /sbin/getty -8 38400 tty1

实现自动登录主要通过修改最后一行的getty命令行参数实现,所以我们首先需要弄明白getty各选项的含义:

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]
  1. 首先明确一点,getty的最后2个必选参数portbaud_rate分别是剔除/dev/前缀的终端设备文件名波特率的值,位置千万不能挪到前面。对于本例,就是tty138400(不知为何它俩内部调换位置getty也能正确解析😓)
  2. -8 表示终端设备是8-bit clean,因此不需要做奇偶校验(即串口配置常见的8N1的那个N

参考帖子修改解析

参考帖子将tty1.conf文件最后一行改成下面模样

exec /sbin/getty -n -l /usr/bin/autologin -8 38400 tty1

这里使用了getty的另外2个选项-n-l,我们分别看下含义:

-n, --skip-login
              Do  not prompt the user for a login name. This can be used in connection with -l option to invoke a non-standard login process such as a BBS system. Note that with the -n  option, agetty gets no input from user who logs in and therefore won't be able to figure out parity, character size, and newline processing of the connection. It defaults to space parity, 7 bit characters, and ASCII CR (13) end-of-line character.  Beware that the program that agetty starts (usually /bin/login) is run as root.

       -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 password file).

-n的作用是不等待用户输入用户名,相当于跳过认证环节;-l的作用是替换系统默认的login程序/bin/login用户指定的login程序,比如bbs客户端等。这里参考帖子将/bin/login替换成/usr/bin/autologin

而/usr/bin/autologin是个shell脚本:

#!/bin/bash
/bin/login -f root #将root替换成你的用户名

看到没,这个脚本只是将/bin/login封装了一下,传递了选项-f,本质上仍然是/bin/login

我们看下/bin/login的-f选项是啥意思

-f
           Do not perform authentication, user is preauthenticated.

           Note: In that case, username is mandatory.

-f的作用是让login不要执行认证,即不要读取/etc/passwd文件的密码字段,因为getty也没获取用户名嘛!

综合起来,就是getty执行(exec)了一个默认登录root的login程序,从而实现自动登录

我的进一步简化

那个仅仅是改变/bin/login行为的shell脚本,就是个wrapper,能否将其去掉呢?
注意到getty有个-a选项

-a, --autologin username
              Log the specified user automatically in without asking for a login name and password. The -f username option is added to the  /bin/login  command  line  by  default.  The --login-options option changes this default behaviour and then only \u is replaced by the username and no other option is added to the login command line.

-a选项的值会被getty当作/bin/login的-f选项的值原样传递过去,这样就不需要那个wrapper脚本了。

实际改动

根据上面的思路,将tty1.conf的最后一行修改为:

exec /sbin/getty -8 -a root 38400 tty1

这行代码相比原版就多了个-a root选项,整句意思是,当用户以38400的波特率连接tty1时,默认root登录,且通知/bin/login不要对其做认证,直接启动/etc/passwd中对应的shell。

实测修改后业务程序仍可以开机自启动。

总结

其实我一开始是用ps -efj命令查看进程组的含义,无意间发现6个tty就tty1没有getty值守,而是运行着/bin/login -f,联想到为啥设备能自启动业务应用,就一路逛过来了,还发现了个优化方法。

看来爱走神的毛病是改不掉啦😉