Monday, January 16, 2012

C Arrays Basics Explained with 13 Examples

This article is part of our on-going C programming series.
There are times while writing C code, you may want to store multiple items of same type as contiguous bytes in memory so that searching and sorting of items becomes easy. For example:
  1. Storing a string that contains series of characters. Like storing a name in memory.
  2. Storing multiple strings. Like storing multiple names.
C programming language provides the concept of arrays to help you with these scenarios.

1. What is an Array?

An array is a collection of same type of elements which are sheltered under a common name.
An array can be visualised as a row in a table, whose each successive block can be thought of as memory bytes containing one element. Look at the figure below :
An Array of four elements:
| elem1     |  elem2      | elem3      | elem4      |
The number of 8 bit bytes that each element occupies depends on the type of array. If type of array is ‘char’ then it means the array stores character elements. Since each character occupies one byte so elements of a character array occupy one byte each.

2. How to Define an Array?
An array is defined as following :
  • type-of-array: It is the type of elements that an array stores. If array stores character elements then type of array is ‘char’. If array stores integer elements then type of array is ‘int’. Besides these native types, if type of elements in array is structure objects then type of array becomes the structure.
  • name-of-array: This is the name that is given to array. It can be any string but it is usually suggested that some can of standard should be followed while naming arrays. At least the name should be in context with what is being stored in the array.
  • [number of elements]: This value in subscripts [] indicates the number of elements the array stores.
For example, an array of five characters can be defined as :
char arr[5];

3. How to Initialize an Array?

An array can be initialized in many ways as shown in the code-snippets below.
Initializing each element separately. For example :
int arr[10];
int i = 0;
Initializing array at the time of declaration. For example :
int arr[] = {'1','2','3','4','5'};
In the above example an array of five integers is declared. Note that since we are initializing at the time of declaration so there is no need to mention any value in the subscripts []. The size will automatically be calculated from the number of values. In this case, the size will be 5.
Initializing array with a string (Method 1):
Strings in C language are nothing but a series of characters followed by a null byte. So to store a string, we need an array of characters followed by a null byte. This makes the initialization of strings a bit different. Let us take a look :
Since strings are nothing but a series of characters so the array containing a string will be containing characters
char arr[] = {'c','o','d','e','\0'};
In the above declaration/initialization, we have initialized array with a series of character followed by a ‘\0′ (null) byte. The null byte is required as a terminating byte when string is read as a whole.
Initializing array with a string (Method 2):
char arr[] = "code";
Here we neither require to explicitly wrap single quotes around each character nor write a null character. The double quotes do the trick for us.

4. Accessing Values in an Array

Now we know how to declare and initialize an array. Lets understand, how to access array elements. An array element is accessed as :
int arr[10];
int i = 0;
As we can see above, the 5th element of array is accessed as ‘arr[5]‘.
Note that for an array declared as int arr[5]. The five values are represented as: arr[0] arr[1] arr[2] arr[3] arr[4] and not arr[1] arr[2] arr[3] arr[4] arr[5]
The first element of array always has a subscript of ’0′

5. Array of Structures

The following program gives a brief idea of how to declare, initialize and use array of structures.

struct st{
    int a;
    char c;

int main()
    struct st st_arr[3]; // Declare an array of 3 structure objects 

    struct st st_obj0; // first structure object
    st_obj0.a = 0;
    st_obj0.c = 'a'; 

    struct st st_obj1; //Second structure object
    st_obj1.a = 1;
    st_obj1.c = 'b'; 

    struct st st_obj2; // Third structure object
    st_obj2.a = 2;
    st_obj2.c = 'c'; 

    st_arr[0] = st_obj0; // Initializing first element of array with first structure object
    st_arr[1] = st_obj1; // Initializing second element of array with second structure object
    st_arr[2] = st_obj2; // Initializing third element of array with third structure object 

    printf("\n First Element of array has values of a = [%d] and c = [%c]\n", st_arr[0].a, st_arr[0].c);
    printf("\n Second Element of array has values of a = [%d] and c = [%c]\n", st_arr[1].a, st_arr[1].c);
    printf("\n Third Element of array has values of a = [%d] and c = [%c]\n", st_arr[2].a, st_arr[2].c); 

    return 0;
The output of the above program comes out to be :
$ ./strucarr 

 First Element of array has values of a = [0] and c = [a] 

 Second Element of array has values of a = [1] and c = [b] 

