From: root@fusion.cuc.ab.ca (Superuser)
Newsgroups: comp.os.coherent
Subject: Coherent Job Control
Date: 10 Apr 1992 20:53:06 -0500
Organization: CS Dept, University of Texas at Austin
NNTP-Posting-Host: cs.utexas.edu

Here's some code I hacked up to try to implement job control under Coherent
with ptrace().  Applications?  See the notes at the end of the listing.  You
may use this code in your own works, but please read the restrictions in the
header.

Try the following example:

Me!% cc fork.c <cr>
Me!% fork 0 ls -alR / <cr>

 child stopped 0177

c
{ recursive directory listing begins... }
s
{ directory listing stops... }
 child stopped 0177

c
{ directory listing continues... }
s
{ directory listing stops... }
 child stopped 0177

p
{ 'ps-al' listing }
x
 child stopped 0
Me%

Note that the 'ps -al' shows the status of the child as 'T' - being traced
and you can start/stop the child as you like.

Another experiment- remove the code at the end of the listing which terminates
the child when 'x' is pressed, then run again.  Press 'c' to start the 'ls',
then while 'ls' is still running, hit 'x'.  'ls' should still be running,
type 'ps -al > processes' and look at the file after 'ls' finishes- note that
'ls' is now either 'R' or 'S' or 'W', meaning that since the parent has
exited, the ptrace() is no longer in effect.

Here's the code:

-----------8<-------cut-here--------8<--------
/* fork.c - try simulated job control with process tracing while forking */

/* Copyright C. Lau (root@fusion.cuc.ab.ca) - April 10/1992
   Permission is given to use and modify the following code for PERSONAL use.

   Distribution of derivative works is allowed with the following provisions:

   o Any source containing any of the following code or its derivatives
     MAY NOT BE DISTRIBUTED AT ANY COST (INCLUDING DUPLICATION AND MEDIA
     CHARGES) WITHOUT THE EXPRESS WRITTEN CONSENT OF THE AUTHOR.

   o This notice (or a reasonable alternative wording crediting the author
     of this work) must appear in any derivative work.

   The author makes no warranty as to the correctness of the following code
   nor to the fitness of it to any application.
*/

#include <stdio.h>
#include <sys/proc.h>
#include <signal.h>

main(argc,argv)
int argc;
char *argv[];
{
	char temp;
	int pid;
	int nice_level, valid, minimum_level;

/* ignore this..  I originally started out trying to write a nice(1)
   program, but it turned into an experiment in process control */
	
	temp = argv[1][0];
	nice_level = atoi(argv[1]);

	/* only superuser can run at higher priority */
	if(geteuid()!=0)
		minimum_level = DEFNICE;
	else
		minimum_level = MINNICE;
	
	/* make sure it's a valid level (sysV compatible 0 to 40) */
	if(nice_level >= minimum_level && nice_level <= MAXNICE)
		valid = 1;
	else
		valid = 0;

	/* print a usage message if the user screwed up */
	if(argc<3 || !isdigit(temp) || !valid) {
		fprintf(stderr,"usage: %s nice_level command [options]\n",
			argv[0]);
		fprintf(stderr,"       nice_level = %d (min) to %d (max)\n",
			minimum_level, MAXNICE);
		exit(-1);
	}

	/* set the nice level */
	nice(nice_level); 

#ifdef DEBUG
	printf("nice level = %d\n",nice_level);
#endif


/* here's the meat of the program.. it's really a hack job, so there's some
   ugly code constructs.. */

	if((pid=fork())==0) {
		/* I'm the child, tell parent I want to be traced */
		ptrace(0,getpid(),NULL,NULL);
		/* run the user command */
		execvp(argv[2],(char **)&(argv[2]));
		/* the child will stop at this point..  the parent must:
			1- wait for the child
			2- check status = 0177
			3- restart the child (ptrace(8,pid,(int *)1,0))
		*/
	} else {
		/* I'm the parent, tell child I want to trace him */
		ptrace(0,pid,NULL,NULL);
		/* child stops on exec, wait for it */
		wait(&valid);
		printf("\nchild stopped %o\n",valid);

		/* do a command loop.. 

		x = exit parent
		s = stop child
		c = continue child
		p = execute 'ps -al'
		*/

		valid = 0;   
		while((temp=getchar())!='x') {
	
			/* the stuff with valid make sure you can't
			   signal the process while it is stopped...
			   (ptrace has some trouble with that.. don't
			   know why..)  If you want to try, delete
			   the exclusion code and try running.  You'll
			   note that if you hit 's' twice in a row
			   you'll need to run 'ps' before 'c' will
			   restart the process...  something to do with
			   clearing a status bit or something ??
				
			   The octal number 0177 should be the wait status
			   if the child process is successfully stopped.
			*/

			if(temp == 's' && valid) {
				kill(pid,SIGTRAP);
				wait(&valid);
				printf("\n child stopped %o\n",valid);
				valid=0;  
			} else if(temp == 's' && !valid)
				printf("\n child already stopped\n");

			if(temp == 'c' && !valid) {
				ptrace(7,pid,(int *) 1,0);
				valid=1;
			} else if(valid)
				printf("\n child already going\n");
			if(temp == 'p') {

				system("ps -al");
			}
		}

		/* end..  */
		kill(pid,SIGTRAP);   /* stop child */
		wait(&valid);        /* wait till he stops */
		printf("\n child stopped %o\n",valid);
		ptrace(8,pid,NULL,NULL);  /* tell child to terminate */
	}
}

/* Notes:

   Those of you running the dash shell may want to try adapting this code
   for job control (I haven't looked at David Feynes' version of simulated
   job control using this method to see if it's any different than mine
   above, but I understand that what he tried didn't work, while mine
   DOES.    Most probably, he forgot to put the wait()s in..  I found
   that those necessary, otherwise ptrace stalls.)

   Another consideration is that when a process is being traced, any
   setuid or setgid modes on a file being exec()'ed DO NOT HAVE ANY
   EFFECT.  So you have to make special provisions for running a suid/sgid
   program (stat() the executable, and if it has suid/sgid modes set,
   don't ptrace() it).

   Let me know about any changes made and/or applications you have found
   for this code.


   Christopher Lau - "Mr. UNIX"
   Internet: {root,lauc}@fusion.cuc.ab
   UUCP: ..!uunet!{ucb-cs,utai,alberta}!calgary!debug!fusion!{root,lauc}

*/
-----------8<-------cut-here--------8<--------

C4


--
----------------------------------------------------------------------------
Christopher Lau - "Mr. UNIX"       |     /      Fusion: Playing with fire!
"Bring Back Trudeau!"              |    / /     H -> He + 24MeV
Running SCO Unix System V 3.2.2    |   / / /    
Phone: (403)-243-7249              |  /_/_/_/_  "This space for rent"
----------------------------------------------------------------------------
Internet: {root,lauc}@fusion.cuc.ab
UUCP: ..!uunet!{ucb-cs,utai,alberta}!calgary!debug!fusion!{root,lauc}