How to create | in one's own shell? - shell

I'm actually doing my own shell.
I have done the following special characters:
int commande(int fin, int fout, char * com, char * param, int * bg){
// execute a command
(ex. ls –l)
int symbole;
char *mot;
pid_t pid;
symbole = parsing();
switch(symbole){
case 0: // NL
case 1: // ;
case 2: // &
case 3: // <
case 4: // >
case 5: // | (Here I have some issues when I try to redirect the output of a command).
(correspond à ctrl+D)
case 10:// Mot
default:
}
return;
}
But I have some issues to do the redirection of an output when it is piped " |", when I have two instructions that follow themselves. Indeed I have tried the following operations which have all worked:
>myShell ps > fich
>myShell ls -l | wc -l
But not this one:
>myShell ls -l | wc -l >file
here are the two cases specifically developped. I think that the issue is in the case 5 and not in the case 4 because the first command I tried worked (which I shew you above).
case 4: // SYMBOLE : >
if(output==0){
output=1;
execute=1;
for (l=0;l<10;l++){
eltsoutput[l]=eltsCommande[l];
}
}
break;
case 5: // SYMBOLE : |
//if(tube==0){
/*for (l=0;l<10;l++){
eltstube[l]=eltsCommande[l];
}*/
p2=fork();
if(p2==0){
if(tube==0){
freopen( "fichtmp", "w", stdout );
execvp(eltsCommande[0], eltsCommande);
}
return(0);
}
else{ if(background==0){ // SANS MOD BG ATTENDRE FIN FILS
waitpid(p2, NULL, 0);
}
tube=1;
execute=1;
}
break;
Can you help me finding a way to execute two commands at the same time with | and that allow their result to go to a file?
In my shell, the case one work in the case of a redirection with an instruction ";":
}else if(output==1){
close(1);
int filew = creat(eltsCommande[0], 0644);
execvp(eltsoutput[0], eltsoutput);
Maybe I should use this code to make it work?

Looking at the NetBSD /bin/sh source code, I see the following pipe implementation:
static int
sh_pipe(int fds[2])
{
int nfd;
if (pipe(fds))
return -1;
if (fds[0] < 3) {
nfd = fcntl(fds[0], F_DUPFD, 3);
if (nfd != -1) {
close(fds[0]);
fds[0] = nfd;
}
}
if (fds[1] < 3) {
nfd = fcntl(fds[1], F_DUPFD, 3);
if (nfd != -1) {
close(fds[1]);
fds[1] = nfd;
}
}
return 0;
}
This function is called by evalpipe with 2 file descriptors:
STATIC void
evalpipe(union node *n)
{
struct job *jp;
struct nodelist *lp;
int pipelen;
int prevfd;
int pip[2];
TRACE(("evalpipe(0x%lx) called\n", (long)n));
pipelen = 0;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
pipelen++;
INTOFF;
jp = makejob(n, pipelen);
prevfd = -1;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
prehash(lp->n);
pip[1] = -1;
if (lp->next) {
if (sh_pipe(pip) < 0) {
if (prevfd >= 0)
close(prevfd);
error("Pipe call failed");
}
}
if (forkshell(jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
INTON;
if (prevfd > 0) {
close(0);
copyfd(prevfd, 0, 1);
close(prevfd);
}
if (pip[1] >= 0) {
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1, 1);
close(pip[1]);
}
}
evaltree(lp->n, EV_EXIT);
}
if (prevfd >= 0)
close(prevfd);
prevfd = pip[0];
close(pip[1]);
}
if (n->npipe.backgnd == 0) {
exitstatus = waitforjob(jp);
TRACE(("evalpipe: job done exit status %d\n", exitstatus));
}
INTON;
}
evalpipe is called in a switch statement in evaltree as follows:
case NPIPE:
evalpipe(n);
do_etest = !(flags & EV_TESTED);
break;
... which is called by the infinite loop in evalloop, and percolates up the tree till it gets to the eval function. I hope this helps.

Related

Error with fread() in c, not having expected outut

