Some more job control updates.  It will now sucessfully background
stuff.  Good luck getting things back into the foreground though...
 -Erik
diff --git a/hush.c b/hush.c
index 01fd334..4a16a3f 100644
--- a/hush.c
+++ b/hush.c
@@ -470,48 +470,53 @@
 /* built-in 'fg' and 'bg' handler */
 static int builtin_fg_bg(struct child_prog *child)
 {
-	int i, jobNum;
-	struct pipe *job=NULL;
-	
-	if (!child->argv[1] || child->argv[2]) {
-		error_msg("%s: exactly one argument is expected\n",
-				child->argv[0]);
-		return EXIT_FAILURE;
-	}
+	int i, jobnum;
+	struct pipe *pi=NULL;
 
-	if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
-		error_msg("%s: bad argument '%s'\n",
-				child->argv[0], child->argv[1]);
-		return EXIT_FAILURE;
-	}
+	/* If they gave us no args, assume they want the last backgrounded task */
+	if (!child->argv[1]) {
+		for (pi = job_list->head; pi; pi = pi->next) {
+			if (pi->progs && pi->progs->pid == last_bg_pid) {
+				break;
+			}
+		}
+		if (!pi) {
+			error_msg("%s: no current job", child->argv[0]);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
+			error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+			return EXIT_FAILURE;
+		}
 
-	for (job = job_list->head; job; job = job->next) {
-		if (job->jobid == jobNum) {
-			break;
+		for (pi = job_list->head; pi; pi = pi->next) {
+			if (pi->jobid == jobnum) {
+				break;
+			}
+		}
+		if (!pi) {
+			error_msg("%s: %d: no such job", child->argv[0], jobnum);
+			return EXIT_FAILURE;
 		}
 	}
-
-	if (!job) {
-		error_msg("%s: unknown job %d\n",
-				child->argv[0], jobNum);
-		return EXIT_FAILURE;
-	}
-
 	if (*child->argv[0] == 'f') {
 		/* Make this job the foreground job */
+		signal(SIGTTOU, SIG_IGN);
 		/* suppress messages when run from /linuxrc mag@sysgo.de */
-		if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY)
+		if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY)
 			perror_msg("tcsetpgrp"); 
-		job_list->fg = job;
+		signal(SIGTTOU, SIG_DFL);
+		job_list->fg = pi;
 	}
 
 	/* Restart the processes in the job */
-	for (i = 0; i < job->num_progs; i++)
-		job->progs[i].is_stopped = 0;
+	for (i = 0; i < pi->num_progs; i++)
+		pi->progs[i].is_stopped = 0;
 
-	kill(-job->pgrp, SIGCONT);
+	kill(-pi->pgrp, SIGCONT);
 
-	job->stopped_progs = 0;
+	pi->stopped_progs = 0;
 	return EXIT_SUCCESS;
 }
 
@@ -1055,7 +1060,7 @@
 	}
 
 	/* physically copy the struct job */
-	*thejob = *pi;   
+	memcpy(thejob, pi, sizeof(struct pipe));
 	thejob->next = NULL;
 	thejob->running_progs = thejob->num_progs;
 	thejob->stopped_progs = 0;
@@ -1103,6 +1108,7 @@
 	memset(pi, 0, sizeof(struct pipe));
 }
 
+
 /* Checks to see if any background processes have exited -- if they 
    have, figure out why and see if a job has completed */
 static void checkjobs()
