/************************************************************************/
/* hsh version 0.01 by Arny - cs6171@scitsc.wlv.ac.uk			*/
/* This really isnt completely ready yet, but it should compile with	*/
/* ansi compatible compilers (such as gcc) under Linux and SunOS.	*/
/* E-mail me if you have a copy of this and I will notify you when I've	*/
/* tidied up all the loose ends (I might put something in to get the	*/
/* zombies, displayfile() is pretty crude and may not work, etc).	*/
/* (c) 1994 Arny - I accept no responsiblity for anything this does.	*/
/************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<limits.h>
#include<pwd.h>
#include<sys/termio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define MAXCOMLEN 1024	/* length of the command line			*/
#define MAXARGS 512	/* number of arguments in the command line	*/
#define MAXWIDTH 80	/* screen width, used for the 'more' command	*/
#define MAXLINES 23	/* screen length				*/
#define PROMPT "hsh$ "

/* if you want I/O to a socket #define PORTNUM to the port number,	*/
/* if you dont, dont.							*/

/* #define PORTNUM 7890 */
 

/* end of comments (I dont like them), you're on your own now.....	*/



#ifdef PORTNUM
void bulk();
#endif

void help();
int commandlinetoagg(char**,char*);
char *procom(char*);
int getargc(char**);
void arnsetid(char**);
void arnsetgid(char**);
void arnsetpgid(char**);
void arnspawn(char**);
void aswait(char**);
void asbg(char**);
void arnexec(char**);
void cutarg(int,char**);
void displaypinfo();
void displayids();
void displaygids();
void displaypids();
void pwdatanam(char**);
void pwdatauid(char**);
void displayhostinfo(char**);
void dispinetaddr(char*,int);

char inbuf[MAXCOMLEN+1];

