Warning this article may contain opinions of the author that you and iTWire don't agree with.
Visit the last page to have your say in our forum.

No. 1 Story

Telstra adds one million mobile services, but Sensis plummets

Telstra has revealed the addition of almost one million new mobile services in the six months to December 2011, but Sensis revenues plummeted 24 percent in 12 months.

read more

Real world Linux programming

Opinion and Analysis

Finally, here is menu.c, the main program file for the menu application. This reads in the menu configuration file, displays a text-based menu on screen, prompts the user for input, then performs the appropriate command with privilege elevation if required.


free hit counter
/*
 * Simple menu program
 *
 *  David M. Williams
*/

#include "menu.h"

// ----------------------------------------------------------------------------
int main (int argc, char **argv)
{
 char  *username;
 char  *password;
 int  access = -1;
 ScriptTree theMenu = NULL;

#ifdef DISABLE_INTERRUPTS
 signal (SIGINT, SIG_IGN);
#endif

 username = (char *) malloc (sizeof (char) * 50);
 password = (char *) malloc (sizeof (char) * 10);

// Ask for a login

 login (username, password);

// Verify username and password, getting access level

 if (verify (username, password, &access) < 0)
  noAccess (username);
 else
 {

// Generate a list of menu options

  buildMenu (access, &theMenu);

// Repeatedly display menu and process input

  DoMenu (username, theMenu, 0);

// Tidy up

 }

 printf ("\nBye.\n");

 free (username);
 free (password);
 Destroy (theMenu);
}

// ----------------------------------------------------------------------------
void clrscrn ()
{
#ifdef CLEAR_SCREEN
 system ("/bin/clear");
#endif
}

// ----------------------------------------------------------------------------
void login (char *username, char *password)
{
 char tempPassword [10];

 clrscrn ();

#ifdef BANNER
 if (strlen (BANNER) > 0)
  puts (BANNER);
#endif

 printf ("   Login: ");
 scanf ("%s", username);

#ifdef HIDE_PASSWORD
 strcpy (tempPassword, getpass ("Password: "));
#else
 printf ("Password: ");
 scanf ("%s", tempPassword);
#endif

 log ("Login attempt by %s\t%s\n", username, tempPassword);

 strcpy (password, crypt (tempPassword, username));
}

// ----------------------------------------------------------------------------
void noAccess (char *username)
{
 clrscrn ();
 printf ("%s, you do not have permission to access this system\n"
  "or your password was wrong.\n", username);
}

// ----------------------------------------------------------------------------
int verify (char *username, char *password, int *access)
{
 FILE *fp;
 int Found = 0;
 char line [80];
 char tempUser [50];
 char tempPass [10];
 int tempAccess;

 *access = -1;

 if ((fp = fopen (USERLIST, "r")) > 0)
 {
  while ((!Found) && (!feof (fp)))
  {
   fgets (line, 80, fp);
   if ((line [0] != '\n') && (line [0] != '#'))
   {
    sscanf (line, "%s%s%d", tempUser, tempPass,
     &tempAccess);

    if ((strcmp (tempUser, username) == 0) &&
     (strcmp (tempPass, password) == 0))
    {
     Found = 1;
     *access = tempAccess;
    }
   }
  }

  fclose (fp);
 }
 else
  log ("Cannot open %s\n", USERLIST);

 log ("%s has an access level of %d\n", username, *access);

 return *access;
}

// ----------------------------------------------------------------------------
void buildMenu (int access, ScriptTree *theMenu)
{
 FILE  *fp;
 char  *line;
 char  *line2;
 char  *scriptName;
 char  *LineType;
 int  userLevel;
 int  useSudo;
 ScriptTree subMenu;

 line = (char *) malloc (sizeof (char) * 80);
 line2 = (char *) malloc (sizeof (char) * 80);
 scriptName = (char *) malloc (sizeof (char) * 80);
 LineType = (char *) malloc (sizeof (char) * 10);

 subMenu = *theMenu;

 if ((fp = fopen (MENULIST, "r")) > 0)
 {
  while (!feof (fp))
  {
   line [0] = '#';
   while (((line [0] == '\n') || (line [0] == '#')) &&
     (!feof (fp)))
    fgets (line, 80, fp);

   line2 [0] = '#';
   while (((line2 [0] == '\n') || (line2 [0] == '#')) &&
     (!feof (fp)))
    fgets (line2, 80, fp);

   if (!feof (fp))
   {
    sscanf (line, "%s", LineType);

    if (strcmp (LineType, "Menu") == 0)
    {
     sscanf (line, "%s%d", LineType,
      &userLevel);
     if (userLevel <= access)
      subMenu = AddMenu
       (theMenu, line2);
    }
    else if (strcmp (LineType, "Submenu") == 0)
    {
     sscanf (line, "%s%d", LineType,
      &userLevel);
     if (userLevel <= access)
      subMenu = AddMenu
       (&subMenu, line2);
    }
    else if (strcmp (LineType, "Option") == 0)
    {
     sscanf (line, "%s%d%d%s", LineType,
      &userLevel, &useSudo,
      scriptName);
     if (userLevel <= access)
      AddNode (&subMenu, line2,
       scriptName, useSudo);
    }
   }
  }

  fclose (fp);
 }
 else
  log ("Cannot open %s\n", MENULIST);

#ifdef DEBUGGING
 DumpMenu (0, *theMenu);
 exit (0);
#endif

 free (line);
 free (line2);
 free (scriptName);
 free (LineType);
}