@@ -1169,14 +1175,27 @@
 static int run_pipe_real(struct pipe *pi)
 {
 	int i;
+	int ctty;
 	int nextin, nextout;
 	int pipefds[2];				/* pipefds[0] is for reading */
 	struct child_prog *child;
 	struct built_in_command *x;
 
+	ctty = -1;
 	nextin = 0;
 	pi->pgrp = 0;
 
+	/* Check if we are supposed to run in the foreground */
+	if (pi->followup!=PIPE_BG) {
+		if ((pi->pgrp = tcgetpgrp(ctty = 2)) < 0
+				&& (pi->pgrp = tcgetpgrp(ctty = 0)) < 0
+				&& (pi->pgrp = tcgetpgrp(ctty = 1)) < 0)
+			return errno = ENOTTY, -1;
+
+		if (pi->pgrp < 0 && pi->pgrp != getpgrp())
+			return errno = EPERM, -1;
+	}
+
 	/* Check if this is a simple builtin (not part of a pipe).
 	 * Builtins within pipes have to fork anyway, and are handled in
 	 * pseudo_exec.  "echo foo | read bar" doesn't work on bash, either.
@@ -1225,6 +1244,7 @@
 
 		/* XXX test for failed fork()? */
 		if (!(child->pid = fork())) {
+
 			signal(SIGTTOU, SIG_DFL);
 			
 			close_all();
@@ -1244,22 +1264,33 @@
 			/* Like bash, explicit redirects override pipes,
 			 * and the pipe fd is available for dup'ing. */
 			setup_redirects(child,NULL);
+			
+			if (pi->followup!=PIPE_BG) {
+				/* Put our child in the process group whose leader is the
+				 * first process in this pipe. */
+				if (pi->pgrp < 0) {
+					pi->pgrp = child->pid;
+				}
+				/* Don't check for errors.  The child may be dead already,
+				 * in which case setpgid returns error code EACCES. */
+				if (setpgid(0, pi->pgrp) == 0) {
+					signal(SIGTTOU, SIG_IGN);
+					tcsetpgrp(ctty, pi->pgrp);
+					signal(SIGTTOU, SIG_DFL);
+				}
+			}
 
 			pseudo_exec(child);
 		}
-		if (interactive) {
-			/* Put our child in the process group whose leader is the
-			 * first process in this pipe. */
-			if (pi->pgrp==0) {
-				pi->pgrp = child->pid;
-			}
-			/* Don't check for errors.  The child may be dead already,
-			 * in which case setpgid returns error code EACCES. */
-			setpgid(child->pid, pi->pgrp);
+		/* Put our child in the process group whose leader is the
+		 * first process in this pipe. */
+		if (pi->pgrp < 0) {
+			pi->pgrp = child->pid;
 		}
-		/* In the non-interactive case, do nothing.  Leave the children
-		 * with the process group that they inherited from us. */
-	
+		/* Don't check for errors.  The child may be dead already,
+		 * in which case setpgid returns error code EACCES. */
+		setpgid(child->pid, pi->pgrp);
+
 		if (nextin != 0)
 			close(nextin);
 		if (nextout != 1)
@@ -1295,13 +1326,10 @@
 			/* XXX check bash's behavior with nontrivial pipes */
 			/* XXX compute jobid */
 			/* XXX what does bash do with attempts to background builtins? */
-#if 0
-			printf("[%d] %d\n", pi->jobid, pi->pgrp);
-			last_bg_pid = pi->pgrp;
-#endif	
 			insert_bg_job(pi);
 			rcode = EXIT_SUCCESS;
 		} else {
+
 			if (interactive) {
 				/* move the new process group into the foreground */
 				/* suppress messages when run from /linuxrc mag@sysgo.de */
diff --git a/shell/hush.c b/shell/hush.c
index 01fd334..4a16a3f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -470,48 +470,53 @@
 /* built-in 'fg' and 'bg' handler */
 static int builtin_fg_bg(struct child_prog *child)
 {
-	int i, jobNum;
-	struct pipe *job=NULL;
-	
-	if (!child->argv[1] || child->argv[2]) {
-		error_msg("%s: exactly one argument is expected\n",
-				child->argv[0]);
-		return EXIT_FAILURE;
-	}
+	int i, jobnum;
+	struct pipe *pi=NULL;
 
-	if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
-		error_msg("%s: bad argument '%s'\n",
-				child->argv[0], child->argv[1]);
-		return EXIT_FAILURE;
-	}
+	/* If they gave us no args, assume they want the last backgrounded task */
+	if (!child->argv[1]) {
+		for (pi = job_list->head; pi; pi = pi->next) {
+			if (pi->progs && pi->progs->pid == last_bg_pid) {
+				break;
+			}
+		}
+		if (!pi) {
+			error_msg("%s: no current job", child->argv[0]);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
+			error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+			return EXIT_FAILURE;
+		}
 
-	for (job = job_list->head; job; job = job->next) {
-		if (job->jobid == jobNum) {
-			break;
+		for (pi = job_list->head; pi; pi = pi->next) {
+			if (pi->jobid == jobnum) {
+				break;
+			}
+		}
+		if (!pi) {
+			error_msg("%s: %d: no such job", child->argv[0], jobnum);
+			return EXIT_FAILURE;
 		}
 	}
-
-	if (!job) {
-		error_msg("%s: unknown job %d\n",
-				child->argv[0], jobNum);
-		return EXIT_FAILURE;
-	}
-
 	if (*child->argv[0] == 'f') {
 		/* Make this job the foreground job */
+		signal(SIGTTOU, SIG_IGN);
 		/* suppress messages when run from /linuxrc mag@sysgo.de */
-		if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY)
+		if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY)
 			perror_msg("tcsetpgrp"); 
-		job_list->fg = job;
+		signal(SIGTTOU, SIG_DFL);
+		job_list->fg = pi;
 	}
 
 	/* Restart the processes in the job */
-	for (i = 0; i < job->num_progs; i++)
-		job->progs[i].is_stopped = 0;
+	for (i = 0; i < pi->num_progs; i++)
+		pi->progs[i].is_stopped = 0;
 
-	kill(-job->pgrp, SIGCONT);
+	kill(-pi->pgrp, SIGCONT);
 
-	job->stopped_progs = 0;
+	pi->stopped_progs = 0;
 	return EXIT_SUCCESS;
 }
 
@@ -1055,7 +1060,7 @@
 	}
 
 	/* physically copy the struct job */
-	*thejob = *pi;   
+	memcpy(thejob, pi, sizeof(struct pipe));
 	thejob->next = NULL;
 	thejob->running_progs = thejob->num_progs;
 	thejob->stopped_progs = 0;
@@ -1103,6 +1108,7 @@
 	memset(pi, 0, sizeof(struct pipe));
 }
 
