You are on page 1of 11

Buffered & Unbuffered IO Calls As we know, C library provides two sets of IO calls.

. One of them works at lower level and have no explicit means of buffering any read and write. It is used in byte oriented operations, buffering if any has to be provided for by the user. Example of these are read(), write(), open(), close() etc. The other set works at higher level and provides for buffering, better error control and better efficiency by doing IO in a block-oriented manner. The block size is defined based on the device. Example of these calls are fread(), fwrite(), fopen(), fclose(), fflush() etc. In normal programming by end users these are the recommended calls. In some implementations, these calls may internally use their unbuffered variants Expect similar differentiation in pipe calls as well pipe() call works at lower level for unbuffered IO whereas popen() and pclose() are its buffered equivalents. Pipe() call Pipe() call is at a lower level than popen() and allows two related processes to communicate data between them Unlike popen() where the shell features are invokes, and this is a major overhead, pipe() is more economical in terms of resource usage Pipe() also provides more granular control over the read and write ends of the pipe created Prototype of pipe() is # include <unistd.h> #int pipe (int fd[2]); A call to pipe() passes a pointer to an array of 2 file_descriptors(fd) and on return the array has two valid fds created. On success it returns 0. On failure it returns -1 and sets the global variable errno to predefined diagnostic messsage like EMFILE, ENFILE OR EFAULT. Two file_descriptors of pipe() These two fd*0+ and fd*1+ are connected in a special way. Any data written to fd[1] can be read back from fd[0]. Data is processed on a FAST_IN_FIRST_OUT (FIFO) mode. It is a perfectly serial way of data ordering Read and Write operations using fd*0+ and fd*1+ requires one to use low level calls read() and write() Be aware that in many implementations reading from fd*1+ and writing to fd[1], even if allowed may result in unpredictable results. So stick to fd[0] for read and fd[1] for write Recollect that when we use fork() for creating a child proces s, the child inherits all open file_descriptors. Hence, if we have created a pipe setup using pipe(), then fd[0] and fd[1] are available to both parent and child. Serialized communication between these two related processes can be done by suitably piping data between fd[1] and fd[0] by relating one of these to the parent and other to the child. If the parent writes to fd[1] then child can get it by reading fd[0] and thus a neat data flow from parent to

child is established

Unix/Linux Architecture - Shell is a layer above Kernel and provides the most traditional user interface across most UNIX/Linux implementations - Most UNIX/Linux commands are designed to run within the shell and interplay What is Shell? User Interface: takes commands from user Command Interpreter uses them as you type (at the command line) and executes them appropriately Shell can also take scripts (shell programs) and run either interactively or in silent mode Shell allows Customization of a Unix/Linux session Scripting either one-time use or stored programs and procedures Shell programming is pretty similar to other structured programming languages of course with some new freaks Copyright DKES School of Computer Science 7 Types of Shells Interactive vs. Non-interactive (login or not) Interactive login shell started after login Non-interactive shell Present when shell script is running Still inherits much of parents environment variables etc. Interactive non-login shell started Started from a command line Copies parent environment then invokes ~/.bash_rc (or ~/.cshrc or ~/.tcshrc) Possible to use a restricted version of the shell (restricted shell) where the user is allowed to work with a subset of Linux commands only and may not have even the ability to change directory. It is used as a part of secure / monitored computing practice 8 Popular Shells Bourne Shell

-Again Shell

#!/bin/bash # Start the script with any number of arguments echo " Name of Script is = $0" echo " Argument List is = $*" echo " Argument List is = $@" echo " Number of Arguments = $#" echo " Process-id of the script = $$" echo " Return Value at this point = $?" exit 0 #End of Script #!/bin/bash # Run the script with 3 args filenames for i in $@ do echo if [ -f $i ] then echo "Processing the File = $i" NoChars=`wc -c $i | cut -c1-4` NoWords=`wc -w $i | cut -c1-3` NoLines=`wc -l $i | cut -c1-2` echo "This File has $NoChars characters" echo "This File Has $NoWords Words" echo "This File Has $NoLines Lines" else echo File $i is either non-existent or not regular fi done exit 0 #End of Script #!/bin/bash ## Try to enter the correct word (secret) ## While Loop continues till you give a different string that ## is incorrect echo echo -n "Enter your Password : " read myinput while [ "$myinput" != "secret" ] do echo "Sorry - Word not matched - Try again" echo echo -n "Enter your Password : " read myinput done echo exit 0 #End of Script

