return to calling cgi in bash script

Posted on 2013-11-01
Last Modified: 2013-12-25
i probably can't find this explained anywhere because it's ridiculously easy or I am not supposed to do this in the first place, however, I need to accomplish some form of this.

Throwing together a gui to allow our installers to do very basic linux functions on a little linux server we are using for a gateway.  The linux server is very barebones so I get to learn some bash.

In this example, I am popping a simple webform to get the date month and year and will run a simple bash script to change the date and then load up the main menu again.  All is fine up until I try and load up the URL I want.  I know many ways to do this in many languages, but bash isn't behaving.  I probably have a space somewhere I shouldn't or some such silliness, but I am willing to be humiliated to move on  :)

There is zero chance of security issues here so no scolding on the sudo stuff.

setdate cgi - trimmed down as much as possible:

echo "Content-type: text/html"
echo ""
echo "<html><head><title>Set the System Date"
echo "</title></head>"
echo "<body>"
echo "<FORM ACTION=dosetdate.cgi METHOD=POST>"
echo "Enter the date to set:"
echo "<select name=day size=1>"
echo "   <option value=1>1</option>"
echo "   <option value=2>2</option>"
echo "   <option value=3>3</option>"
echo "</select>"
echo "<select name=month size=1>"
echo "   <option value=JAN>JAN</option>"
echo "   <option value=FEB>FEB</option>"
echo "</select>"
echo "<select name=year size=1>"
echo "   <option value=2013>2013</option>"
echo "   <option value=2014>2014</option>"
echo "</select>"
echo "<input type=submit value=Submit>"
echo "</form>"
echo "</body></html>"

Open in new window

dosetdate.cgi - most of this is copy/pasted from a well known example online

echo "Content-type: text/html"