// ----------------------------------------------------------------------------
void DoMenu (char *username, ScriptTree theMenu, int InSub)
{
 int  DoExit = 0;
 int  userChoice;
 int  MenuItems;

 while (!DoExit)
 {

// Display the menu

  MenuItems = DisplayMenu (theMenu, InSub);

// Get input

  userChoice = getChoice (MenuItems);

// Process command

  if (userChoice == 0)
   DoExit = 1;
  else
   ProcessChoice (userChoice, theMenu, username, InSub);
 }
}

// ----------------------------------------------------------------------------
ScriptTree AddMenu (ScriptTree *theMenu, char *ItemText)
{
// Make a new node
 ScriptTree aNode;

 aNode = (ScriptTree) malloc (sizeof (ScriptNode));
 strcpy (aNode->MenuText, ItemText);
 strcpy (aNode->ScriptName, "");
 aNode->Next = NULL;
 aNode->Submenu = NULL;

// Find the last node in the list and set its next pointer to this node.

 if (*theMenu == NULL)
  *theMenu = aNode;
 else
 {
  ScriptTree iterator = *theMenu;

  while (iterator->Submenu != NULL)
   iterator = (void *) iterator->Submenu;

  iterator->Submenu = aNode;
 }

 return aNode;
}

// ----------------------------------------------------------------------------
void AddNode (ScriptTree *theMenu, char *ItemText,
        char *ScriptCommand, int UseSudo)
{
// Make a new node
 ScriptTree aNode;

 aNode = (ScriptTree) malloc (sizeof (ScriptNode));
 strcpy (aNode->MenuText, ItemText);
 strcpy (aNode->ScriptName, ScriptCommand);
 aNode->RunAsRoot = UseSudo;
 aNode->Next = NULL;
 aNode->Submenu = NULL;

// Find the last node in the list and set its next pointer to this node.

 if (*theMenu == NULL)
  *theMenu = aNode;
 else
 {
  ScriptTree iterator = *theMenu;

  while (iterator->Next != NULL)
   iterator = (void *) iterator->Next;

  iterator->Next = aNode;
 }
}

// ----------------------------------------------------------------------------
void Destroy (ScriptTree theMenu)
{
 ScriptTree iterator = theMenu;

 if (iterator != NULL)
 {
  Destroy (iterator->Next);
  Destroy (iterator->Submenu);
  free (iterator);
 }
}

// ----------------------------------------------------------------------------
void DoCommand (char *username, char *ScriptName, int UseSudo)
{
 char c = ' ';
 char FullPath [PATH_MAX];

 puts ("\n\n");

 log ("%s is running %s %s sudo\n", username, ScriptName,
  (UseSudo ? "with" : "without"));

 if (strlen (ScriptName) > 0)
 {
  sprintf (FullPath, "%s/%s", SCRIPTSDIR, ScriptName);

  if (fork () == 0)
  {
#ifdef USE_EXECL
   if (UseSudo)
    execl (SUDO, SUDO, FullPath, NULL);
   else
    execl (FullPath, FullPath, NULL);
#else
   if (UseSudo)
   {
    char SudoCmnd [PATH_MAX];
    sprintf (SudoCmnd, "%s %s", SUDO, FullPath);
    system (SudoCmnd);
   }
   else
    system (FullPath);
#endif

   exit (0);
  }
#ifdef USE_EXECL
  else
  {
   int status;
          wait3 (&status, NULL, (struct rusage *) 0);
  }
#endif
 }

// Wait for a key to be pushed

 printf ("\n\n\tPlease press return : ");
 while (c != '\n')
  c = getchar ();
}