#ifdef PORTNUM
main()
{
int sd,cd,n;
int coninflen=sizeof(struct sockaddr_in);
struct sockaddr_in sa;
struct sockaddr_in coninf;

sa.sin_family=AF_INET;
sa.sin_port=htons(PORTNUM);
sa.sin_addr.s_addr=htonl(INADDR_ANY);

if((sd=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
	perror("cant create socket");
	exit(1);
	};
if(bind(sd,(struct sockaddr*)&sa,sizeof(sa)))
	{
	perror("cant bind to address");
	exit(1);
	};
if(listen(sd,2))
	{
	perror("error with listen");
	exit(1);
	};
if((cd=accept(sd,(struct sockaddr*)&coninf,&coninflen))<0)
	{
	perror("error with accept");
	exit(1);
	};
close(STDIN_FILENO);
dup(cd);
close(STDOUT_FILENO);
dup(cd);
close(STDERR_FILENO);
dup(cd);
close(cd);
bulk();
close(sd);
}

void bulk()

#else

main()

#endif

{
char *argv[MAXARGS+1];
while (1)
	{
	printf(PROMPT);
#ifdef PORTNUM
	fflush(stdout);
#endif
	fgets(inbuf,MAXCOMLEN,stdin);
	if(*procom(inbuf)=='\0') continue;
	printf(">%s<\n",inbuf);
#ifdef PORTNUM
	fflush(stdout);
#endif
	if (commandlinetoagg(argv,inbuf)) continue; 
	if (!strcmp(*argv,"exit")) break;
	else
	if (!strcmp(*argv,"ihelp")) help();
	else
	if (!strcmp(*argv,"imore")) displayfile(argv[1]);
	else
	if (!strcmp(*argv,"cd")) changedir(argv);
	else
	if (!strcmp(*argv,"imkdir")) makedir(argv[1]);
	else
	if (!strcmp(*argv,"ird")) removedir(argv[1]);
	else
	if (!strcmp(*argv,"pwd")) pcwd();
	else
	if (!strcmp(*argv,"ils")) directory(argv);
	else
	if (!strcmp(*argv,"setid")) arnsetid(argv);
	else
	if (!strcmp(*argv,"setgid")) arnsetgid(argv);
	else
	if (!strcmp(*argv,"setpgid")) arnsetpgid(argv);
	else
	if (!strcmp(*argv,"pinfo")) displaypinfo();
	else
	if (!strcmp(*argv,"pwdata")) pwdatanam(argv);
	else
	if (!strcmp(*argv,"pwdatauid")) pwdatauid(argv);
	else
	if (!strcmp(*argv,"hinfo")) displayhostinfo(argv);
	else
	if (*argv==NULL);
	else
	arnspawn(argv);
	};
}

void help()
{
printf("\ninternal commands recognised are:\n");
printf("\texit, ihelp, imore, cd, imkdir, ird, pwd, ils,\n");
printf("\tsetid, setgid, setpgid, pinfo\n");
printf("\tpwdata, pwdatauid, hinfo\n\n");
}
 
int commandlinetoagg(char **argv,char *cmdline)
{
int i,argnumber=0,inword=0;
for(i=0;cmdline[i]!='\0';i++)
	{
	if ((cmdline[i]!=' ')&&(!inword))
		{
		argv[argnumber]=(cmdline+i);
		if((++argnumber)>=MAXARGS)
			{
			printf("too many arguments\n");
			*argv=NULL;
			return(1);
			};
		inword=1;
		};
	if (cmdline[i]==' ')
		{
		cmdline[i]='\0';
		inword=0;
		};
	};
argv[argnumber]=NULL;
return(0);
}

char *procom(char *astring)
{
int i;
for(i=0;astring[i]!='\0';i++)
	{
	if (astring[i]=='\r') astring[i]='\0';
	if (astring[i]=='\n') astring[i]='\0';
	};
return(astring);
}
 
changedir(char **argv)
{
if (getargc(argv)!=2)
	{
	printf("usage: %s path\n",*argv);
	return(1);
	};
if (chdir(argv[1]))
	{
	perror("error when trying to change directory ");
	return(1);
	};
return(0);
}

makedir(char *dirname)
{
printf("sorry, function not written yet....\n");
return(1);
}
 
removedir(char *dirname)
{
printf("sorry, function not written yet....\n");
return(1);
}
 
pcwd()
{
char *achpoint;
achpoint=(char*)getcwd(NULL,800);
printf("%s\n",achpoint);
free(achpoint);
return(0);
}
 
directory(char **argv)
{
printf("sorry, function not written yet....\n");
return(1);
}
 
displayfile(char *filename)
{
char tempch,lines,horizpos;
unsigned char pages;
int tempint;
char keybuf[32];
long pagetable[UCHAR_MAX+1];
struct termio old,new;
FILE *afilepoint;
if(!isatty(STDIN_FILENO))
	{
	printf("input is not a tty\n");
	return(1);
	};
if ((afilepoint=fopen(filename,"r"))==NULL)
	{
	printf("error opening file\n");
	return(1);
	};
if(ioctl(STDIN_FILENO,TCGETA,&old))
	{
	printf("error getting terminal status, too risky to try to change\n");
	return(1);
	};
new=old;
new.c_lflag&=~(ICANON|ECHO);
ioctl(STDIN_FILENO,TCSETA,&new);
for (tempint=0;tempint<=UCHAR_MAX;tempint++) pagetable[tempint]=0;
pages=0;
lines=0;                                   
horizpos=0;
while ((tempch=getc(afilepoint))!=EOF)
	{
	switch(tempch)
		{
		case 9 : putchar(9);
			 horizpos+=((horizpos+7)%8)+1;
			 break;
		case 10: printf("\n");
			 horizpos=0;
			 lines++;
			 break;
		default: if ((tempch>31)&&(tempch<127))
				{
				putchar(tempch);
				horizpos++;
				};
		};
	if (horizpos>=MAXWIDTH)
		{
		horizpos-=MAXWIDTH;
		lines++;
		};
	if (lines>=MAXLINES)
		{
		pages++;
		if(read(STDIN_FILENO,keybuf,24)==0) break;
		switch (*keybuf)
			{
			case 'q': ioctl(STDIN_FILENO,TCSETA,&old);
				  fclose(afilepoint);
				  return(1);
			case 'c': ioctl(STDIN_FILENO,TCSETA,&old);
				  fclose(afilepoint);
				  return(1);
			case 'b': printf("\n\n\n");
				  horizpos=0;
				  pages-=2;
				  fseek(afilepoint,pagetable[pages],SEEK_SET);
				  break;
			};
		pagetable[pages]=ftell(afilepoint);
		lines=0;
		};
	};
ioctl(STDIN_FILENO,TCSETA,&old);
fclose(afilepoint);
return(0);
}
 
int getargc(char **argv)
{
int count;
for(count=0;argv[count]!=NULL;count++);
return(count);
}
 
void arnsetid(char **argv)
{
int realid,effid;
displayids();
if (getargc(argv)!=3)
		{
		printf("usage: %s realid effectiveid\n",argv[0]);
		return;
		};
realid=atoi(argv[1]);
effid=atoi(argv[2]);
printf("trying to set:  real id = %d , effective id = %d\n",realid,effid);
if (setreuid(realid,effid))
	{
	printf("failed\n");
	perror("setreuid");
	}
else
	printf("success\n");
displayids();
return;
}

void arnsetgid(char **argv)
{
int realgid,effgid;
displaygids();
if (getargc(argv)!=3)
		{
		printf("usage: %s realgid effectivegid\n",argv[0]);
		return;
		};
realgid=atoi(argv[1]);
effgid=atoi(argv[2]);
printf("trying to set:  real gid = %d , effective gid = %d\n",realgid,effgid);
if (setregid(realgid,effgid))
	{
	printf("failed\n");
	perror("setregid");
	}
else
	printf("success\n");
displaygids();
return;
}

void arnsetpgid(char **argv)
{
int pid,pgid;
displaypids();
if (getargc(argv)!=3)
		{
		printf("usage: %s pid pgid\n",argv[0]);
		return;
		};
pid=atoi(argv[1]);
pgid=atoi(argv[2]);
printf("trying to set the process group of process %d to %d\n",pid,pgid);
if (setpgid(pid,pgid))
	{
	printf("failed\n");
	perror("setpgid");
	}
else
	printf("success\n");
displaypids();
return;
}

void displayids()
{
printf("real uid = %d , effective uid = %d\n",getuid(),geteuid());
}

void arnspawn(char **argv)
{
int argcdec;
argcdec=(getargc(argv)-1);
if (strcmp(argv[argcdec],"&")) aswait(argv);
else
	{
	argv[argcdec]=NULL;
	asbg(argv);
	};
}

void aswait(char **argv)
{
int childpid,waitstat,waitret;
switch(childpid=fork())
	{
	case -1	: printf("can not fork, :-(\n");
		  break;
	case 0	: arnexec(argv);
	default	: printf("program forked, waiting for child process (%d) to exit.....\n",childpid);
		  waitret=waitpid(childpid,&waitstat,0);
		  printf("return value of wait : %d        wait status : %d\n",waitret,waitstat);
	}
}

void asbg(char **argv)
{
int childpid;
switch(childpid=fork())
	{
	case -1 : printf("can not fork, :-(\n");
		  break;
	case 0	: arnexec(argv);
	default : printf("program forked, child process id : %d\n",childpid);
		  sleep(1);
	}
}

void arnexec(char **argv)
{
int x,fdin,fdout,trunc,append;
for(x=1,trunc=1;argv[x]!=NULL;x++) if(!(trunc=(strcmp(argv[x],"<")))) break;
if (!trunc)
	{
	printf("redirecting stdin from filename >%s<\n",argv[x+1]);
	if ((fdin=open(argv[x+1],O_RDONLY))== -1)
		{
		perror("cannot open file");
		printf("cannot open file for stdin, better luck next time ;-)\n");
		exit(1);
		};
	if (close(STDIN_FILENO))
		{
		perror("cannot close");
		printf("sorry but I'm confused again\n");
		exit(1);
		};
	if (dup(fdin)!=STDIN_FILENO)
		{
		printf("something wrong with dup(2), sorry but I'm out a here\n");
		close(fdin);
		exit(1);
		};
	if (close(fdin))
		{
		perror("cannot close");
		printf("sorry but I'm confused again\n");
		exit(1);
		};
	cutarg(x,argv);
	cutarg(x,argv);
	}
for(x=1,trunc=1;argv[x]!=NULL;x++) if(!(trunc=(strcmp(argv[x],">")))) break;
if (trunc) for(x=1,append=1;argv[x]!=NULL;x++) if(!(append=(strcmp(argv[x],">>")))) break;
if ((!trunc)||(!append))
	{
	printf("redirecting stdout to filename >%s<\n",argv[x+1]);
	if ((fdout=open(argv[x+1],O_WRONLY|O_CREAT|(trunc?0:O_TRUNC)|(append?0:O_APPEND),0666))== -1)
		{
		perror("cannot open file");
		printf("cannot open file for stdout, better luck next time ;-)\n");
		exit(1);
		};
	if (close(STDOUT_FILENO))
		{
		perror("cannot close");
		printf("sorry but I'm confused again\n");
		exit(1);
		};
	if (dup(fdout)!= STDOUT_FILENO)
		{
		printf("something wrong with dup(2), sorry but I'm out a here\n");
		close(fdout);
		exit(1);
		};
	if (close(fdout))
		{
		perror("cannot close");
		printf("sorry but I'm confused again\n");
		exit(1);
		};
	cutarg(x,argv);
	cutarg(x,argv);
	};
if ((execvp(argv[0],argv))==-1)
	{
	printf("can not use command, sorry\n");
	exit(1);
	};
printf("whats happened? exec has a strange return value!  I'm confused ;-O\n");
exit(1);
}

void cutarg(int x,char **argv)
{
for(;argv[x]!=NULL;x++) argv[x]=argv[x+1];
}

void displaypinfo()
{
displayids();
displaygids();
displaypids();
}

void displaygids()
{
printf("real group id = %d , effective group id = %d\n",getgid(),getegid());
}

void displaypids()
{
printf("pid = %d , parent pid = %d , process group = %d\n",getpid(),getppid(),getpgrp());
}

void pwdatanam(char **argv)
{
struct passwd *a;
if(getargc(argv)!=2)
	{
	printf("usage: %s username\n",*argv);
	return;
	};
if((a=getpwnam(argv[1]))==NULL)
	{
	printf("%s: cant get info\n",*argv);
	perror(*argv);
	return;
	};
printf("username=%s passwd=%s uid=%d gid=%d gecos=%s home=%s shell=%s\n",
	a->pw_name,a->pw_passwd,a->pw_uid,a->pw_gid,a->pw_gecos,a->pw_dir,a->pw_shell);
}

void pwdatauid(char **argv)
{
struct passwd *a;
if(getargc(argv)!=2)
	{
	printf("usage: %s uid\n",*argv);
	return;
	};
if((a=getpwuid(atoi(argv[1])))==NULL)
	{
	printf("%s: cant get info\n",*argv);
	perror(*argv);
	return;
	};
printf("username=%s passwd=%s uid=%d gid=%d gecos=%s home=%s shell=%s\n",
	a->pw_name,a->pw_passwd,a->pw_uid,a->pw_gid,a->pw_gecos,a->pw_dir,a->pw_shell);
}

void displayhostinfo(char **argv)
{
int c;
struct hostent *he;
if(getargc(argv)!=2)
	{
	printf("usage: %s hostname\n",*argv);
	return;
	};
if((he=gethostbyname(argv[1]))==NULL)
	{
	printf("%s: error with gethostbyname\n",*argv);
	return;
	};
if(he->h_addrtype!=AF_INET) printf("warning, address returned is a type I dont know of\n");
printf("official name=\"%s\"\n",he->h_name);
printf("length of address=%d\n",he->h_length);
printf("aliases:\n");
for(c=0;he->h_aliases[c]!=NULL;c++) printf("\"%s\"\n",he->h_aliases[c]);
printf("addresses:\n");
for(c=0;he->h_addr_list[c]!=NULL;c++) dispinetaddr(he->h_addr_list[c],he->h_length);
}

void dispinetaddr(char *a,int b)
{
int c;
for(c=0;c<b;c++) printf("%u.",(unsigned char)a[c]);
putchar('\n');
}

