tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

add a "notty" flag to ttys(5) for init(8)



The other day I was having problems with a syslogd dying during log
rotation, at which point I was having to notice this happened (which I
could tell from the emails from cron, once I checked email) and then of
course I had to manually restart it.

For a very long time now I've wanted a simple solution to deal with
managing essential services in an rc.d world in such a way that I could
automate such things.

I finally remembered sysutils/monit and gave it a try.  It works
amazingly well and while it is extremely minimal in requirements it
provides an enormous amount of features and flexibility.  It was trivial
to set up to monitor and restart syslogd and it works very very well.

However that raised the question of how to reliably start it.

I figured the best way would be to run it from init(8) so that it would
be running at all times while logins are allowed, and so that init(8)
could restart it should it ever die.

The problem was that monit, like most programs, doesn't want arbitrary
arguments on its command line, and the normal way init(8) starts a
"getty" is to explicitly pass the terminal name as an additional
argument.  I could have named the session "-I", but that's UGLY.

In the end I was unable to make it work without writing a (trivial)
wrapper script, but that also seemed like a crazy requirement when all I
really wanted was for init(8) to not add an extra argument if it wasn't
wanted/needed.

So, I decided to add a "notty" flag to ttys(5) for init(8).

(line numbers are not exact)

Index: init.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/sbin/init/init.c,v
retrieving revision 1.108
diff -u -u -r1.108 init.c
--- init.c	22 Jun 2020 07:50:53 -0000	1.108
+++ init.c	17 Apr 2025 17:39:08 -0000
@@ -1136,7 +1145,8 @@
 		free(sp->se_getty);
 		free(sp->se_getty_argv);
 	}
-	(void)asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
+	(void)asprintf(&sp->se_getty, "%s %s", typ->ty_getty,
+		       typ->ty_status & TTY_NOTTY ? "" : typ->ty_name);
 	if (!sp->se_getty)
 		return 0;
 	sp->se_getty_argv = construct_argv(sp->se_getty);


Of course there are other necessary (but simple and, I think, obvious)
changes in lib/libc/gen/getttyent.c and the documentation.  Notably in
ttys(5) I wrote:

     notty    Do not add the tty name as an argument to the command.  This is
              useful to allow init(8) to be used to run any command that must
              be started when logins are allowed and which must always be
              running.  The command will be restarted if it exits.

I can now add a line like the following to /etc/ttys:

	monitor "/usr/pkg/bin/monit -I"         -	on notty

and, voila!

	# kill -1 1
	# who -a
	                   ? system boot Apr 17 14:51   .            0  term=0 exit=0 sess=0 type=boot time
	                   ? system down Apr 17 14:52   .            0  term=0 exit=0 sess=0 type=down time
	                   ? run-level m Apr 18 11:20   .            0  new=m old=T sess=0 type=run level
	/usr/libexec/getty - constty     Apr 17 14:52 20:28       3916  term=0 exit=0 sess=1 type=login process
	woods              - pts/0       Apr 17 14:52 00:19       3928  term=0 exit=0 sess=0 type=user process  (10.0.2.146)
	/usr/pkg/bin/monit ? monitor     Apr 18 11:20   .        20027  term=0 exit=0 sess=18 type=login process


So, to me this seems like a simple but highly effective feature, and it
is arguably far more elegant and simple than writing wrapper scripts.

What do you all think?

For those who want to do some bikeshedding, we could discuss adding a
full-fledged /etc/inittab to init(8)!  :-)  [But not seriously -- I'm
quite happy with /etc/ttys just being able to start extra processes
whenever logins are allowed and using /etc/rc (with all of /etc/rc.d,
etc.) to do the rest.  No need to turn the world upside down just for
this simple feature!]


For the curious, this is the meat in my first /etc/monit/monitrc:

set daemon  5               # check services at 5 second intervals
set init                    # don't become a daemon (also called with -I)
set log syslog
set pidfile /var/run/monit.pid
set idfile /var/run/monit.id
set statefile /var/run/monit.state
set mailserver localhost               # primary mailserver
set mail-format { from: monit%more.weird.com@localhost }
set alert root%more.weird.com@localhost          # receive all alerts
set httpd port 2812 and
    use address localhost  # only accept connection from localhost
    allow localhost        # allow localhost to connect to the server and
    allow admin:monit      # require user 'admin' with password 'monit'
check process syslogd with pidfile /var/run/syslogd.pid
    start program = "/etc/rc.d/syslogd start" with timeout 60 seconds
    stop program  = "/etc/rc.d/syslogd stop"
    group server

--
					Greg A. Woods <gwoods%acm.org@localhost>

Kelowna, BC     +1 250 762-7675           RoboHack <woods%robohack.ca@localhost>
Planix, Inc. <woods%planix.com@localhost>     Avoncote Farms <woods%avoncote.ca@localhost>

Attachment: pgp52yL7gabji.pgp
Description: OpenPGP Digital Signature



Home | Main Index | Thread Index | Old Index