The Linux distillery
Bringing the world of Linux to you, David cuts through the tech and shows you how it works and how to use it, in terms that apply to any distro. RSS
Technology news and Jobs arrow The Linux distillery arrow Real world Linux programming
Real world Linux programming E-mail
by David M Williams   
Tuesday, 11 December 2007
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.


/*
 * 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 (' ');
}

Please enable JavaScript in your browser to post your comment!


Get stories like this delivered daily - FREE - subscribe now


 
< Next story in category   Previous story in the category >
iTWire user statistics Visitors last 30 days
Suscribers
904,266
13,751
#1 independent technology news advertise here
  •   *  
  • Search
  • AdvSeach
  • Login
  • Events
  • FreeStuff
Subscribe to our free e-newsletter