Message queues are one of the many ways of communicating among processes in linux.
Message queues communicate by sending and reciveing messages, over a common queue. The sender sends the message by writing to the queue and recieves by reading from the queue.
The following are some of the commonly used functions with respect to message queues.
To create or open a message queue we use the function mq_open:
Note: The description of the flags can be found in the man pages.
When a new message queue has to be created along with the above two argumetns these two are also mandatory
Retrun:
The function returns a data type mqd_t which is a descrpitor for the message queues. In case of a error it returns -1.
Setting and getting attributes :
The attributes of the message queue are stored in a structure mq_attr.
The fields of these structures can be read by using the function
To change the attributes of an already existing queue we can use the function
Sending and recieving messages :
Once the message queue is opened successfully, the process can communicate with the queue using the queue descriptor along with the functions mq_send to send a message and mq_recieve to recieve a message.
Sending:
Receieving:
Using the above set of functions we can set up a message queue and communicate between processes using them. In the next few posts we will see examples of how to use the above mentioned functions.
Pages
▼
Changing the font and background of a terminal
In almost all the linux distributions the default terminal that opens is with black text and white back ground or when you log into the text mode it would be black background with white font.
Not everyone is fond of such simple looks and if you are one of them then here are a few ways you can change that look.
Using GUI:
Go to edit->"Profile preferences" and from the tabs, color and background you can set the color for the text as well as the backgroud.
This is possible only when you are using the terminal in the GUI, but not when you log in using the text mode.
Here are two to modify the color of the font as well as the background, even when in the text mode .
tput:
To change the font run the command
e.g.:
This will make the font to appear in red. There are 8 possible colors for the 8 different numbers.
Similarly for changing the background color
e.g.:
This will set the background to green.
To make the font bold:
To go back to the default colors run the command
setterm:
This command does not work in the GUI but works in the text mode.
To change the color of the font pass the option forground to the command
Where the color could be one of the following :
black, red, green, yellow, blue,magenta, cyan, or white
e.g.:
Similarly to change the background of the font pass the option "background" with the color.
e.g.:
To make the font bold
To go back to the default settings
Not everyone is fond of such simple looks and if you are one of them then here are a few ways you can change that look.
Using GUI:
Go to edit->"Profile preferences" and from the tabs, color and background you can set the color for the text as well as the backgroud.
This is possible only when you are using the terminal in the GUI, but not when you log in using the text mode.
Here are two to modify the color of the font as well as the background, even when in the text mode .
tput:
To change the font run the command
e.g.:
This will make the font to appear in red. There are 8 possible colors for the 8 different numbers.
Similarly for changing the background color
e.g.:
This will set the background to green.
To make the font bold:
To go back to the default colors run the command
setterm:
This command does not work in the GUI but works in the text mode.
To change the color of the font pass the option forground to the command
Where the color could be one of the following :
black, red, green, yellow, blue,magenta, cyan, or white
e.g.:
Similarly to change the background of the font pass the option "background" with the color.
e.g.:
To make the font bold
To go back to the default settings
Creating a template for text files with some default text
Very often while writing programs or text documents, we use a certain content in every file we write. For eg almost every "c" file has the following lines
To avoid typing this repeatedly we can create a template which we can use to intialize our file with the default text.
Here are a two ways we can do it using shell scripting.
1. Taking the same example of a "c" file as above we can create a script as below
In the above script the first set of echo commands are for the text we want our text file to have.
Let us call this script as template.sh
To this script we will pass the new file name which we want to create and use the "vi" editor to open it for editing.
To open a file by the name test having the required contents already entered i in it run the script as follows.
You should see a new file opened in the vi editor with the following contents.
2. The second way doing the same, especially when the text to be entered is more than a few lines we can create a file that has the required text and use the same to create the new file.
For eg:
Let us create a new file called "template" and put the required contetns into it
template:
Let us say the above file is saved at the location /home/user/template.
We can use this file as shown in the script below
save the script as template2.sh and execute it as follows
A new file by the name test should get created which has the contents of the file template in it.
Below is a script that combines the above two into one, and makes it more dynamic such that it is able to create any number of files whose names are passed on the command line .
template.sh:
To make this command work from any terminal you want, copy this script to /usr/bin as follows
Note: This will prompt for your password and you will be able to execute this only if you have root permissions.
If that is successful, you can call this command from any where in the system and create ths files with default text in it, all you have to do is modify the script with the text that you want.
To avoid typing this repeatedly we can create a template which we can use to intialize our file with the default text.
Here are a two ways we can do it using shell scripting.
1. Taking the same example of a "c" file as above we can create a script as below
In the above script the first set of echo commands are for the text we want our text file to have.
Let us call this script as template.sh
To this script we will pass the new file name which we want to create and use the "vi" editor to open it for editing.
To open a file by the name test having the required contents already entered i in it run the script as follows.
You should see a new file opened in the vi editor with the following contents.
2. The second way doing the same, especially when the text to be entered is more than a few lines we can create a file that has the required text and use the same to create the new file.
For eg:
Let us create a new file called "template" and put the required contetns into it
template:
Let us say the above file is saved at the location /home/user/template.
We can use this file as shown in the script below
save the script as template2.sh and execute it as follows
A new file by the name test should get created which has the contents of the file template in it.
Below is a script that combines the above two into one, and makes it more dynamic such that it is able to create any number of files whose names are passed on the command line .
template.sh:
To make this command work from any terminal you want, copy this script to /usr/bin as follows
Note: This will prompt for your password and you will be able to execute this only if you have root permissions.
If that is successful, you can call this command from any where in the system and create ths files with default text in it, all you have to do is modify the script with the text that you want.
Running shell commands from the vi editor
If you are fond of vi editor or use it a lot because you have to, here is small tip that might be helpful.
We can execute the shell commands while working with the editor. To this go the command mode by pressing "esc" and to execute a shell command first type ":!" and then the command.
Let us say we want to look at the contents of the current working directory with out exiting the editor then we can do it as follows
We can execute the shell commands while working with the editor. To this go the command mode by pressing "esc" and to execute a shell command first type ":!" and then the command.
Let us say we want to look at the contents of the current working directory with out exiting the editor then we can do it as follows
Inter process communication using named pipes(FIFO) in linux
In the last post we saw the how to create pipes for communication between processes in linux.
One of the major disadvantage of pipes is that the they can not be accesed using their names by any other process other than child and the parent as they do not get listed in the directory tree.
The work around for this porblem is to create a named pipe which is also called as a FIFO, which stands for First in First out, meaning the data that is written into the pipe first will be read out first always.
The fifos get listed in the directory tree and any process can access it using its name by providing the approproiate path.
fifo are created using the function mkfifo() which takes as arguments
1. The name of the fifo that has to be created
2. The permissions for the file.
Once the file is created, it needs to be opened using the system call open() and the data can be read and written from the file using read() and write system calls.
One of the examples you can think of using a named pipe is communication between a server and a client. If ther are two fifos one of the server and the other of the client, then the client can send request to the server on the server fifo which the server will read and respond back with the reply on the client's fifo.
Another advantage of a fifo over the pipes is that fifo are birectoinal, that is the same fifo can be read from as well and written into.
Here is an example the demostrates the working of fifos.
First we will create two fifos one called the server and the other called the client.
create_fifo.c:
Save the above program as create_fifo.c and compile is using gcc as follows
If the compilation is successfull, run the program as follows
If there are no errors, then two fifo should have got created in your current working directory. To confirm this run the command the "ls -l" in your current workind directory and you should see some thing like this.
If you notice the first column of the row containing fifo_server and fifo_client, you can see the letter "p" which signifies that it is a pipe.
Now to use these pipes, we will write two program's one to represent the server and other to represent the client. The server will read from the pipe fifo_server to which the client will send a request. On reciveing the request, the server will send the information to the client on fifo_client.
server.c
The above code,server.c, reads the choice from fifo_server to which the client writes and depending on the request,the server responds with the relevant data by writing to fifo_client.
Save the file and server.c and compile it as follows
client.c:
The above code,client.c, sends a request to the server by writing to the pipe fifo_server, and recieves the reply from the server by reading the pipe fifo_client.
Save the file and server.c and compile it as follows
To see the pipe in operation, open two terminals and go the folder where the pipes have been created.
Note: The server.c and client.c codes assume that the pipes exist in the same directory as the executables of server and client are, if they exist in any other directory you will have to provide the path to the same in the system call open().
Terminal 1:
The terminal will go into a wait state with the cursor blinking, waiting for request from client.
Terminal 2:
The client will prompt to make a choice of request to be sent to the server, enter number 1,2 or 3
This number will be sent to the server and the client will go into a wait state, waiting for the server to respond.
After a few seconds you should see the reponse from the server being printed on the client terminal.
Note: wait for 10 seconds for the output to appear as the server has a sleep for 10 seconds, this is required to allow some time for the client to start its read operation on the fifo_client pipe.
for eg if we entered option 2, the response would be
output on client terminal:
Ouput on server terminal :
Thus we were able to communicate between the two processes using the fifos, even though the pipes were not created by them.
To use the pipes with out writing the server and client code we can use "cat" and "echo" commands.
Terminal 1:
Terminal 2:
We should be able to see the "hello world" being printed on the Terminal 1.
One of the major disadvantage of pipes is that the they can not be accesed using their names by any other process other than child and the parent as they do not get listed in the directory tree.
The work around for this porblem is to create a named pipe which is also called as a FIFO, which stands for First in First out, meaning the data that is written into the pipe first will be read out first always.
The fifos get listed in the directory tree and any process can access it using its name by providing the approproiate path.
fifo are created using the function mkfifo() which takes as arguments
1. The name of the fifo that has to be created
2. The permissions for the file.
Once the file is created, it needs to be opened using the system call open() and the data can be read and written from the file using read() and write system calls.
One of the examples you can think of using a named pipe is communication between a server and a client. If ther are two fifos one of the server and the other of the client, then the client can send request to the server on the server fifo which the server will read and respond back with the reply on the client's fifo.
Another advantage of a fifo over the pipes is that fifo are birectoinal, that is the same fifo can be read from as well and written into.
Here is an example the demostrates the working of fifos.
First we will create two fifos one called the server and the other called the client.
create_fifo.c:
Save the above program as create_fifo.c and compile is using gcc as follows
If the compilation is successfull, run the program as follows
If there are no errors, then two fifo should have got created in your current working directory. To confirm this run the command the "ls -l" in your current workind directory and you should see some thing like this.
If you notice the first column of the row containing fifo_server and fifo_client, you can see the letter "p" which signifies that it is a pipe.
Now to use these pipes, we will write two program's one to represent the server and other to represent the client. The server will read from the pipe fifo_server to which the client will send a request. On reciveing the request, the server will send the information to the client on fifo_client.
server.c
The above code,server.c, reads the choice from fifo_server to which the client writes and depending on the request,the server responds with the relevant data by writing to fifo_client.
Save the file and server.c and compile it as follows
client.c:
The above code,client.c, sends a request to the server by writing to the pipe fifo_server, and recieves the reply from the server by reading the pipe fifo_client.
Save the file and server.c and compile it as follows
To see the pipe in operation, open two terminals and go the folder where the pipes have been created.
Note: The server.c and client.c codes assume that the pipes exist in the same directory as the executables of server and client are, if they exist in any other directory you will have to provide the path to the same in the system call open().
Terminal 1:
The terminal will go into a wait state with the cursor blinking, waiting for request from client.
Terminal 2:
The client will prompt to make a choice of request to be sent to the server, enter number 1,2 or 3
This number will be sent to the server and the client will go into a wait state, waiting for the server to respond.
After a few seconds you should see the reponse from the server being printed on the client terminal.
Note: wait for 10 seconds for the output to appear as the server has a sleep for 10 seconds, this is required to allow some time for the client to start its read operation on the fifo_client pipe.
for eg if we entered option 2, the response would be
output on client terminal:
Ouput on server terminal :
Thus we were able to communicate between the two processes using the fifos, even though the pipes were not created by them.
To use the pipes with out writing the server and client code we can use "cat" and "echo" commands.
Terminal 1:
Terminal 2:
We should be able to see the "hello world" being printed on the Terminal 1.
Making the home directory as the desktop
By default in all linux distributions the Desktop that is displayed is the contents of the folder Desktop under the home directory of the user.
If you are using a gnome desktop and using nautilus you can change this and make the contents of the your home folder be displayed on the desktop.
To do this open the terminal and type
gconf-editor /apps/nautilus/preferences/desktop_is_home_dir
You should see a window pop up as shown below.
In the line highlighted in the right frame of the window, check the option desktop_is_home_dir and then click on File->Quit
That should change your desktop to the home folder .
If you are using a gnome desktop and using nautilus you can change this and make the contents of the your home folder be displayed on the desktop.
To do this open the terminal and type
gconf-editor /apps/nautilus/preferences/desktop_is_home_dir
You should see a window pop up as shown below.
In the line highlighted in the right frame of the window, check the option desktop_is_home_dir and then click on File->Quit
That should change your desktop to the home folder .
Switching between terminal tabs
If you are some one who uses terminal a lot and are used to opening more than a few tabs of terminals at time, here is simple way of switching between the terminals with out touching the mouse.
Alt + 1 will take you to the first tab of terminal, Alt + 2 will take you to the second tab of terminal and so on.
Another way of doing it is cntrl + pgup will take you to thee previous terminal and cntrl + pgdn will take you to the next terminal.
Alt + 1 will take you to the first tab of terminal, Alt + 2 will take you to the second tab of terminal and so on.
Another way of doing it is cntrl + pgup will take you to thee previous terminal and cntrl + pgdn will take you to the next terminal.
Inter process communication using pipes in linux
Linux provides many ways for processes to communicate with each other. One of them is using pipes.
Like a pipe that carries water in which water enters from one end and exits from the other, in linux pipes data enters from one end and exits from the other.
Pipes are created using the system call pipe() and the system calls read() and write() are used to read and write from the pipe. The c library in linux provides wrappers around these system calls which make their use much easier.
The function popen() is a wrapper for pipe, which allows us to create a pipe and read or write from it using c fuctions like fprintf,fscanf etc
popen :
Arguments : 1. command that will be executed by the child process.
2. The type of communication by the parent, i.e. whether the parent is going to read from the pipe or write into the pipe.
Return : It returns a file descriptor that gets created as a result of th call to the pipe.
Operation:
The open() system call creates a pipe and returns two file descriptors, one that can be used to read from the pipe and one that can be used to write into the pipe. This can be visualized as follows
The popen function which recives these two descriptors decides the next step based on whether the process requested for a read or write operation from the pipe. That is the whether the second arguement to the pipe was "r" or "w"
If the second argument was "r" that is the process is going to read from the pipe then the write file descriptor is changed to that of the standard output. Which means when the output of "command", which was passed as the first argument to open, instead of being printed on the standard output will now be sent into the pipe, which can be later read by using fscanf . Thus the child is able to send data through the pipe to the parent process, achieveing the commnicatio between processes.
Here is a example that shows how to open a pipe in read mode pipe_read.c The above program opens the pipe in read mode, hence the process is going to read from the pipe, and write to the other end of the pipe which will be the standard output as exaplined above.
The command that the child process is going to execute is "echo hello world" which will be read by the parent process . The popen() returns a file descriptor which can be used to read from the pipe using the function fscanf() ,which reads from a file.
Thus we run a while loop till the end of file is reached and keep reading the contents of the file into a string, which is turn is printed on to the standard output to see what was the string read from the pipe.
compile the code using the gcc compiler as shown below
Output:
The command "echo hello world" wrote "hello world" into the pipe, the same was read out using the file descriptor returned by popen.
If second argument was "w" that is the process is going to write into the pipe then the read file descriptor is changed to standard input. Which means what ever we write into the pipe will act as an input to the command that was passed in the first argument to popen. Thus the parent is able to send data to the child through the pipe, achieveing the commnicatio between processes.
Here is a example that shows how to open a pipe in write mode
pipe_write.c
The above program opens the pipe in write mode. The command that the child is executing is "wc -c" which counts the number of characters in the input file passed to it. As the pipe has been opened in write mode, that is the parent is going to write into the pipe, the child will read the data that the parent wrties. Hence what ever is printed into the file, using the file descriptor returned by popen() will be passed to "wc -w" as input which will count the number of characters and give the output on the standard output.
save the file as pipe_write.c. Compile it using gcc and execute is as follows.
Output:
There are 11 characters in the string "hello world" including the blank space, hence we see the output 11.
Like a pipe that carries water in which water enters from one end and exits from the other, in linux pipes data enters from one end and exits from the other.
Pipes are created using the system call pipe() and the system calls read() and write() are used to read and write from the pipe. The c library in linux provides wrappers around these system calls which make their use much easier.
The function popen() is a wrapper for pipe, which allows us to create a pipe and read or write from it using c fuctions like fprintf,fscanf etc
popen :
Arguments : 1. command that will be executed by the child process.
2. The type of communication by the parent, i.e. whether the parent is going to read from the pipe or write into the pipe.
Return : It returns a file descriptor that gets created as a result of th call to the pipe.
Operation:
The open() system call creates a pipe and returns two file descriptors, one that can be used to read from the pipe and one that can be used to write into the pipe. This can be visualized as follows
The popen function which recives these two descriptors decides the next step based on whether the process requested for a read or write operation from the pipe. That is the whether the second arguement to the pipe was "r" or "w"
If the second argument was "r" that is the process is going to read from the pipe then the write file descriptor is changed to that of the standard output. Which means when the output of "command", which was passed as the first argument to open, instead of being printed on the standard output will now be sent into the pipe, which can be later read by using fscanf . Thus the child is able to send data through the pipe to the parent process, achieveing the commnicatio between processes.
Here is a example that shows how to open a pipe in read mode pipe_read.c The above program opens the pipe in read mode, hence the process is going to read from the pipe, and write to the other end of the pipe which will be the standard output as exaplined above.
The command that the child process is going to execute is "echo hello world" which will be read by the parent process . The popen() returns a file descriptor which can be used to read from the pipe using the function fscanf() ,which reads from a file.
Thus we run a while loop till the end of file is reached and keep reading the contents of the file into a string, which is turn is printed on to the standard output to see what was the string read from the pipe.
compile the code using the gcc compiler as shown below
Output:
The command "echo hello world" wrote "hello world" into the pipe, the same was read out using the file descriptor returned by popen.
If second argument was "w" that is the process is going to write into the pipe then the read file descriptor is changed to standard input. Which means what ever we write into the pipe will act as an input to the command that was passed in the first argument to popen. Thus the parent is able to send data to the child through the pipe, achieveing the commnicatio between processes.
Here is a example that shows how to open a pipe in write mode
pipe_write.c
The above program opens the pipe in write mode. The command that the child is executing is "wc -c" which counts the number of characters in the input file passed to it. As the pipe has been opened in write mode, that is the parent is going to write into the pipe, the child will read the data that the parent wrties. Hence what ever is printed into the file, using the file descriptor returned by popen() will be passed to "wc -w" as input which will count the number of characters and give the output on the standard output.
save the file as pipe_write.c. Compile it using gcc and execute is as follows.
Output:
There are 11 characters in the string "hello world" including the blank space, hence we see the output 11.
Changing the cursor style of the terminal
The default style of the cursor in the terminal of most distros is a big blinking block. This can be changed to either just a underline or a thinner block as follows.
-> open a terminal
-> run the command
gconf-editor /apps/gnome-terminal/profiles/Default/cursor_shape
-> In the window that will pop out , look at window on the right. The highlighted line will have cursor_shape in the first column and the value "block" in the second column.
-> To change this, click on the second column and enter the value "underline" to have the cursor as an underline or enter "ibeam" to use a vertical line cursor.
-> Hit the enter key after entering the new value
-> click on file and quit.
Your terminal cursor would have changed to what ever new value you chose.
-> open a terminal
-> run the command
gconf-editor /apps/gnome-terminal/profiles/Default/cursor_shape
-> In the window that will pop out , look at window on the right. The highlighted line will have cursor_shape in the first column and the value "block" in the second column.
-> To change this, click on the second column and enter the value "underline" to have the cursor as an underline or enter "ibeam" to use a vertical line cursor.
-> Hit the enter key after entering the new value
-> click on file and quit.
Your terminal cursor would have changed to what ever new value you chose.
Writing an example driver from scratch : Chapter -6
In the previous five chapters we walked through the steps of writing an simple charcater driver and for a virtual device and accessing it from the user space.
The limitation of driver written was it could not read using cat command . This was because the return value of the read function was not appropriate for the cat function.
The cat command continues to read from a file unless it is not informed that there is no further data to be read from the file, which is done by returning 0 when the end of file is reached.
To do this in our read function we have to keep count of the number of bytes that are written into the device. Hence we add a variable "written" into the write function which gets updated when data is written in to the device as follows
written = written + count ;
This value of written is assigned to another variable "read" every time device is opened. When the read function is called the variable "read" is compared with the variable "count", which indicates the number of bytes that the userspace wants to read. In case the count value is more than read, then we have to decrease the value of count to the amount of data present in the device i.e
if ( count > read)
count = read
And on every pass through the read function we keep decreasing the value of read by the count number of bytes that are read, and return the value of read.
Thus when end of file is reached the value of read becomes zero which when returned to cat, it would stop reading from the file.
Here is the drive code with the modified read and write functions. The steps to compile and insert the device are the same as in chapter-4
Note: The code has been tested and found working on kernel version 4.6
Assuming we have created a device by the name /dev/temp, we can communicate with the device as follows
$ echo "hi" > /dev/temp
$ cat /dev/temp
hi
Or we can use the user application code as show in chapter-5
The limitation of driver written was it could not read using cat command . This was because the return value of the read function was not appropriate for the cat function.
The cat command continues to read from a file unless it is not informed that there is no further data to be read from the file, which is done by returning 0 when the end of file is reached.
To do this in our read function we have to keep count of the number of bytes that are written into the device. Hence we add a variable "written" into the write function which gets updated when data is written in to the device as follows
written = written + count ;
This value of written is assigned to another variable "read" every time device is opened. When the read function is called the variable "read" is compared with the variable "count", which indicates the number of bytes that the userspace wants to read. In case the count value is more than read, then we have to decrease the value of count to the amount of data present in the device i.e
if ( count > read)
count = read
And on every pass through the read function we keep decreasing the value of read by the count number of bytes that are read, and return the value of read.
Thus when end of file is reached the value of read becomes zero which when returned to cat, it would stop reading from the file.
Here is the drive code with the modified read and write functions. The steps to compile and insert the device are the same as in chapter-4
Note: The code has been tested and found working on kernel version 4.6
Assuming we have created a device by the name /dev/temp, we can communicate with the device as follows
$ echo "hi" > /dev/temp
$ cat /dev/temp
hi
Or we can use the user application code as show in chapter-5