-
Notifications
You must be signed in to change notification settings - Fork 8
Home
tcllauncher is a way to have Tcl programs run out of /usr/local/bin, or wherever.
Now you might think, why bother? I’ll just put my script in there and do a #! thing to invoke Tcl.
Well, OK, but this has certain problems:
- everything will show in “ps” as tclsh
- everything will show in “top” as tclsh
- if there are any files you want to pull in that aren’t in a package, you have to invent your own place to install and locate them.
You’d like to be able to have stuff show up as its script name.
You could just copy or even link tclsh to the name of your program. Say, for instance, trackserver.
But then you have to invoke trackserver with arguments and do stuff to prep it, like:
cd ...somewhere...
/usr/local/bin/trackserver main.tcl
That’s the original purpose for tcllauncher, just to make that reasonable.
cp /usr/local/bin/tcllauncher /usr/local/bin/trackserver
trackserver
How does it find its files? It cd’s to the corresponding lib directory and a directory underneath that of the same name as the application, and sources main.tcl with tcl_interactive set to 0.
run
trackserver
what happens
/usr/local/bin/trackserver, a copy of /usr/local/bin/tcllauncher, sources in /usr/local/lib/trackserver/main.tcl.
Also, a global variable called launchdir is set containing the “launch directory.” In the above example, /usr/local/lib/trackserver.
Tcllauncher doesn’t change your directory behind your back, so wherever you are at when you run it, you’re still in that directory.
But a lot of times you want to go to your application directory, so you can just
cd $::launchdir
Then you can source in all of your various files and stuff like that.
If you are going to fork off children, exec them, or whatever, you should
probably become your own process group so hopefully your children might
inherit your signals and Do The Right Thing.
Lots of apps write a file with the server’s process ID in it. Upon relaunch,
the program can come along and look in its own pid file to see if it’s already
alive or not, and also to potentially kill it.
Our pidfile support is a studied Tcl-based copy of BSD’s pidfile C library.
::tcllauncher::pidfile_open
Given an optional path to a directory and optional permissions, pidfile_open opens (or creates) a file specified by the path and locks it with TclX’s interface to the flock system call. If the file cannot be locked, the PID of an already running daemon is returned. Otherwise zero is returned and you’ve got the lock. You can now call pidfile_write to get your pid into the lock file. This function does not write your process’ PID into the file, so it can be used before forking if needed.::tcllauncher::pidfile_write
Writes your pid into the pid file previously opened by pidfile_open.::tcllauncher::pidfile_close
Close a pidfile. It should be used after your daemon forks to start a child process.::tcllauncher::pidfile_remove
Close and remove a pidfile.
set pid [::tcllauncher::pidfile_open "/var/run/daemon.pid 0600] if {$pid > 0} {puts stderr “pid $pid already has the lock”
exit 1
}
Sometimes you want your program to spawn itself off into the background in
a way that when you logout it doesn’t kill the process, etc.
To daemonize a tcllauncher app,
::tcllauncher::daemonizeBy default this forks off a child and exits the parent. In the child, it
changes the current directory to /, and redirects stdin, stdout and stderr
to/from /dev/null.
Optional arguments are -noclose, which prevents the closing and redirecting
of stdin, stdout and stderr, and -nochdir, which prevents the changing of
the working dir to /.
This is a rough copy of BSD 4.4’s daemon library routine.
.h1 user and group management
If a program needs to be run as a certain use, it can invoke
::tcllauncher::require_user fred
This requires the program to either be run as fred or as root or something
like that, a user that has permissions to become fred.
If the program is running as user fred or can change the user id (suid) to
fred, it continues, else it aborts.
::tcllauncher::require_group does for groups what require_user does for
users.
Note that if you require user first then require group, the process may have
lost the privileges necessary to change groups after changing users. Either
require the group ID first or use ::tcllauncher::require_user_and_group
to do both.