I'm making a checksum algorithm for one of my classes, I want to read two binary files and run them through a checksum algorithm. The checksum algorithm works (I've tried inputting what I want into the terminal and it works) but I can't get my fread() to work. I've tried printing the outputs and they print the correct stuff, but then a bunch of other random numbers and letters at the end.
Here is my code:
int main(int argc, char *argv[])
{
FILE *ptr1;
FILE *ptr2;
ptr1 = fopen("test1.bin","rb");
ptr2 = fopen("test2.bin","rb");
char file1[sizeof(ptr1)], file2[sizeof(ptr2)];
char sum[sizeof(ptr1)], comp[sizeof(ptr1)];
fread(file1,sizeof(file1),1,ptr1);
fread(file2,sizeof(file2),1,ptr2);
fclose(ptr1);
fclose(ptr2);
/* char file1[20], file2[20];
char sum[20], comp[20];
printf("enter 1\n");
scanf("%s",&file1);
printf("enter 2\n");
scanf("%s",&file2);*/
if(strlen(file1)==strlen(file2)) {
char next='0';
int length = strlen(file1);
for(int i=length-1;i>=0;i--)
{
if(file1[i]=='0' && file2[i]=='0' && next=='0')
{
sum[i]='0';
next='0';
}
else if(file1[i]=='0' && file2[i]=='0' && next=='1')
{
sum[i]='1';
next='0';
}
else if(file1[i]=='0' && file2[i]=='1' && next=='0')
{
sum[i]='1';
next='0';
}
else if(file1[i]=='0' && file2[i]=='1' && next=='1')
{
sum[i]='0';
next='1';
}
else if(file1[i]=='1' && file2[i]=='0' && next=='0')
{
sum[i]='1';
next='0';
}
else if(file1[i]=='1' && file2[i]=='0' && next=='1')
{
sum[i]='0';
next='1';
}
else if(file1[i]=='1' && file2[i]=='1' && next=='0')
{
sum[i]='0';
next='1';
}
else if(file1[i]=='1' && file2[i]=='1' && next=='1')
{
sum[i]='1';
next='1';
}
else
break;
}
for (int i=0;i<length;i++)
{
if(sum[i]=='0')
comp[i]='1';
else
comp[i]='0';
}
if(next=='1')
next='0';
else
next='1';
printf("\nChecksum=%c%s",next, comp);
}
else {
printf("\nInput Lengths do not match");
}
}
test1.bin and test2.bin are two files that contain 8 bytes of binary. I've tried using
printf("this is file 1 %s\n", file1)
printf("this is file 2 %s\n", file2)
to help debug and it outputs
this is file 1 01001001dL
this is file 2 01001000P5L
What is my error here? I'm not great at C so I'm sure its something simple.
You allocate sizeof(ptr1) bytes for file1, but that means the size of the type FILE*, which is likely to be 4. If you know your file contains exactly 8 bytes, do write 8 there.

PVS-Studio: warning V595 is generated even if pointer is checked

In the following code there is already check for nullptr in (1):
int msg;
struct x * var[2];
if ((var[0] = get_x()) == nullptr) { // (1)
return;
}
if (var[0]->data != 11) { // (2) <<< V595
msg = 1;
printf("msg1");
}
if (var[0] && var[0]->data == 12) { // (3) <<< V595
msg = 2;
return;
}
but I still get error: V595. Why?
I agree that there is an exceeding check for nullptr in (3).
Analyzer considers this piece of code abnormal. First, the pointer is being deferenced, and after that it is being verified. Even if it cannot be equal to NULL, it looks very suspicious. There's a possibility that wrong variable is used or checked.
So it is possible that the wrong variable is used, and the corrected version of code could look like:
if (FOO->data != 11) {
msg = 1;
printf("msg1");
}
if (var[0] && var[0]->data == 12) {
msg = 2;
return;
}
Or, probably, the condition is incorrect:
if (var[0]->data != 11) {
msg = 1;
printf("msg1");
}
if (FOO && var[0]->data == 12) {
msg = 2;
return;
}
Anyway, the analyzer doesn't like it, and it issues a warning. To eliminate such warnings, remove unnecessary checks which overload the code and confuse other programmers and the analyzer. In this case the analyzer will not issue the warning:
if ((var[0] = get_x()) == nullptr) {
return;
}
if (var[0]->data != 11) {
msg = 1;
printf("msg1");
}
if (var[0]->data == 12) {
msg = 2;
return;
}
If you don't want to remove this check, use one of the following ways to suppress warnings:
Suppression of false alarms
Mass Suppression of Analyzer Messages

Building simple unix shell problems

