Introduction

In Part 2 of this "Rabbit Trail", we added a new feature to this new command-line, menu-driven tool we are developing. This actvity is on a parallel track with our main journey of exploring Web Clients / Web Services.

The more we enhance this tool, the more helpful to us with our main project-work.

Another way of looking at this is that it gives us motivation to explore Bash shell scripting that can be applied to many situations.

This article's main point today is job control and graceful shutdown of the database server when hitting CTRL-C on the keyboard.

More Database Features

Our first two functions of the script (Parts 1 and 2 articles) was to be able to:

start / stop the MySQL database server

view a list of databases

In the time between Part 2 and this article, I've added the ability to:

create a new database

select from the list of databases

drop a database

show tables within that selected databases

drop a table

show all data in the selected table

I am not going to discuss the details of the above. The new items all follow along the same lines and use very similar commands and script structure as the one we throughly discussed in Part 2.

You should be able to use Part 2's information to compare against the new script portions.

If you compare the above version with the latest script from article Part 2, you'll notice that the start and stop has turned into functions. And everywhere there used to be an exit, there is now an _exit. The new _exitfunction calls the new shutdown function.

Adding Graceful Database Shutdown

At the moment, if we use the script as it is intended, and only exit it via the "e" (exit selection), then we're good. The database will shutdown gracefully.

However, I for one, hardly ever do that. I'm impatient. So I would rather just hit CTRL-C.

If you try that now when running this script, and you re-start MySQL later, you may find that the output says something about having to recover from a crash.

So, let's not leave things this way.

Job Control

Before we get to the new parts of the script that will handle CTRL-C, though, let's discuss and try out some job control in Cygwin window (no scripts). And to understand job control, you need some understanding of processes.

Let's open a new Cygwin window, and make sure it is the ONLY Cygwin window running.

Cygwin is a sort-of attempt at a Linux / Unix environment. It has the concept of shells. A shell is what allows you to enter commands, and view output, etc. A shell will also run scripts. A shell can (and does) spawn new shells (child or sub-shells).

Every shell, sub-shell, etc, is a separately running process. That means it has a PID. (Process ID).

And, it belongs to a parent. Thus, it has its PPID (Parent Process ID).

In the above window screenshot, we entered a ps -ef . It is a long printout of all Cygwin processes that are running. In this case, there are three.

There is a hierachy. You can follow that if you trace through the PIDs and PPIDs.

Here is the path from parents to children, for the above example:

/usr/bin/mintty ---> /usr/bin/bash ---> /usr/bin/ps

Or, if we do the same thing, but using the process IDs:

15204 ---> 20848 ---> 16740

The mintty is the actual window process. (Later) we can add color; we can change font; we can change the window size; all of that is done with mintty.

The bash shell is what allows us to communicate (enter commands; view output).

The ps command is what gave us the list of running Cygwin processes.

Foreground and Background Processes

A foreground process is any command or script that is tied and in control of the window's input and ouput ( I am being a bit fast and loose here with the definitions).

So far, everything we have done in Parts 1, 2, and this one, are all foreground processes, with one exception. In the script, where we start mysqld server, we turned it into a background process.

$(mysqld --console) &

That ampersand turns it into a background process. And that is the reason we were able to continue with our menu-driven script. By the way, the $(...) is probably not necessary for our purposes. More on that later.

Disowning

Remember I mentioned the idea that child processes have a parent process. There's also the idea that a child process can be disowned by the parent. Sometimes that is a good thing. It means it can keep running even if the parent ends.

Let's see if we can demonstrate all that we've discussed so far.

In the above window, we saw three processes. Now let's start up MySQL database server, and then we will do another process id listing. We will start the mysqld in the background, and that means we can keep control of the Cygwin window. We will wait until mysqld has finished the start up output, then we just hit <ENTER> to get back our prompt.

Above is prior to the start. Then we hit <ENTER> and wait:

Once we see output has ceased and MySQL is up, we hit <ENTER> again, and do that ps -ef command again. We should see the three processes as before (mintty, bash, ps), but we should also see a new one, the mysqld.

So, mysqld is running, however we have control of the window and the prompt is responsive to us.

Notice that the mintty process has a parent ID (PPID) of "1".

Notice that the mysqld process has a parent ID that is the (mintty --> bash)'s ID. Mintty is the parent (or grandparent).

Now, let's open another Cygwin window, and we are going to monitor the mysqld process. And then while we are monitoring it, we will exit out of the first window (that started everything).

What we should see is that mysqld process will change - its parent ID will go from 684, to 1.

What happens when we close or exit the first window, is that the mintty / bash pair for that window end, but mysqld continues on.

Without too much explanation, the above command scriptlet is a while-loop, with a delay of 5 seconds in every iteration, and it takes the output of the long ps listing, and just displays the process we're interested in. Here we go:

As expected, when we exit from the original parent window that started the MySQL server, the monitoring window shows that its parent ID changes. And that it continues to run.

Furthermore, if we exit the monitor window, we would normally assume that all Cygwin processes are done. But we open the Windows Task Manager, and we see one bash process:

If we open a new Cygwin window and do another process-listing, we will see the running MySQL server.

Time to Add To Script

I think we are ready.

A key point here: job control (what we just did) is DISABLED (usually) by default, when Cygwin (Bash) is running a script (aka batch-mode as opposed to interactive-mode).

In order for us to have our script behave like what we've been doing, we must make sure we have job control enabled.

#!/usr/bin/bash
set -m

Right at the start of the script, we add the set -m . That enables job control.

#!/usr/bin/bash
set -m
trap _trap_ctrl_c INT;

Then, we add the ability to catch (trap) when a user hits the CTRL-C on the keyboard.

The above statement means we have a new function that will run in the case of CTRL-C. Here is the new function: