Skip to content

Latest commit

 

History

History
 
 

syscalls

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

#Syscalls and How to Use Them

Within this folder, you will find tutorials on functions that will be useful when programming your own shell. These functions are called system calls, or syscalls, and they differ from regular functions because a syscall requests a specific service from the operating system’s kernel.

All system calls will be described in their respective files, but there will be a brief description of what each does here. exec.md will explain system calls relating to exec and includes fork, wait, and exec. io.md will include system calls that relate to input and output redirection and include dup and pipe. Lastly, getinfo.md will include system calls that retrieve information about a process or environment variable. These include getcwd, getpwuid, and getgrgid.

exec: will execute a file

fork: will create a copy of the running process

wait: will wait for a child process and reap it

dup: creates a copy of a file descriptor

pipe: creates a pipe, or data channel for communication

getcwd: gets the current working directory

getpwuid: gets information about a passed in username

getgrgid: gets information about a group which matches a passed in group ID

The only function we will discuss in this README will be perror, an error checking function which should be used with every system call.

Syscalls might seem confusing to use but we’ll try our best to explain some of them in this list! If you want any more information we've included a link to the man page for each syscall.

##perror:

includes: #include <stdio.h>, #include <errno.h>

declaration: void perror(const char *s);

returns: No return value.

man page

The glorious error checker! perror is used when an error occurs in a syscall, and technically isn't a syscall - rather its used WITH every single syscall. The parameter of perror, const char *s, can be any c-string you wish to output when an error happens (examples below). perror will output the c-string you specify followed by information on the specific error that happened using information from errno. These are output to stderr so in the event that you mess up your standard output, stdout or cout, it will still print to the screen (unless you mess up your stderr too, then I'm sorry it won't help).

errno is a global int variable that is written to by system calls upon exiting (if it was successful, errno is still set, but to success), and will be set to a different value based on the reason the syscall failed. There is no need to try to remember the actual value for each error, perror will automatically print out the corresponding error based on the value of errno when it is called. If there is any reason that you need these values for checking why a system call failed, they are given as macros in the man page of the specific system call. Examples on the output will be shown in the example below.

For these reasons, perror is very useful when you’re debugging your program. It will give you not only your message which should indicate which system call failed, but also an error message from the system that is specified by errno. perror is extremely crucial while coding, and adding them after each syscall is considered proper coding etiquette - in fact, many instructors and professors may dock points for not having them (I was a "victim" of this my first assignment). The reason for this is because there are many reasons as to why a system call may fail and if you do not properly check each one, they can cause large and also confusing errors.

Now, we will show an example of perror with fork:

int pid = fork();
if(pid == -1)//fork’s return value for an error is -1
{
   //perror("There was an error with fork(). ");
   perror("fork"); //although you certainly can use the above, it is good
                   //practice not to write more information than necessary
   exit(1);//there was an error with fork so exit the program and go back and fix it
}
else if(pid == 0)//when pid is 0 you are in the child process
{
   cout<<"This is the child process ";
   exit(1);  //when the child process finishes doing what we want it to, cout, 
             //we want to kill the child process so it doesn’t go on in the program so we exit
}
//if pid is not 0 then we’re in the parent

So if fork fails, the output will look something like this:

fork: Resource temporarily unavailable

We can see that it outputs our char * appended by a : and then the error message from the system.

We use the if statement to see if our system call failed. Generally system calls will return -1 or NULL upon error depending on what data type they return. In this case, fork returns -1 so we check to see if it failed. If it did, then output an error message and exit the program. As you can see, we set our parameter for perror as simply, fork. This message can be customized however you desire. Additional useful information you can output is the function it’s in, the line it’s on in your code, among other things - the choice is yours! But beware, with great power comes great responsibility! Outputting error messages that are irrelevant or unnecessarily long are unlikely to be very helpful.