I am new with unix and I've got an assignemnt on college to build a simple shell in c with built in cd and kill command..
This is my code which is not working..tbh I dont understand it the best so Im not suprised it is not working.. can you help me with it? Also have no idea how I would implement kill command. thank you!
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024
const int ARGSIZE = 20;
void execute(char*args[])
{
int pid, status;
pid = fork();
if(pid<0)
{
perror("Error forking!");
}
else if(pid > 0)
{
while(wait(&status) != pid)
continue;
}
else if(pid == 0)
{
if (execvp(args[0], args) == -1)
{
perror("Error");
}
}
}
void cd(char*directory)
{
int ret = 0;
if(directory == '\0')
directory = getenv("HOME");
ret = chdir(directory);
if(ret != 0)
fprintf(stderr,"Failed to enter directory: %s\n",directory);
else
printf("%s\n",directory);
}
int main()
{
char line[BUF_SIZE];
char *args[ARGSIZE];
int argIndex = 0;
while(1){
printf("> ");
fgets(line, BUF_SIZE, stdin);
char *token;
token = strtok(line," ");
while(token!=NULL)
{
args[argIndex]=token;
token = strtok(NULL," ");
argIndex++;
}
args[argIndex]=NULL;
if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
break;
if(line== "\n")
printf("> ");
else if ((strcmp(args[0], "cd") == 0))
cd(args[1]);
else
execute(args);
}
return 0;
}
You were on the right track. There were a few subtle issues where you were not accounting for the trailing '\n' that would remain in line as the last character following whatever was entered at the prompt. Including " \n" in the delimiters used to tokenize the input with strtok will remove it, allowing valid strcmp comparisons with the final token (e.g. that is why quit and exit would not quit the application).
Other than than, there were several additional things you could do a little different/better, you could handle directories entered as e.g. '~/somedir', and similar additional checks that could be employed. I have notated most below as comments to the code.
Look over the changes below and let me know if you have any questions. There are always additional checks that can be added, etc.., but on balance your approach to the problem was pretty good. (note: some of the changes made were non-substantive, e.g. "shell> " as the prompt, instead of "> ". Just handle any of those as you wish.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
enum {ARGSIZE = 20, BUF_SIZE = 1024};
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1) {
argIndex = 0; /* reinitialize variables */
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> "); /* prompt */
if (fgets (line, BUF_SIZE, stdin) == NULL) {
printf ("EOF received\n");
return 0;
}
if (*line == '\n') /* Enter alone */
continue;
token = strtok (line, " \n"); /* add \n to delimiters */
while (token != NULL) {
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex) continue; /* validate at least 1 arg */
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
/* handle 'cd' or 'kill' separately */
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0)) {
if (args[1]) killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0) {
perror ("Error forking!");
return;
}
else if (pid > 0) {
while (wait (&status) != pid)
continue;
}
else if (pid == 0) {
if (execvp (args[0], args) == -1) {
perror ("Error");
}
_exit (EXIT_FAILURE);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory) { /* handle 'cd' */
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~') { /* handle cd ~/stuff */
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory)) /* handle given directory */
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1) {
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
// return kill (pid, sig);
return 0;
}
Sample Usage/Output
$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
killing pid '18004' with signal '15'
shell>
shell> quit

Sending child stdout to parent stdout

I am working on a simple application that takes the output from another one and writes it to a socket.
Below is the code for the application that I am execvp'ing
this code is called simple App
int main( int argc, char * argv[])
{
int count = 0;
while(count < 5)
//Attempt fork
if((pid2 = fork()) < 0) //Failed to fork
{
printf("\n Failed to fork in Dump \n");
exit(1);
}
else if (pid2 == 0) //Child Code
{
dup2(STDOUT_FILENO,pipefd[1]);
close(pipefd[0]);
close(STDOUT_FILENO);
if(execvp("../App/App", dumpParam) < 0) //execute the app; returns -1 if failed
{
printf("\nFailed to execute App\n");
exit(1);
}
}
else //Parent
{
close(pipefd[1]);
memset(buff,'0',sizeof(buff));
printf("here\n");
while( (r = read(pipefd[0],buff,sizeof(buff))) >= 0)
{
printf("\nSuccess in read r = %d\n",r);
printf("\nBuff = %s\n",buff);
memset(buff,'0',sizeof(buff));
}
printf("nowHere\n");
}
return pipefd[0];
so far when i run it, it prints out just a ton of 0's. if i set read > 0 then it doesn't run at all. Thoughts?
The read is returning 0 (end of file) because the child end of the pipe is closed.
You've got the dup2 the wrong way round, it should be
dup2(pipefd[1],STDOUT_FILENO)
also remove
close(STDOUT_FILENO)

Command Line Parameters Through WinMain and CommandLineToArgvW

I'm encountering a problem when trying to pass a parameter through my program via the command line (eg. -w 1280 -h 1024) while attempting to utilize WinMain. I've looked through every topic I could find, and have created code that builds and runs, but the parameters are ignored completely!
My Code:
LPWSTR *szArgList;
int argCount;
szArgList = CommandLineToArgvW(GetCommandLineW(), &argCount);
for(int i = 1;i < argCount;i++)
{
if(i + 1 != argCount)
{
if(szArgList[i] == L"-w")
{
width = _wtoi(szArgList[i+1]);
}
else if(szArgList[i] == L"-h")
{
height = _wtoi(szArgList[i+1]);
}
}
}
MSG msg;
BOOL done=FALSE;
if(MessageBox(NULL,"Fullscreen?", "my window", MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=FALSE;
}
if(!CreateGLWindow("Window",width,height,16,fullscreen))
{
return 0;
}
I'm attempting to pass it as "window.exe -w 800 -h 600" (without quotes, of course)
Anything i'm missing within my sleep-depraved code?
szArgList[i] == L"-w"
szArgList[i] == L"-h"
C and C++ will compare by pointer instead of character. use strcmp.

Resources