// ----------------------------------------------------------------------------
void log (const char *format, ...)
{
#ifdef LOGGING_ENABLED
        va_list args;
        char logmsg [255];
 FILE *fp;
 time_t now;
 char nowtime [30];
 
        va_start (args, format);
        vsprintf (logmsg, format, args);

 if ((fp = fopen (LOGFILE, "a")) > 0)
 {
  time (&now);
  strcpy (nowtime, ctime (&now));
  nowtime [strlen (nowtime) - 1] = '\0';
  fprintf (fp, "%s\t%s", nowtime, logmsg);
  fclose (fp);
 }

        va_end (args);
#endif
}

// ----------------------------------------------------------------------------
int DisplayMenu (ScriptTree theMenu, int InSub)
{
 int   MenuItems = 0;
 ScriptTree iterator;

 clrscrn ();

 if (!InSub)
  puts ("\tAdministrative services main menu");
 else
  printf ("\tAdministative sub-menu\n\t%s", theMenu->MenuText);

 puts ("\n\n");

 if (!InSub)
  puts ("\t0)\tExit the program\n");
 else
  puts ("\t0)\tExit this menu level\n");

 if (theMenu != NULL)
 {
  if (!InSub)
  {
   MenuItems = 1;
   printf ("\t1)\t%s", theMenu->MenuText);
  }

  if (!InSub)
  {
   iterator = (void *) theMenu->Submenu;
   while (iterator != NULL)
   {
    MenuItems++;
    printf ("\t%d)\t%s", MenuItems,
     iterator->MenuText);
    iterator = (void *) iterator->Submenu;
   }
  }
  else
  {
   iterator = (void *) theMenu->Next;
   while (iterator != NULL)
   {
    MenuItems++;
    printf ("\t%d)\t%s", MenuItems,
     iterator->MenuText);
    iterator = (void *) iterator->Next;
   }
  }
 }

 return MenuItems;
}

// ----------------------------------------------------------------------------
int getChoice (int MenuItems)
{
 int userChoice = -1;
 char temp [5];
 char c = ' ';

 do
 {
  printf ("\n\t\tChoice (0-%d) : ", MenuItems);
  scanf ("%s", temp);
  userChoice = atoi (temp);
 } while ((userChoice < 0) || (userChoice > MenuItems));

// Consume all remaining input
 while (c != '\n')
  c = getchar ();

 return userChoice;
}

// ----------------------------------------------------------------------------
void ProcessChoice (int userChoice, ScriptTree theMenu, char *username,
  int InSub)
{
 int  itemNum = 0;
 ScriptTree iterator = theMenu;
 ScriptTree theChoice = NULL;

 if (!InSub)
 {
  if (userChoice == 1)
   theChoice = theMenu;
  else
   itemNum = 1;
 }

 if ((theChoice == NULL) && (!InSub))
 {
  iterator = (void *) theMenu->Submenu;
  while ((iterator != NULL) && (theChoice == NULL))
  {
   itemNum++;
   if (userChoice == itemNum)
    theChoice = iterator;
   else
    iterator = (void *) iterator->Submenu;
  }
 }

 if ((theChoice == NULL) && (InSub))
 {
  iterator = (void *) theMenu->Next;
  while ((iterator != NULL) && (theChoice == NULL))
  {
   itemNum++;
   if (userChoice == itemNum)
    theChoice = iterator;
   else
    iterator = (void *) iterator->Next;
  }
 }

 if (theChoice == NULL)
  puts ("\nInvalid choice.\n");
 else
 {
  if (strcmp (theChoice->ScriptName, "") != 0)
   DoCommand (username, theChoice->ScriptName,
    theChoice->RunAsRoot);
  else
   DoMenu (username, theChoice, 1);
 }
}

// ----------------------------------------------------------------------------
void DumpMenu (int level, ScriptTree theMenu)
{
 ScriptTree iterator;

 if (theMenu != NULL)
 {
  indent (level);
  printf ("%d\t%s", level, theMenu->MenuText);

  level++;
  iterator = (void *) theMenu->Next;
  while (iterator != NULL)
  {
   indent (level);
   printf ("%d\t%s", level, iterator->MenuText);
   iterator = (void *) iterator->Next;
  }
  level--;

  iterator = (void *) theMenu->Submenu;
  while (iterator != NULL)
  {
   DumpMenu (level, iterator);
   iterator = (void *) iterator->Submenu;
  }
 }
}

// ----------------------------------------------------------------------------
void indent (int level)
{
 int i;

 for (i = 0; i < level * 2; i++)
  putchar (' ');
}

Loading comments ...



- sponsored feature -

The Death of Traditional BI: What’s Next?

How to Make Business Discovery Work for Your Business IP PABX BUYING GUIDE

Business Discovery takes its cues from consumer apps. Like Google, it encourages us- ers to hunt for and explore data without worrying about or even noticing the underly- ing technology. Their entire experience is working within an intuitive interface to get real-time, self-service results with only minimal training. ...more