• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 952
  • Last Modified:

return to calling cgi in bash script

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

  • 3
  • 3
1 Solution
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

Owen_ParkerAuthor Commented:
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!  :)
So, did removing the outputting of the unwanted content-type header and adding the colon fix the problem?
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Owen_ParkerAuthor Commented:
No, sorry, I thought that was implied.  Same basic end result.  The echoing of the string "Location: and the URL to the screen.
Owen_ParkerAuthor Commented:
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...
You're welcome. :)
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now