 Third Element of array has values of a = [2] and c = [c]

6. Array of Char Pointers

The following program gives a brief Idea of how to declare an array of char pointers :

int main()
    // Declaring/Initializing three characters pointers
    char *ptr1 = "Himanshu";
    char *ptr2 = "Arora";
    char *ptr3 = "TheGeekStuff"; 

    //Declaring an array of 3 char pointers
    char* arr[3]; 

    // Initializing the array with values
    arr[0] = ptr1;
    arr[1] = ptr2;
    arr[2] = ptr3; 

    //Printing the values stored in array
    printf("\n [%s]\n", arr[0]);
    printf("\n [%s]\n", arr[1]);
    printf("\n [%s]\n", arr[2]); 

    return 0;
The output of the above program is :
$ ./charptrarr 




7. Pointer to Arrays

Pointers in C Programming language is very powerful. Combining pointers with arrays can be very helpful in certain situations.
As to any kind of data type, we can have pointers to arrays also. A pointer to array is declared as :
For example :
The above example declares a pointer ptr to an array of 5 integers.
Lets look at a small program for demonstrating this :

int main(void)
    char arr[3];

    arr[0] = 'a';
    arr[1] = 'b';
    arr[2] = 'c'; 

    ptr = &arr; 

    return 0;
In the above program, we declared and initialized an array ‘arr’ and then declared a pointer ‘ptr’ to an array of 3 characters. Then we initialized ptr with the address of array ‘arr’.

8. Static vs Dynamic Arrays

Static arrays are the ones that reside on stack. Like :
char arr[10];
Dynamic arrays is a popular name given to a series of bytes allocated on heap. this is achieved through malloc() function. Like :
char *ptr = (char*)malloc(10);
The above line allocates a memory of 10 bytes on heap and we have taken the starting address of this series of bytes in a character pointer ptr.
Static arrays are used when we know the amount of bytes in array at compile time while the dynamic array is used where we come to know about the size on run time.

9. Decomposing Array into Pointers

Internally, arrays aren’t treated specially, they are decomposed into pointers and operated there-on. For example an array like :
char arr[10];
When accessed like :
arr[4] = 'e';
is decomposed as :
*(arr + 4) = 'e'
So we see above that the same old pointers techniques are used while accessing array elements.

10. Character Arrays and Strings

Mostly new programmers get confused between character arrays and strings. Well, there is a very thin line between the two. This thin line only comprises of a null character ‘\0′ . If this is present after a series of characters in an array, then that array becomes a string. This is an array:
char arr[] = {'a', 'b', 'c'};
This is a string:
char arr[] = {'a', 'b', 'c', '\0'};
Note : A string can be printed through %s format specifier in printf() while an printing an array through %s specifier in printf() is a wrong practice.

11. Bi-dimensional and Multi-dimensional Arrays

The type of array we discussed until now is single dimensional arrays. As we see earlier, we can store a set of characters or a string in a single dimensional array. What if we want to store multiple strings in an array. Well, that wont be possible using single dimensional arrays. We need to use bi-dimensional arrays in this case. Something like :
char arr[5][10];
The above declaration can be thought of as 5 rows and 10 columns. Where each row may contain a different name and columns may limit the number of characters in the name. So we can store 5 different names with max length of 10 characters each. Similarly, what if we want to store different names and their corresponding addresses also. Well this requirement cannot be catered even by bi-dimensional arrays. In this case we need tri-dimensional (or multi-dimensional in general) arrays. So we need something like :
char arr[5][10][50];
So we can have 5 names with max capacity of 10 characters for names and 50 characters for corresponding addresses. Since this is an advanced topic, So we won’t go into practical details here.

12. A Simple C Program using Arrays

Consider this simple program that copies a string into an array and then changes one of its characters :

int main(void)
    char arr[4];// for accommodating 3 characters and one null '\0' byte.
    char *ptr = "abc"; //a string containing 'a', 'b', 'c', '\0' 

    memset(arr, '\0', sizeof(arr)); //reset all the bytes so that none of the byte contains any junk value
    strncpy(arr,ptr,sizeof("abc")); // Copy the string "abc" into the array arr 

    printf("\n %s \n",arr); //print the array as string 

    arr[0] = 'p'; // change the first character in the array 