+
 /* Checks to see if any background processes have exited -- if they 
    have, figure out why and see if a job has completed */
 static void checkjobs()
@@ -1169,14 +1175,27 @@
 static int run_pipe_real(struct pipe *pi)
 {
 	int i;
+	int ctty;
 	int nextin, nextout;
 	int pipefds[2];				/* pipefds[0] is for reading */
 	struct child_prog *child;
 	struct built_in_command *x;
 
+	ctty = -1;
 	nextin = 0;
 	pi->pgrp = 0;
 
+	/* Check if we are supposed to run in the foreground */
+	if (pi->followup!=PIPE_BG) {
+		if ((pi->pgrp = tcgetpgrp(ctty = 2)) < 0
+				&& (pi->pgrp = tcgetpgrp(ctty = 0)) < 0
+				&& (pi->pgrp = tcgetpgrp(ctty = 1)) < 0)
+			return errno = ENOTTY, -1;
+
+		if (pi->pgrp < 0 && pi->pgrp != getpgrp())
+			return errno = EPERM, -1;
+	}
+
 	/* Check if this is a simple builtin (not part of a pipe).
 	 * Builtins within pipes have to fork anyway, and are handled in
 	 * pseudo_exec.  "echo foo | read bar" doesn't work on bash, either.
@@ -1225,6 +1244,7 @@
 
 		/* XXX test for failed fork()? */
 		if (!(child->pid = fork())) {
+
 			signal(SIGTTOU, SIG_DFL);
 			
 			close_all();
@@ -1244,22 +1264,33 @@
 			/* Like bash, explicit redirects override pipes,
 			 * and the pipe fd is available for dup'ing. */
 			setup_redirects(child,NULL);
+			
+			if (pi->followup!=PIPE_BG) {
+				/* Put our child in the process group whose leader is the
+				 * first process in this pipe. */
+				if (pi->pgrp < 0) {
+					pi->pgrp = child->pid;
+				}
+				/* Don't check for errors.  The child may be dead already,
+				 * in which case setpgid returns error code EACCES. */
+				if (setpgid(0, pi->pgrp) == 0) {
+					signal(SIGTTOU, SIG_IGN);
+					tcsetpgrp(ctty, pi->pgrp);
+					signal(SIGTTOU, SIG_DFL);
+				}
+			}
 
 			pseudo_exec(child);
 		}
-		if (interactive) {
-			/* Put our child in the process group whose leader is the
-			 * first process in this pipe. */
-			if (pi->pgrp==0) {
-				pi->pgrp = child->pid;
-			}
-			/* Don't check for errors.  The child may be dead already,
-			 * in which case setpgid returns error code EACCES. */
-			setpgid(child->pid, pi->pgrp);
+		/* Put our child in the process group whose leader is the
+		 * first process in this pipe. */
+		if (pi->pgrp < 0) {
+			pi->pgrp = child->pid;
 		}
-		/* In the non-interactive case, do nothing.  Leave the children
-		 * with the process group that they inherited from us. */
-	
+		/* Don't check for errors.  The child may be dead already,
+		 * in which case setpgid returns error code EACCES. */
+		setpgid(child->pid, pi->pgrp);
+
 		if (nextin != 0)
 			close(nextin);
 		if (nextout != 1)
@@ -1295,13 +1326,10 @@
 			/* XXX check bash's behavior with nontrivial pipes */
 			/* XXX compute jobid */
 			/* XXX what does bash do with attempts to background builtins? */
-#if 0
-			printf("[%d] %d\n", pi->jobid, pi->pgrp);
-			last_bg_pid = pi->pgrp;
-#endif	
 			insert_bg_job(pi);
 			rcode = EXIT_SUCCESS;
 		} else {
+
 			if (interactive) {
 				/* move the new process group into the foreground */
 				/* suppress messages when run from /linuxrc mag@sysgo.de */