# (internal) routine to store POST data
function cgi_get_POST_vars()
    # check content type
    # FIXME: not sure if we could handle uploads with this..
    [ "${CONTENT_TYPE}" != "application/x-www-form-urlencoded" ] && \
    #echo "bash.cgi warning: you should probably use MIME type "\
    #     "application/x-www-form-urlencoded!" 1>&2
    # save POST variables (only first time this is called)
    [ -z "$QUERY_STRING_POST" \
      -a "$REQUEST_METHOD" = "POST" -a ! -z "$CONTENT_LENGTH" ] && \
    # prevent shell execution
    local t
    t=${QUERY_STRING_POST//%60//} # %60 = `

# (internal) routine to decode urlencoded strings
function cgi_decodevar()
    [ $# -ne 1 ] && return
    local v t h
    # replace all + with whitespace and append %%
    t="${1//+/ }%%"
    while [ ${#t} -gt 0 -a "${t}" != "%" ]; do
    v="${v}${t%%\%*}" # digest up to the first %
    t="${t#*%}"       # remove digested part
    # decode if there is anything to decode and if not at end of string
    if [ ${#t} -gt 0 -a "${t}" != "%" ]; then
        h=${t:0:2} # save first two chars
        t="${t:2}" # remove these
        v="${v}"`echo -e \\\\x${h}` # convert hex to special char
    # return decoded string
    echo "${v}"

# routine to get variables from http requests
# usage: cgi_getvars method varname1 [.. varnameN]
# method is either GET or POST or BOTH
# the magic varible name ALL gets everything
function cgi_getvars()
    [ $# -lt 2 ] && return
    local q p k v s
    # prevent shell execution
    t=${QUERY_STRING//%60//} # %60 = `
    # get query
    case $1 in
        [ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
        [ ! -z "${QUERY_STRING_POST}" ] && q="${QUERY_STRING_POST}&"
        [ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
        [ ! -z "${QUERY_STRING_POST}" ] && q="${q}${QUERY_STRING_POST}&"
    s=" $* "
    # parse the query data
    while [ ! -z "$q" ]; do
    p="${q%%&*}"  # get first part of query string
    k="${p%%=*}"  # get the key (variable name) from it
    v="${p#*=}"   # get the value from it
    q="${q#$p&*}" # strip first part from query string
    # decode and evaluate var if requested
    [ "$1" = "ALL" -o "${s/ $k /}" != "$s" ] && \
        eval "$k=\"`cgi_decodevar \"$v\"`\""

# register all GET and POST variables
cgi_getvars BOTH ALL

datestring="$day $month $year 01:00:00"

/usr/bin/sudo /bin/su -c "/bin/date -s '$datestring' >/dev/null 2>&1"


echo "Location $url"

Open in new window

Now I am very aware that the final line could not possibly work.  However, I have not been able to come up with anything else.  In a perl script, I would simply print this and it would open the url specified.  How can this be accomplished in bash?

Thanks in advance

Question by:Owen_Parker
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
LVL 28

Accepted Solution

FishMonger earned 500 total points
ID: 39618753
I don't do bash scripting but, I'd start by removing the output of the Content-Type on line 2.

Also, I believe you need a colon after Location.
echo "Location: $url"

Open in new window

This might be a silly question but, since it sounds like you already know how to do this in Perl, why not use it instead of bash?  You'd be able to reduce the dosetdate.cgi script by about 80%.

Here's the minimalist version of the perl script.

use strict;
use warnings;
use CGI;

my $cgi        = CGI->new;
my %param      = $cgi->Vars;
my $datestring = "$param{day} $param{month} $param{year} 01:00:00";
my $url        = "";

# there are multiple ways to run this command, and this may not be the best
system( qq(/usr/bin/sudo /bin/su -c "/bin/date -s '$datestring' >/dev/null 2>&1") );

print $cgi->redirect($url);

Open in new window


Author Comment

ID: 39618778
Hi FishMonger

You are right on the colon after location.  That was a typo somehow.  As for doing this in bash versus perl, I had inherited this little project and the device it is running on has only a 1 GB flash for storage and I was told it was a very stripped down version of OpenSuse and not much could be done on it.  When asked to add some sort of interface, it was suggested it be done in bash due to the limitations.  So, I did it all in bash.  This and one other similar function is all that is left.  And this one little part is all that is left of those.  However, before i started answering you, I asked myself when was the last time I saw ANY linux install that didn't have perl installed.  So I type perl -v and lo and behold, perl is installed after all.  LOL

Learned a couple lessons there I guess.

However, now there is this issue with bash, and I must resolve it.  Knowing I can finish this in 15 minutes now is reassuring.  but I'm not very good at dealing with an unresolved issue, other than to find the solution!  

I thank you for asking the very obvious question and leading me to spend the 1.3 seconds checking something i should have checked a week ago!  :)
LVL 28

Expert Comment

ID: 39618864
So, did removing the outputting of the unwanted content-type header and adding the colon fix the problem?
Give Your Engineering Team a Productivity Boost

Learn why container technology is so powerful and how it can provide your team with productivity gains and other benefits.


Author Comment

ID: 39619169
No, sorry, I thought that was implied.  Same basic end result.  The echoing of the string "Location: and the URL to the screen.

Author Closing Comment

ID: 39620478
I never did receive the solution to my query, but since I could do it in Perl, I did.  I will see about getting the solution from my engineer Monday and will post it here for future reference if it is resolvable...  Thanks for your input FishMonger...  It was surely helpful...
LVL 28

Expert Comment

ID: 39620489
You're welcome. :)

Featured Post

Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to provide a dynamic RTF document on your website generated with data from your database. For this tutorial you will need Microsoft Word or WordPad, WhizBase and Microsoft Access. In this tutorial I will show …
I hope you'll find this tutorial useful and interesting. So let's try to extend Tcl with a new package.  For anyone more deeply interested please check out the book "Practical Programming in Tcl and Tk". It's really one of the best written books abo…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to count occurrences of each item in an array.

628 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question