#!/bin/bash ## Demonstrate the use of case construct ## echo echo -n "Is it morning? Please answer in yes or no : " read myinput case "$myinput" in yes | Yes | YES) echo "Good Morning";; No | NO | no ) echo "Good Afternoon";; y | Y ) echo "Good Morning";; n | n ) echo "Good Afternoon";; * ) echo "No valid Input";; esac echo exit 0 #End of Script #!/bin/bash ## Demonstrate the use of function() value1="global" cur_time=`date` echo "Current Time = $cur_time # # Space for function yes_no() # sleep 5 if yes_no "$1" then echo "$value1 - Hi $1, you have a nice name" else echo "$value1 - Not sure - Try Again" fi echo "Current Time = $cur_time" exit 0 #End of Script #!/bin/bash ## Demonstrate arithmetic calculations x=10; y=25; z=100; pi=3.14 echo x + y echo $x + $y total=`expr $x + $y ` diff=`expr $x - $y` product=`expr $x \* $y` dividend=`expr $y / $x` modulus=`expr $y % $x` echo " Operands are $x and $y " echo " Total = $total Diff = $diff " echo " Product= $product \ Dividend = $dividend" echo " Modulus= $modulus" echo exit 0 #End of Script

#!/bin/bash ## Demonstrate Logical operations # Logical Returns 1 if true, 0 if false, echo "Logical Operators" echo x=24; y=25 b=`expr $x = $y` # Test equality. echo "b = $b" # 0 ( $x -ne $y ) echo a=3; b=`expr $a \> 10` echo 'b=`expr $a \> 10`, therefore...' echo "If a > 10, b = 0 (false)" echo "b = $b" # 0 ( 3 ! -gt 10 ) echo b=`expr $a \<= 10` echo "If a <= 10, b = 1 (true)" echo "b = $b" # 1 ( 3 -le 10 ) exit $? #End of Script #!/bin/bash echo "String Operators" echo a=1234zipper43231 echo "The string being operated upon is \"$a\"." b=`expr length $a` echo "Length of \"$a\" is $b." # index: position of 1st char in substring matching in string b=`expr index $a zi` echo "Numerical position of first \"zi\" in \"$a\" is \"$b\"." # substr: extract substring, starting position & length specified b=`expr substr $a 2 6` echo "Substring of \"$a\", start at pos 2 and len=6 is \"$b\"." # Using Regular Expressions ... b=`expr match "$a" '[0-9]*'` echo Number of digits at the beginning of \"$a\" is $b. b=`expr match "$a" '\([0-9]*\)'` echo "The digits at the beginning of \"$a\" are \"$b\"." echo #End of Script Common Filters er) are Used for identifying filenames, strings and other contents in typically text oriented scenarios Find Grep sed awk used stand-alone or be a part of a pipe. Can be used in command line as well as a part of scripts Start a New Process A new process is typically the instance of a program in

execution. A program is an executable file in a.out format, on a Linux machine they are ELF (Extended Library Format) binaries Most commands on a Linux machine are in this category There are three ways by which you can create a new process from within a running C program. They are System(command_name) statement Fork() call Exec () call Start a new Process by system() #include <stdio.h> #include <unistd.h> main () {{ printf("\n About to start the call to system() \n\n"); system("/usr/bin/wc /home/pkm/mca301/proc_signal/cal2013"); printf("\n This line prints after the call to system() \n"); }} Start a new Process by fork() #include <stdio.h> #include <unistd.h> int main () { int pid1, pid2; printf("Before fork() \n\n"); fflush (stdout); pid1 = fork(); if (pid1 != 0) { printf("I am Parent_Process and my Child_Proces PID is %d\n",pid1); fflush(stdout); } else { printf("========= I am the Child_Process =========\n"); fflush(stdout); } printf("Process Ends.\n\n"); fflush(stdout); } exec Function calls t begins / spawns a process execution based on the command name and arguments to thereof the calling process. Hence after exec() call there is still one running process (unlike fork() ). Note that in the calling program all code lines after exec() will never get executed from the parent process. Use the one most suits needs