    printf("\n %s \n",arr);//again print the array as string
    return 0;
I think the program is self explanatory as I have added plenty of comments. The output of the above program is :
$ ./array_pointer 


So we see that we successfully copied the string into array and then changed the first character in the array.

13. No Array Bound Check in a C Program

What is array bound check? Well this is the check for boundaries of array declared. For example :
char arr[5];
The above array ‘arr’ consumes 5 bytes on stack and through code we can access these bytes using :
arr[0], arr[1], arr[2], arr[3], arr[4]
Now, C provides open power to the programmer to write any index value in [] of an array. This is where we say that no array bound check is there in C. SO, misusing this power, we can access arr[-1] and also arr[6] or any other illegal location. Since these bytes are on stack, so by doing this we end up messing with other variables on stack. Consider the following example :

unsigned int count = 1; 

int main(void)
    int b = 10;
    int a[3];
    a[0] = 1;
    a[1] = 2;
    a[2] = 3; 

    printf("\n b = %d \n",b);
    a[3] = 12;
    printf("\n b = %d \n",b); 

    return 0;
In the above example, we have declared an array of 3 integers but try to access the location arr[3] (which is illegal but doable in C) and change the value kept there.
But, we end up messing with the value of variable ‘b’. Cant believe it?, check the following output . We see that value of b changes from 10 to 12.
$ ./stk 

 b = 10 

 b = 12

TCP/IP Attacks – ARP Cache Poisoning Fundamentals Explained

Suppose ‘A’ and ‘B’ are very good friends and ‘A’ shares all his secrets with ‘B’.
Now if a guy ‘C’ comes in and fakes as if he is ‘B’. Can you imagine what could happen? Yes, ‘A’ could tell all his secrets to ‘C’ and ‘C’ could misuse it.
In a layman’s language, this is what we mean by ARP cache poisoning.
ARP poisoning may cause many serious networking problems and network administrators should know how this attack works.

ARP Protocol

Before Jumping on to the description of ARP cache poising, lets first refresh how ARP protocol works. ARP protocol consists of the following 4 basic messages:
  1. ARP request : Computer ‘A’ asks on the network, “who has this IP?”
  2. ARP reply : All the other computers ignore the request except the computer which has the requested IP. This computer, lets say ‘B’ says, I have the requested IP address and here is my MAC address.
  3. RARP request: This is more or less same as ARP request, the difference being that in this message a MAC address is broad-casted on network.
  4. RARP reply : Same concept. Computer ‘B’ tells that the requested MAC is mine and here is my IP address.
All the devices that are connected to network have an ARP cache. This cache contains the mapping of all the MAC and IP address for the network devices this host has already communicated with.

ARP Cache Poisoning Concept

ARP protocol was designed to be simple and efficient but a major flaw in the protocol is lack of authentication. No authentication was added to its implementation and as a result, there is no way to authenticate the IP to MAC address mapping in the ARP reply. Further, the host does not even check whether it sent an ARP request for which it is receiving ARP reply message.
In a layman’s language, if computer ‘A’ has sent and ARP request and it gets an ARP reply, then ARP protocol by no means can check whether the information or the IP to MAC mapping in the ARP reply is correct or not. Also, even if a host did not send an ARP request and gets an ARP reply, then also it trusts the information in reply and updates its ARP cache. This is known as ARP cache poisoning.
So you can see that its easy to exploit this weakness of ARP protocol. An evil hacker can craft a valid ARP reply in which any IP is mapped to any MAC address of the hackers choice and can send this message to the complete network. All the devices on network will accept this message and will update their ARP table with new Information and this way the hacker can gain control of the to and fro communication from any host in network.

ARP Cache Poisoning Consequences

After a hacker sees a possibility of ARP cache poisoning, the attacker can use various attack techniques to harm or to gain control of the victims machine. Lets discuss some of them here :

1) Denial of service

A hacker can send an ARP reply mapping an IP address on network with a wrong or non-existent MAC address. For example, a fake ARP reply mapping the network’s router IP with a non-existent MAC will bring down the connectivity of the whole network with the outer world as now any packet sent to IP of router will be sent to a machine with a MAC address that does not exist.

2) Man in Middle

As the name suggest, the hacker can make his machine sit right in between of the communication between your system and any other system on network. This way the hacker can sniff all the traffic to and from from both the machines.
To achieve this suppose your machine is host ‘A’ and your network router is host ‘B’. ‘A’ has IP-A and MAC-A, while ‘B’ has IP-B and MAC-B as IP address and MAC address respectively. Now, the hacker sends an ARP reply to the router mapping your IP (IP-A) with his machine’s MAC address and another ARP reply to your machine mapping routers IP with his machine’s MAC address. Now any message sent by your machine to router or from router to your machine will reach the hacker’s machine. The hacker can now switch on the ‘IP forwarding’ feature on his machine which lets the hacker’s machine to forward all the traffic to and fro to your machine and router. This way the hacker’s machine sits right in the middle and can sniff or block the traffic.

