From: BigBrother on
I'm trying to build a very basic shell (like bash but..bad). And I've
decided the best way to do this would be to make my programs
separately and put them in their own directory, much like /bin. Well
how can I set something like this up. I tell my shell 'ls' and it
looks in the directory I choose to store the data in, then it runs the
program and when its done exits and returns to its own process? I'm
teaching myself C so I'm pretty lost on how to do this. Sorry if this
is poorly worded
From: Barry Margolin on
In article
<4559b36e-3bb6-48da-a9b0-97da42038d65(a)s20g2000prm.googlegroups.com>,
BigBrother <cowboyninja(a)gmail.com> wrote:

> I'm trying to build a very basic shell (like bash but..bad). And I've
> decided the best way to do this would be to make my programs
> separately and put them in their own directory, much like /bin. Well
> how can I set something like this up. I tell my shell 'ls' and it
> looks in the directory I choose to store the data in, then it runs the
> program and when its done exits and returns to its own process? I'm
> teaching myself C so I'm pretty lost on how to do this. Sorry if this
> is poorly worded

When a shell runs a program, it uses fork() to create a child process.
The child process uses execv() (or one of the other exec* variants) to
run the program, while the shell uses wait() to wait for it to finish.

Things get a bit more complicated when pipelines are involved, but
that's the basic structure. And if the program is run in the
background, the shell simply continues on rather than using wait() (job
control complicates this somewhat).

--
Barry Margolin, barmar(a)alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: jellybean stonerfish on
On Fri, 26 Mar 2010 15:09:53 -0700, BigBrother wrote:

> I'm trying to build a very basic shell (like bash but..bad). And I've
> decided the best way to do this would be to make my programs separately
> and put them in their own directory, much like /bin. Well how can I set
> something like this up. I tell my shell 'ls' and it looks in the
> directory I choose to store the data in, then it runs the program and
> when its done exits and returns to its own process? I'm teaching myself
> C so I'm pretty lost on how to do this. Sorry if this is poorly worded

Maybe add your own directory to your PATH

PATH=yourdir:$PATH

From: Phred Phungus on
Alan Curry wrote:

> Or just call execvp()
>

I have something slightly different that I'm looking at. It's
intorduced in Stevens and Rago as a basic shell, and it uses the exec
family for the business end of it.

My question is about the buffers.

$ gcc -D_GNU_SOURCE -std=c99 -Iinclude -Wall -Wextra lib/error.o
fig1.10.1.c -o out
fig1.10.1.c:38: warning: unused parameter �signo�
$ ./out
% ls
advio fig11.5 fig16.15 fig18.12 fig6.2 figC.4

....

fig11.4 fig16.14 fig18.11 fig5.5 figC.3
% ^Cinterrupt
% Aborted
$

$ cat fig1.10.1.c
#include "apue.h"
#include <sys/wait.h>

static void sig_int(int); /* our signal-catching function */

int
main(void)
{
char buf[MAXLINE]; /* from apue.h */
pid_t pid;
int status;

if (signal(SIGINT, sig_int) == SIG_ERR)
err_sys("signal error");

printf("%% "); /* print prompt (printf requires %% to print %) */
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0; /* replace newline with null */

if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) { /* child */
execlp(buf, buf, (char *)0);
err_ret("couldn't execute: %s", buf);
exit(127);
}

/* parent */
if ((pid = waitpid(pid, &status, 0)) < 0)
err_sys("waitpid error");
printf("%% ");
}
exit(0);
}

void
sig_int(int signo)
{
printf("interrupt\n%% ");
abort();
}

// gcc -D_GNU_SOURCE -std=c99 -Iinclude -Wall -Wextra lib/error.o
fig1.10.1.c -o out
$

Basically, my question is whether the buffers here are well-constructed.
MAXLINE will probably be a large number, while the commands I type
will be no more than a hundred characters.

execlp(buf, buf, (char *)0);

To my eye, it looks like this could get by with one argument instead of
three.

To the OP, a basic shell is here if you can replicate the steps. You
won't have the source for things like err_sys, but you can comment those
lines out.

HTH
--
fred
From: Alan Curry on
In article <8187ufFt6bU1(a)mid.individual.net>,
Phred Phungus <Phred(a)example.invalid> wrote:
| while (fgets(buf, MAXLINE, stdin) != NULL) {
| if (buf[strlen(buf) - 1] == '\n')
| buf[strlen(buf) - 1] = 0; /* replace newline with null */
[...]
|
|Basically, my question is whether the buffers here are well-constructed.
| MAXLINE will probably be a large number, while the commands I type
|will be no more than a hundred characters.

If you type a line that's too long, some ugly stuff will happen, but that's
an acceptable flaw in a small demonstration program.

|
|execlp(buf, buf, (char *)0);
|
|To my eye, it looks like this could get by with one argument instead of
|three.

Well the 0 at the end is a terminator, you have to have that or execlp
doesn't know how many args there are. And the first 2 are semi-redundant: one
is the name of the program to be executed, and the other one is what that
program will get in its argv[0]. Normally those should be the same, and in
this example they are the same (both are "buf").

If you left out the secnod arg to execlp, the exec'd program would get a null
argv[0], which is not quite a disaster but it's really nasty.

--
Alan Curry