execv Function calls (another variant of exec() call - path: directory path to executable image. Can be your program, a command on your system . Typically in a.out format - argv: Array of pointers to null terminated strings. These are arguments to the program to be executed. The last argument is 0. his is similar to the parsing of the command line arguments in a typical C Program Starting process by execl() #include <stdio.h> #include <unistd.h> main () {{ int pid, i; char *args[3]; pid = fork(); if (pid ==0) { execl("/usr/bin/wc","/home/pkm/mca301/proc_signal/cal2013",0); printf("\n This line may not print after exec call \n"); } else printf ("\n Parent Process Ends.\n"); }} Starting another process by execl() #include <stdio.h> #include <unistd.h> main () {{ int pid, i; char *args[3]; pid = fork(); if (pid ==0) { execl("/usr/bin/who", 0); printf("\n This line may not print after exec call \n"); } else printf ("\n Parent Process Ends.\n"); }}

Parent process waiting for a child to Exit #include <stdio.h> #include <unistd.h> main () { int pid, status; if(fork()) { printf("\nI am Parent - Starting to wait.\n"); fflush(stdout); pid = wait(&status); printf("\nI am Parent - my child's PID is %d - exit status is %d\n", pid, status); } else { sleep (2); // without this line child starts before parent. printf("\nI am Child - Going for a small nap.\n"); fflush(stdout); sleep(10); printf("\nI am Child, Woke up after a nap and Exiting.\n"); fflush(stdout); exit(0); } } This program shows how a parent process is waiting for a child process to complete a task and report back its status in certain ways . It is done by using the wait() call. This approach should work In most of the cases. But be careful if there are multiple child processes. The order in which child processes communicate with the parent may also be a bit indeterminate leading to unexpected results. What is a signal? Signals are software interrupts. It can also be considered a way of communicating between two running processes Signals are a way to deliver asynchronous events to the application. Events such as CTRL-C, hardware exceptions, resource limits, time alarms etc. Most of these signals that are relevant to an implementation are defined in header files particularly <signal.h>. Has been with UNIX for a long time Note that every signal has a name that begins with characters SIG and has a unsigned integer assigned to it. Typically signal numbers 1 through 9 are same in practically all UNIX and Linux implementations. SIGINT signal that is generated when a user presses CTRL-C. This is the way to terminate programs from terminal. Another signal SIGQUIT CTRL-\ makes any running program to quit/terminate without fail. Below is a list of other signals SIGALRM generated when the timer set by alarm function goes off. SIGKILL Kill Signal SIGSTOP Stop Signal SIGFPE Floating Point Exceptions like division by 0

Signal Handler When the signal occurs, the process has to tell the kernel what to do with it. Usually the default behaviour of all defined signals is assigned when a process starts. There are 3 ways in which a process may react to a signal. o The signal can be ignored. By ignoring we mean that nothing will be done when signal occurs. Most of the signals can be ignored but signals generated by hardware exceptions like divide by zero, if ignored can have weird consequences. Also, a couple of signals like SIGKILL and SIGQUIT cannot be ignored. o The signal can be caught. When this option is chosen, then the process registers a function called signal handler. This function is called invoked when that signal occurs. If the signal is non-fatal for the process the function can be used for defining how the process handles the signal o Let the default action apply. Every signal has a default action. This could be process terminate, ignore etc. Default action is defined at the start of the process. It can also be set in the middle of a process Some signals SIGKILL and SIGQUIT cannot be ignored. This is because they provide ways to kill or stop any process in any situation .The default action of these signals is to terminate the process.

Most famous and popular shells sh: The Bourne shell (obsolete) Traditional, basic shell found on Unix systems, by Steve Bourne. csh: The C shell (obsolete) Once popular shell with a C-like syntax tcsh: The TC shell (still very popular) A C shell compatible implementation with evolved features (command completion, history editing and more...) bash: The Bourne Again shell (most popular) An improved implementation of sh with lots of added features too.

fish: a great new shell The Friendly Interactive Shell Standard features: history, command and file completion... Brand new features: command option completion, command completion with short description, syntax highlighting.. Easier to any open files: open built-in command. Much simpler and consistent syntax (not POSIX compliant) Makes it easier to create shell scripts.