3) MAC Flooding

For switches on network, MAC flooding is an ARP cache poising technique that is used. Many network switches when overloaded can start acting like a hub and start broadcasting all the network traffic to all the hosts connected to network. So a hacker can flood a switch with fake ARP replies and can make the switch to start behaving like a hub. In this role, the switch does not enable its ‘port security’ feature due to which it broadcast all the network traffic and taking advantage of this, the hacker can packet sniff the network.

ARP Cache Poisoning Mitigation Techniques

Poisoning ARP cache remotely is bit difficult as it requires either physical access to the network or control of one of the machines in the network. Since its not always easy so ARP attacks are not frequently heard. Anyways, taking precautions is better than taking medicines. Network administrators should take care that these type of attacks do not take place. Here are a few mitigation points :
  • For small networks, static ARP entries can be maintained. Static means unchanging, so as the name suggests these entries cannot be changed and thus any tries by hackers to change the mapping fails. This is good for small networks but not for big networks as mapping for every new device added to network needs to be done manually.
  • For a large network, the port security features of network switches can be explored. Some features when turned on force the switch to allow only one MAC address for each physical port on switch. This feature makes sure that machines cannot change their MAC address and cannot map more than one MAC to their machine hence preventing attacks like ‘man in middle’.
  • In general, Some monitoring tool like ARPwatch can be deployed to get alerts when some malicious ARP activity takes place on your network.
To conclude, in this article, we studied the basics of ARP protocol, its loopholes, how these loopholes can be exploited and how they can be mitigated.

Understand UNIX / Linux Inodes Basics with Examples

Several countries provides a unique identification number (for example, social security number in the USA) to the people who live in that country. This makes it easier to identify an individual uniquely. This makes it easier to handle all the paper work necessary for an individual by various government agencies and financial institutions.
Similar to the social security number, there is a concept of Inode numbers which uniquely exist for all the files on Linux or *nix systems.

Inode Basics

An Inode number points to an Inode. An Inode is a data structure that stores the following information about a file :
  • Size of file
  • Device ID
  • User ID of the file
  • Group ID of the file
  • The file mode information and access privileges for owner, group and others
  • File protection flags
  • The timestamps for file creation, modification etc
  • link counter to determine the number of hard links
  • Pointers to the blocks storing file’s contents
Please note that the above list is not exhaustive. Also, the name of the file is not stored in Inodes (We will come to it later).
When a file is created inside a directory then the file-name and Inode number are assigned to file. These two entries are associated with every file in a directory. The user might think that the directory contains the complete file and all the extra information related to it but this might not be the case always. So we see that a directory associates a file name with its Inode number.
When a user tries to access the file or any information related to the file then he/she uses the file name to do so but internally the file-name is first mapped with its Inode number stored in a table. Then through that Inode number the corresponding Inode is accessed. There is a table (Inode table) where this mapping of Inode numbers with the respective Inodes is provided.

Why no file-name in Inode information?

As pointed out earlier, there is no entry for file name in the Inode, rather the file name is kept as a separate entry parallel to Inode number. The reason for separating out file name from the other information related to same file is for maintaining hard-links to files. This means that once all the other information is separated out from the file name then we can have various file names which point to same Inode.
For example :
$ touch a

$ ln a a1

$ ls -al
drwxr-xr-x 48 himanshu himanshu 4096 2012-01-14 16:30 .
drwxr-xr-x 3 root root 4096 2011-03-12 06:24 ..
-rw-r--r-- 2 himanshu family 0 2012-01-14 16:29 a
-rw-r--r-- 2 himanshu family 0 2012-01-14 16:29 a1
In the above output, we created a file ‘a’ and then created a hard link a1. Now when the command ‘ls -al’ is run, we can see the details of both ‘a’ and ‘a1′. We see that both the files are indistinguishable. Look at the second entry in the output. This entry specifies number of hard links to the file. In this case the entry has value ’2′ for both the files.
Note that Hard links cannot be created on different file systems and also they cannot be created for directories.

When are Inodes created?

