/* Copyright (c) 1991 by Oracle Corporation */
/*
   NAME
     osh.c - <one-line expansion of the name>
   DESCRIPTION
     <short description of component this file declares/defines>
   PUBLIC FUNCTION(S)
     <list of external functions declared/defined - with one-line descriptions>
   PRIVATE FUNCTION(S)
     <list of static functions defined in .c file - with one-line descriptions>
   RETURNS
     <function return values, for .c file with single function>
   NOTES
     <other useful comments, qualifications, etc.>
   MODIFIED   (MM/DD/YY)
    kaghevli   02/22/93 -  Creation 
*/
#ifdef RCSID
static char *RCSid = 
   "$Header: osh.c,v 1.1 93/02/22 23:33:07 KAGHEVLI: Exp $ osh.c Copyr (c) 1986 Oracle";
#endif  /* RCSID */

/*
** Copyright (c) 1986  by Oracle Corporation
**
** osh - Routine to modify a user's ulimit
**
** Under UNIX the largest negating factor for large database is
** the process's "ulimit" parameter. Currently this only can be reset
** by the "super-user". This program needs to be run with the ownership
** of root and the "set uid" bit 'on'. The recommended mode of this program
** 4711 (-rws--x--x) which only allows this program to be "executed" but
** not copied. It raises the ulimit to a theoretical maximum and then
** "exec's" the shell specified in its name. "osh" will exec "sh", "ocsh"
** will exec "csh", etc. If the program is run by anybody other than the
** super-user, it automatically resets the program's uid to that of the
** person executing "osh" so as not to leave the user with unauthorized
** privelages.
**
** PLEASE NOTE: Any program with a set uid bit set is a POTENTIAL security
**              problem and needs to be carefully controlled.
**
** Written:
**	11/01/84 Abbajay
** Modified:
**      07/20/86 Abbajay  - Added optional "SHELL" variable lookup.
**      02/22/89 Andres   - Added -l flag to print current ulimit.
**      02/22/92 jtellez  - modified for sequent to change scheduling.
**
** Compile: cc -O osh.c -o osh
** Compile for Sequent: cc -O osh.c -o osh -lseq
** Install: with set uid root (4711)
*/

#include <stdio.h>
#include <errno.h>

#define NEWLIMIT 2113674		/* define newlimit for upping ulimit */
#define DEFAULT_SHELL "/bin/sh"		/* define deault shell */

#ifdef _SEQUENT_			/* Sequent only includes & defines */

# include <sys/time.h>
# include <sys/resource.h>
# define USAGE "osh [-l] [-a] [-p] \n -l Prints the current ulimit.\n -a Disables Priority Aging.\n -p Disables Preemption.\n"

#else
# define USAGE "osh [-l]\n"
#endif /* _SEQUENT_ */

char error_buffer[512];

char *getenv();

main(argc, argv, envp)
int argc;
char **argv;
char **envp;

{
  register char *cmd;			/* command to execute */
  register long newlimit=NEWLIMIT;	/* define newlimit for upping ulimit */
  char *shell;
  register int i;
  char *nargv[4096];
  long ulimit(), oldlimit;
  char c, *op = "lap";
  extern char *optarg;
  extern int optind;


  while ((c = getopt(argc, argv, op)) != -1) 
     switch (c) {
     case 'l':
	 if ( (oldlimit = ulimit(1)) == -1)
	 {
	     sprintf(error_buffer,"%s: Couldn't get process ulimit.\n",argv[0]);
	     perror(error_buffer);
	     exit(-1);
	 }
	 else
	 {
	     printf("%d\n",oldlimit);
	     exit(0);
	 }
	 break;
#ifdef _SEQUENT_
     case 'a':
	     if (proc_ctl(PROC_PRIOAGE, 0, 0)) {
		 sprintf(error_buffer,
			 "%s: Couldn't disable priority aging.\n",argv[0]);
		 perror(error_buffer);
		 exit(-1);
             }
	 break;
     case 'p':
	     if (proc_ctl(PROC_NOPREEMPT, 0, 1)) {
		 sprintf(error_buffer,
			 "%s: Couldn't disable process preemption.\n",argv[0]);
		 perror(error_buffer);
		 exit(-1);
             }
	 break;
#endif /* _SEQUENT_ */
     default:
         sprintf(error_buffer,"%s\n", USAGE);
	 perror(error_buffer);
         exit(1);
         break;
  }
  
  if(ulimit(2, newlimit) == -1)
  {
     if (errno == EPERM)
     {
	 (void) fprintf(stderr,
			"%s: Can't raise ulimit. The mode of %s should be 4711 and owned by root.\n",
		 argv[0], argv[0]);
     }
     else
	 perror(argv[0]);
     exit(-1);
  }
  if(setuid(getuid()))			/* set uid back to original */
  {
     perror(argv[0]);
     exit(-1);
  }
  
  if (argc == optind)
  {
     shell = nargv[0] = (nargv[0] = getenv("SHELL")) ? nargv[0] : DEFAULT_SHELL;
     nargv[1] = NULL;
     if (execve(shell, nargv, envp))
     {
         perror(argv[0]);
         exit(-1);
     }
  }
  else
  {
     i=optind;
     while (argv[i] != NULL)  {
       nargv[i-optind] = argv[i];
       i++;
     }
     nargv[i]=NULL;
     if (execvp(nargv[0], nargv))
     {
        if (errno != ENOTTY)		/* abort on any other error */
        {
          perror(argv[0]);
          exit(-1);
        }
     }
  }
  exit(0);
}
				/* END PROGRAM */
