tcllauncher - Tcl application launcher
::tcllauncher::pidfile_open ?filename?
?mode?
::tcllauncher::pidfile_write
::tcllauncher::pidfile_mtime
::tcllauncher::pidfile_close
::tcllauncher::pidfile_remove
::tcllauncher::daemonize ?-noclose?
?-nochdir?
::tcllauncher::require_user userName
::tcllauncher::require_group groupName
::tcllauncher::require_user_and_group userName
groupName
tcllauncher is a way to have Tcl programs run out of
/usr/local/bin under their own name, be installed in one place with their
support files, and provides commands to facilitate server-oriented
application execution.
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:
- All your Tcl programs will show in "ps" as tclsh
- All your Tcl programs 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.
So when "tcllauncher" is installed as
"trackserver" and you run trackserver, what happens
"/usr/local/bin/trackserver" starts up like the Tcl shell,
except that it sources in
"/usr/local/lib/trackserver/main.tcl". Also, a global
variable called launchdir is set containing the "launch
directory," i.e. the directory where main.tcl was loaded from. ( 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
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.
The id command is from the TclX extension.
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 ?filename? ?mode?
- Given an optional path to a pid filename 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.
If path is not specified (empty string),
"/var/run/$::argv0.pid" is used, and if mode is not
specified, 0600 is used.
- ::tcllauncher::pidfile_write
- Writes your pid into the pid file previously opened by
pidfile_open.
- ::tcllauncher::pidfile_mtime
- Return the mtime of the pidfile.
Can be used after a successful or unsuccessful call to
pidfile_open. Considered useful after pidfile_open fails due to another
process holding the lock to examine when the owner process got the
lock.
- ::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
}
::tcllauncher::daemonize
::tcllauncher::pidfile_write
...do work...
::tcllauncher::pidfile_remove
exit
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::daemonize ?-noclose? ?-nochdir?
- By 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".
Specifying -noclose prevents the closing and
redirecting of stdin, stdout and stderr, while -nochdir prevents
the changing of the working dir to "/"
This is a rough copy of BSD 4.4's daemon library
routine.
If a program needs to be run as a certain use, it can invoke
- ::tcllauncher::require_user userName
- This requires the program to either be run as fred or as root or something
like that, by 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.
This means if the superuser invokes the program, it will
change user to the correct user. If the correct user invokes the
program, it will correctly do nothing and proceed. Handy.
- ::tcllauncher::require_group groupName
- does for groups what require_user does for users.
- ::tcllauncher::require_user_and_group userName
groupName
- combines changing the group and user into a single procedure.
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.
background, daemon, daemonize, tcllauncher
Copyright (c) 2007-2014 FlightAware LLC (BSD Liscense)