As we all now know that Inode is a data structure that contains information of a file. Since data structures occupy storage then an obvious question arises about when the Inodes are created in a system? Well, space for Inodes is allocated when the operating system or a new file system is installed and when it does its initial structuring. So this way we can see that in a file system, maximum number of Inodes and hence maximum number of files are set.
Now, the above concept brings up another interesting fact. A file system can run out of space in two ways :
  • No space for adding new data is left
  • All the Inodes are consumed.
Well, the first way is pretty obvious but we need to look at the second way. Yes, its possible that a case arises where we have free storage space but still we cannot add any new data in file system because all the Inodes are consumed. This may happen in a case where file system contains very large number of very small sized files. This will consume all the Inodes and though there would be free space from a Hard-disk-drive point of view but from file system point of view no Inode available to store any new file.
The above use-case is possible but less encountered because on a typical system the average file size is more than 2KB which makes it more prone to running out of hard disk space first. But, nevertheless there exists an algorithm which is used to create number of Inodes in a file system. This algorithm takes into consideration the size of the file system and average file size. The user can tweak the number of Inodes while creating the file system.

Commands to access Inode numbers

Following are some commands to access the Inode numbers for files :

1) Ls -i Command

As we explained earlier in our Unix LS Command: 15 Practical Examples article, the flag -i is used to print the Inode number for each file.
$ ls -i
1448240 a 1441807 Desktop 1447344 mydata 1441813 Pictures 1442737 testfile 1448145 worm
1448240 a1 1441811 Documents 1442707 my_ls 1442445 practice 1442739
1447139 alpha 1441808 Downloads 1447278 my_ls_alpha.c 1441810 Public 1447099 Unsaved Document 1
1447478 article_function_pointer.txt 1575132 google 1447274 my_ls.c 1441809 Templates 1441814 Videos
1442390 chmodOctal.txt 1441812 Music 1442363 output.log 1448800 testdisk.log 1575133 vlc
See that the Inode number for ‘a’ and ‘a1′ are same as we created ‘a1′ as hard link.

2) Df -i Command

df -i command displays the inode information of the file system.
$ df -i
Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda1            1875968  293264 1582704   16% /
none                  210613     764  209849    1% /dev
none                  213415       9  213406    1% /dev/shm
none                  213415      63  213352    1% /var/run
none                  213415       1  213414    1% /var/lock
/dev/sda2            7643136  156663 7486473    3% /home
The flag -i is used for displaying Inode information.

3) Stat Command

Stat command is used to display file statistics that also displays inode number of a file
$ stat a
File: `a'
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 805h/2053d Inode: 1448240 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 1000/himanshu) Gid: ( 1001/ family)
Access: 2012-01-14 16:30:04.871719357 +0530
Modify: 2012-01-14 16:29:50.918267873 +0530
Change: 2012-01-14 16:30:03.858251514 +0530

Example Usage Scenario of an Inode number

  1. Suppose there exist a file name with some special character in it. For example:  ”ab*
  2. Try to remove it normally using rm command, you will not be able to remove it.
  3. However using the inode number of this file you can remove it.
Lets see these steps in this example :
1) Check if the file exists:
$ ls -i
1448240 a 1447274 my_ls.c
1448240 a1 1442363 output.log
1448239 "ab* 1441813 Pictures
1447139 alpha
So we have a file with name “ab* in this directory
2) Try to remove it normally:
$ rm "ab*
> ^C
$ rm "ab*
> ^C
See that I tried couple of times to remove the file but could not.
3) Remove the file using Inode number:
As we discussed earlier in our find command examples article, you can search for a file using inode number and delete it.
$ find . -inum 1448239 -exec rm -i {} \;
rm: remove regular empty file `./"ab*'? y
$ ls -i
1448240 a 1447274 my_ls.c
1448240 a1 1442363 output.log
1447139 alpha 1441813 Pictures
So we used the find command specifying the Inode number of the file we need to delete. The file got deleted. Though we could have deleted the file otherwise also by using the command rm \”ab* instead of using the complicated find command example above but still I used it to demonstrate one of the use of Inode numbers for users.

How to View and Extract Files from rpm, deb, depot and msi Packages

Question: How do I view or extract the files that are bundled inside the packages of various operating system. For example, I would like to know how to view (and extract) the content of a rpm, or deb, or depot, or msi file.
Answer: You can use tools like rpm, rpm2cpio, ar, dpkg, tar, swlist, swcopy, lessmsi as explained below.

1. RPM package in Redhat / CentOS / Fedora

