[Tfug] Properly terminating a shell script after using X Windows esadyna3

Bexley Hall bexley401 at yahoo.com
Mon Jan 28 11:15:22 MST 2013


Hi John,

On 1/28/2013 2:03 AM, John Gruenenfelder wrote:
> On Sat, Jan 26, 2013 at 11:54 AM, Bexley Hall<bexley401 at yahoo.com>  wrote:
>>> So... I guess what I'm getting at is that I, personally, could use any
>>> number of methods to make sure the script exits on *my* computer.  I
>>> would like to make this useful for other people, however, and the
>>> fewer changes they are required to make to their X startup procedure,
>>> the better.  That is why I am hoping to find, if possible, some fairly
>>> general method of exiting the script when the user logs out so that it
>>
>> -----------------------------------------------------^^^^^^^
>>
>> "Logs out" or "quits his X session"?
>
> In this case, either.

<grin>  I figured as much but wanted to draw attention to this.

>>> I suppose, failing that, I could put together an instructions file
>>> that includes a list of numerous methods of both starting and stopping
>>> the script and then let the user chose the methods that best match how
>>> their system is configured.  That's still far more manual a process
>>> than I was hoping for, however.
>>
>> You either have to tell "something" (see my previous post)
>> that you are running (and have that "something" kill you
>> when X dies) *or* you have to sense when that "something"
>> (X) dies and kill yourself!
>
> The problem is knowing just what to register the script with.  There
> are numerous session managers available for X and a user could be
> using any one of them, or possibly even none.

Exactly!  There is nothing that prevents the user from "manually"
running it from within an xterm -- presumably opting to move it
to the background (else dedicating that xterm shell to it!).

> Using this method would
> probably mean just picking one, say gnome-session, and informing users
> that the self-termination only works if they are using Gnome.  This
> also assumes that the Gnome session manager is easy enough to use from
> the command line and without all the gnome libraries.

You already *know* this isn't going to be "acceptable" to someone,
somewhere!  :>

I tried to illustrate this in my example(s).  Bottom line being the
only way to ensure it is "taken down" when X quits is to wrap X
in "something" and have that something do this on your behalf.

But, it would be narcissistic for *that* "app" to be the sole reason
for this wrapper.  I.e., the wrapper would want to be generalized
to handle "setup" and "teardown" scripts for X, in general...

[I favor using xdm with xsm for X as all of these hooks are
already in place]

> On the other hand, attempting to *sense* when to exit would be the
> more general solution, though likely harder to make 100% reliable.  I
> originally mentioned that the script could perform checks to see if X
> was still running and/or if the running user was still logged in and
> act accordingly.  This could still get complicated easily, but I think
> I could add a configuration option that names the X process.  As you
> also noted, 'X' is often a link to the actual X server.  More than
> that, it is often even a hard link.  I know on my system, and
> presumably most all Debian systems, the process as found with 'ps' is
> called simply 'X'.  That should make a good default and be easy to
> check for (I think).