Listing the files from a RPM package using rpm -qlp

RPM stands for Red Hat package manager. The following example shows how to view the files available in a RPM package without extracting or installing the rpm package.
$ rpm -qlp ovpc-2.1.10.rpm
Explanation of the command: rpm -qlp ovpc-2.1.10.rpm
  • rpm — command
  • q — query the rpm file
  • l — list the files in the package
  • p — specify the package name

Extracting the files from a RPM package using rpm2cpio and cpio

RPM is a sort of a cpio archive. First, convert the rpm to cpio archive using rpm2cpio command. Next, use cpio command to extract the files from the archive as shown below.
$ rpm2cpio ovpc-2.1.10.rpm | cpio  -idmv

$ ls .

2. Deb package in Debian

deb is the extension of Debian software package format. *.deb is also used in other distributions that are based on Debian. (for example: Ubuntu uses *.deb)

Listing the files from a debian package using dpkg -c

dpkg is the package manager for debian. So using dpkg command you can list and extract the packages, as shown below.

To view the content of *.deb file:

$ dpkg -c ovpc_1.06.94-3_i386.deb
dr-xr-xr-x root/root         0 2010-02-25 10:54 ./
dr-xr-xr-x root/root         0 2010-02-25 10:54 ./ovpc/
dr-xr-xr-x root/root         0 2010-02-25 10:54 ./ovpc/pkg/
dr-xr-xr-x root/root         0 2010-02-25 10:54 ./ovpc/pkg/lib/
dr-xr-xr-x root/root         0 2010-02-25 10:48 ./ovpc/pkg/lib/header/
-r-xr-xr-x root/root       130 2009-10-29 17:06 ./ovpc/pkg/lib/header/

-r-xr-xr-x root/root       131 2009-10-29 17:06 ./ovpc/pkg/etc/conf
dr-xr-xr-x root/root         0 2010-02-25 10:54 ./ovpc/pkg/etc/conf/log.conf

Extracting the files from a debian package using dpkg -x

Use dpkg -x to extract the files from a deb package as shown below.
$ dpkg -x  ovpc_1.06.94-3_i386.deb /tmp/ov
$ ls /tmp/ov
DEB files are ar archives, which always contains the three files — debian-binary, control.tar.gz, and data.tar.gz. We can use ar command and tar command to extract and view the files from the deb package, as shown below.
First, extract the content of *.deb archive file using ar command.
$ ar -vx ovpc_1.06.94-3_i386.deb
x - debian-binary
x - control.tar.gz
x - data.tar.gz
Next, extract the content of data.tar.gz file as shown below.
$ tar -xvzf data.tar.gz

3. Depot package in HP-UX

Listing the files from a depot package using tar and swlist

DEPOT file is a HP-UX Software Distributor Catalog Depot file. HP-UX depots are just a tar file, with some additional information as shown below.
$ tar -tf ovcsw_3672.depot
swlist is a HP-UX command which is used to display the information about the software. View the content of the depot package as shown below using swlist command.
$ swlist -l file -s /root/ovcsw_3672.depot
# Initializing...
# Contacting target "osgsw"...
# Target:  osgsw:/root/ovcsw_3672.depot

# OcswServer   8.50.000       Ocsw  Server product
# OcswServer.MGR       9.00.140       Ocs Server Ovw

Extracting the files from a depot package using swcopy

Swcopy command copies or merges software_selections from a software source to one or more software depot target_selections. Using uncompress option in swcopy, you can extract the files from a depot software package.
$ swcopy -x uncompress_files=true -x enforce_dependencies=false -s /root/ovcsw_3672.depot \* @ /root/extracted/
$ ls /root/extracted
MGR catalog  osmsw.log
Since depot files tar files, you can extract using normal tar extraction as shown below.
$ tar -xvf filename

4. MSI in Windows

Microsoft installer is an engine for the installation, maintenance, and removal of software on windows systems.

Listing the files from a MSI package using lessmsi

The utility called lessmsi.exe is used to view the files from the msi packages with out installing. The same utility is also used to extract the msi package. Select the msi which you want to view the content. lessmsi will list the files available in msi.

Extracting the files from a MSI package using msiexec

Windows Installer Tool (Msiexec.exe) is used to extract the files from the MSI package. It can open a MSI package in “Administrator” installation mode, where it can extract the files without performing the install as shown below.
C:\>msiexec /a ovcsw_3672.msi /qb TARGETDIR="C:\ovcsw"