Forget X!  The problem you are trying to solve is to give the "normal"
child process behavior to a background-ed process (I've worded this
poorly  :<  It's too early in the morning!)

I.e., what you want is for the demise of X -- as an ANCESTOR of your
script -- to bring about the orderly termination of your script as
well!  Regardless of how (*under* X) your script was started.

[Note this assumes you aren't going the "service oriented" direction
I mentioned previously]

So, I'm suggesting your script just watches to see when it's parent
dies!  And, count on X (or whatever agent acting on X's behalf) to
kill that process as a consequence of it's (X's) termination.

E.g., if X dies, whatever invoked your script also dies (so your
script just watches for the invoker's demise).  Similarly, if
the user has *manually* invoked your script from some shell, then
when *that* shell dies, you die as well!

[There are cases where this would not be desirable.  We'll choose
to ignore those!  :> ]

So, what your script does is watch for it's PPID to die!  Then,
accompanies it!!

You can do this by noting the PPID when you are invoked (PPID=$$).
Then, explicitly watch to verify that process is still active
(e.g., ps -p $PPID).

But, for long running processes, this creates a hazzard -- given
enough time, the pid can end up being reused.  So, you'd have
to verify that the process having that $PPID was *actually* the
process that started you.

[Similarly, if your process sleeps for a long time, your parent can
die and pids wrap around before your wake up.  So, it is conceivable
(though not likely!) that you will never "see" it as being "dead"]

I *think* you can exploit a hack in how PPIDs are handled to
implement a "glitch catcher" of sorts.  (i.e., to see the death
of your parent even if it's pid is reused faster than the blink
of your eye).

Watch for the PPID of your *current* process to become '1'
(i.e., that of init(1)).  Your processs *must* (always) have
a declared "parent".  So, the case where the parent dies
before the child is handled by the PPID being set to that of
init (since init ALWAYS is running).

I'm at a Windows machine, presently, so I can't verify any of this
(As I so dreaded hearing:  "exercise left for the student"  :> )

> I suppose the default settings would be to terminate if the user logs
> out or if the X process dies.  As long as this is configurable, I hope
> it will be general enough to work for most people.  Since the job of
> the script is to first gather, from the Net, the data needed for the
> current wallpaper and then to generate that wallpaper once every five
> minutes, it makes sense to terminate if either X or the user goes
> away.

Again, I would move the "gathering" activity to a service that
runs "always" -- though possibly with different update frequencies
so it's not wasting CPU needlessly when no one is logged in (yet
always has some "reasonably current" images on hand).

[I am obsessed with "services"... I try to make everything
resemble a service in my designs!]

> That said, I am also trying to make the script more functional and
> modular.  The user should be able to pick the mode of operation, such
> as fetch the data or generate a single wallpaper, in additional to the
> standard all-in-one timed mode.  Obviously, for those modes which will
> only last a matter of seconds it no longer becomes necessary to
> self-terminate early.
>
> Another question would be how to best handle this status checking.
> Currently, the delay between runs in simply handled by running 'sleep'
> with a default time of five minutes.  It is entirely possible that in
> a five minute span a user could log out of an X session, cause X to
> restart, and then log back in.

Exactly.  As I outlined above with PPID wrapping/reuse.

> I have taken precautions to prevent
> the script from executing twice at the same time.

If service is already running, new invocation just gracefully
exits.

> I think this is
> sufficient since when instructed to display a new wallpaper (via
> Gnome), it does this by poking at the Gnome registry and this does not
> seem to rely on a specific X connection, but rather just the presence
> and accessibility of X.  Should this cause trouble again in the
> future, I can probably make the delay time a multiple of some smaller
> value and then perform the checks every time that common factor
> expires.
>
>> I suspect somewhere there is a little scriptlet that already
>> does all of this -- to varying degrees of pedantic-ness.
>
> It wouldn't surprise me, though I haven't had much luck finding
> anything via Google.  If you're not careful in your query you end up
> getting a lot of results where 'x' is used as a script variable or
> scripts that use the "set -x" command.  Not quite the same thing...

Try looking at *current* PPID and see if that works (I'm curious,
now).  E.g., write a test script that checks it's current pid,
writes that to stdout (wherever) then sleeps and repeats.  Then
you could invoke this from a shell with it's stdout redirected
to a file (or something) and terminate the *invoking* shell.
Notice if the reported PPID changes correspondingly.  If so,
modify test script to exit when it sees this change.

Finally, repeat the exercise and watch the process list *as*
you terminate the invokING shell -- the invokED script should
die within one sleep interval of the time the invokING shell's
death.

> Anyway, these emails have given me some ideas to think about.  My most
> sought after solution is one which does not require any root-level
> modifications on the user's system.

Understood.

> I can see where that might be
> desirable from an admin point of view, but I think that the audience
> for this particular wallpaper "system" is small enough that it is best
> to focus on its use user by user and not system-wide.

IMO, it's desirable for the costs of a particular "service"
(application) to be born (insofar as possible) by that service
itself.  The developer (of the service) knows far more about it
than the *consumer* so it makes for more reliable implementations
when the developer bears the cost of "getting things right"
(instead of hoping the user/consumer does!)

Gotta go check my cooler repairs (poor cooler design allows water to
adhere to underside of cooler and follow bottom of cooler to the
downdraft ductwork -- leading to water *in* ducts.  Haven't met
a MechE that had an ounce of common sense!!  :< )

HTH,
--don




More information about the tfug mailing list