Vous êtes sur la page 1sur 43

Master of Computer Application (MCA) – Semester 2

MC0070 – Operating Systems with Unix – 4 Credits


(Book ID: B0682 & B0683)
Assignment Set – 1 (60 Marks)

1. Describe the following operating system components:


A) Functions of an Operating system B) Operating system components

Ans:
Operating system functions

An operating system is a software component that acts as the core of a computer system.
It performs various functions and is essentially the interface that connects your computer
and its supported components. In this article, we will discuss the basic functions of the
operating system, along with security concerns for the most popular types. Also learn
more about driver updates.

Basic Operation

Drivers play a major role in the operating system. A driver is a program designed to
comprehend the functions of a particular device installed on the system. A driver enables
the operation of numerous devices, including your mouse, keyboard printer, video card
and CD-ROM drive by translating commands from the operating system or the user into
commands understood by the associated component. It also translates responses from the
component back to the operating system, software application or user.

The operating system performs other functions with system utilities that monitor
performance,

debug errors and maintain the system. It also includes a set of libraries often used by
applications to perform tasks to enable direct interaction with system components. These
common functions run seamlessly and are transparent to most users.

Security Concerns

The fact that an operating system is computer software makes it prone to error just as any
human creation. Programmers make mistakes, and inefficient code is often implemented
into programs even after testing. Some developers perform more thorough testing and
generally produce more efficient software. Therefore, some operating systems and more
error prone while others are more secure.

Here are some common security issues that pose a threat to all operating systems:

Instabilities and Crashes - Both of these instances may be the result of software bugs in
the operating system. Bugs in software applications on the computer may also cause
problems, such as preventing the system from communicating with hardware devices.
They can even cause the system to become unstable or crash. A system crash consists of
freezing and becoming unresponsive to point where the machine needs to be rebooted.
These issues vary depending on the type of operating system.

Flaws - Software bugs will not only make a system unstable, but also leave it wide open
to unauthorized users. Once these vulnerabilities are discovered, attackers can exploit
them and gain access to your system. From there, they can install malware, launch attacks
on other machines or even take complete control of your system. Software developers
usually distribute security patches rather quickly to update the operating system and fix
the vulnerabilities.

Types of Operating Systems

There are several types of operating systems, with Windows, Linux and Macintosh suites
being the most widely used. Here is an overview on each system:

Windows: Windows is the popular Microsoft brand preferred by most personal users.
This system has come a long way from version 1.0 all the way up to the new Vista and
soon to be released Windows 7. Although Windows has made strides in regard to
security, it has a reputation for being one of the most vulnerable systems.

Unix/Linux: The Unix operating system has been around for years, and it is well known
for its stability. Unix is often used more as a server than a workstation. Linux was based
on the Unix system, with the source code being a part of GNU open-source project. Both
systems are very secure yet far more complex than Windows.

Macintosh: Recent versions of the Macintosh operating system, including the Mac OS
X, follow the secure architecture of Unix. Systems developed by Apple are efficient and
easy to use, but can only function on Apple branded hardware.

Operating system components

Process Management

The operating system manages many kinds of activities ranging from user programs to
system programs like printer spooler, name servers, file server etc. Each of these
activities is encapsulated in a process. A process includes the complete execution context
(code, data, PC, registers, OS resources in use etc.).

It is important to note that a process is not a program. A process is only ONE instant of a
program in execution. There are many processes can be running the same program. The
five major activities of an operating system in regard to process management are

• Creation and deletion of user and system processes.


• Suspension and resumption of processes.
• A mechanism for process synchronization.
• A mechanism for process communication.
• A mechanism for deadlock handling.

Main-Memory Management

Primary-Memory or Main-Memory is a large array of words or bytes. Each word or byte


has its own address. Main-memory provides storage that can be access directly by the
CPU. That is to say for a program to be executed, it must in the main memory.

The major activities of an operating in regard to memory-management are:

• Keep track of which part of memory are currently being used and by whom.
• Decide which process are loaded into memory when memory space becomes
available.
• Allocate and deallocate memory space as needed.

File Management

A file is a collected of related information defined by its creator. Computer can store files
on the disk (secondary storage), which provide long term storage. Some examples of
storage media are magnetic tape, magnetic disk and optical disk. Each of these media has
its own properties like speed, capacity, data transfer rate and access methods.

A file systems normally organized into directories to ease their use. These directories
may contain files and other directions.

The five main major activities of an operating system in regard to file management are

1. The creation and deletion of files.


2. The creation and deletion of directions.
3. The support of primitives for manipulating files and directions.
4. The mapping of files onto secondary storage.
5. The back up of files on stable storage media.

I/O System Management

I/O subsystem hides the peculiarities of specific hardware devices from the user. Only the
device driver knows the peculiarities of the specific device to whom it is assigned.

Secondary-Storage Management

Generally speaking, systems have several levels of storage, including primary storage,
secondary storage and cache storage. Instructions and data must be placed in primary
storage or cache to be referenced by a running program. Because main memory is too
small to accommodate all data and programs, and its data are lost when power is lost, the
computer system must provide secondary storage to back up main memory. Secondary
storage consists of tapes, disks, and other media designed to hold information that will
eventually be accessed in primary storage (primary, secondary, cache) is ordinarily
divided into bytes or words consisting of a fixed number of bytes. Each location in
storage has an address; the set of all addresses available to a program is called an address
space.

The three major activities of an operating system in regard to secondary storage


management are:

1. Managing the free space available on the secondary-storage device.


2. Allocation of storage space when new files have to be written.
3. Scheduling the requests for memory access.

Networking

A distributed systems is a collection of processors that do not share memory, peripheral


devices, or a clock. The processors communicate with one another through
communication lines called network. The communication-network design must consider
routing and connection strategies, and the problems of contention and security.

Protection System

If a computer systems has multiple users and allows the concurrent execution of multiple
processes, then the various processes must be protected from one another's activities.
Protection refers to mechanism for controlling the access of programs, processes, or users
to the resources defined by a computer systems.

Command Interpreter System

A command interpreter is an interface of the operating system with the user. The user
gives commands with are executed by operating system (usually by turning them into
system calls). The main function of a command interpreter is to get and execute the next
user specified command. Command-Interpreter is usually not part of the kernel, since
multiple command interpreters (shell, in UNIX terminology) may be support by an
operating system, and they do not really need to run in kernel mode. There are two main
advantages to separating the command interpreter from the kernel.

2. Describe the following:

Ans:
A. Micro Kernels

We have already seen that as UNIX expanded, the kernel became large and difficult
to manage. In the mid-1980s, researches at Carnegie Mellon University developed an
operating system called Mach that modularized the kernel using the microkernel
approach. This method structures the operating system by removing all nonessential
components from the kernel and implementing then as system and user-level programs.
The result is a smaller kernel. There is little consensus regarding which services should
remain in the kernel and which should be implemented in user space. Typically, however,
micro-kernels provide minimal process and memory management, in addition to a
communication facility.

Device File Client …. Virtual


Server Process Memory
Drivers
Microkernel
Hardware

Microkernel Architecture

The main function of the microkernel is to provide a communication facility


between the client program and the various services that are also running in user space.
Communication is provided by message passing. For example, if the client program and
service never interact directly. Rather, they communicate indirectly by exchanging
messages with the microkernel.

On benefit of the microkernel approach is ease of extending the operating system.


All new services are added to user space and consequently do not require modification of
the kernel. When the kernel does have to be modified, the changes tend to be fewer,
because the microkernel is a smaller kernel. The resulting operating system is easier to
port from one hardware design to another. The microkernel also provided more security
and reliability, since most services are running as user – rather than kernel – processes, if
a service fails the rest of the operating system remains untouched.

Several contemporary operating systems have used the microkernel approach.


Tru64 UNIX (formerly Digital UNIX provides a UNIX interface to the user, but it is
implemented with a March kernel. The March kernel maps UNIX system calls into

B. Modules
Perhaps the best current methodology for operating-system design involves using
object-oriented programming techniques to create a modular kernel. Here the
kernel has a set of core components and dynamically links in additional services
either during boot time or during run time. Such a strategy uses dynamically
loadable modules and is common in modern implementations of UINX, such as
Solaris, Linux and Mac OS. For examples, the Solaris operating system structure
is organized around acore kernel with seven types of loadable kernel modules:
1. Scheduling classes
2. File system
3. Loadable system calls
4. Executable system calls
5. STREAMS formats
6. Miscellaneous
7. Device and bus drivers

3. Describe the concept of process control in Operating systems?

Ans:

When you type a command at the Unix prompt, press Return , and wait until the
prompt comes back indicating the previous command is done, then you have run a
foreground process. You can only run one foreground process at a time from one
window, but Unix allows you to run more than one process at once, some of which are in
the background.

To start a long program running (one that may take several minutes to complete, for
example) put it in the background by adding a & to the command.

Process creation

Operating systems need some ways to create processes. In a very simple system designed
for running only a single application (e.g., the controller in a microwave oven), it may be
possible to have all the processes that will ever be needed be present when the system
comes up. In general-purpose systems, however, some way is needed to create and
terminate processes as needed during operation.
There are four principal events that cause a process to be created:

 System initialization.
 Execution of process creation system call by running a process.
 A user request to create a new process.
 Initiation of a batch job.

When an operating system is booted, typically several processes are created. Some of
these are foreground processes, that interacts with a (human) user and perform work for
them. Other are background processes, which are not associated with particular users, but
instead have some specific function. For example, one background process may be
designed to accept incoming e-mails, sleeping most of the day but suddenly springing to
life when an incoming e-mail arrives. Another background process may be designed to
accept an incoming request for web pages hosted on the machine, waking up when a
request arrives to service that request.
Process creation in UNIX and Linux are done through fork() or clone() system calls.
There are several steps involved in process creation. The first step is the validation of
whether the parent process has sufficient authorization to create a process. Upon
successful validation, the parent process is copied almost entirely, with changes only to
the unique process id, parent process, and user-space. Each new process gets its own user
space.[1]
Process termination

There are many reasons for process termination:

 Batch job issues halt instruction


 User logs off
 Process executes a service request to terminate
 Error and fault conditions
 Normal completion
 Time limit exceeded
 Memory unavailable
 Bounds violation; for example: attempted access of (non-existent) 11th element of
a 10-element array
 Protection error; for example: attempted write to read-only file
 Arithmetic error; for example: attempted division by zero
 Time overrun; for example: process waited longer than a specified maximum for
an event
 I/O failure
 Invalid instruction; for example: when a process tries to execute data (text)
 Privileged instruction
 Data misuse
 Operating system intervention; for example: to resolve a deadlock
 Parent terminates so child processes terminate (cascading termination)
 Parent request
4. Describe the following with respect to UNIX operating System:
Ans:
A) Hardware Management

One of the first things you do, after successfully plugging together a plethora of
cables and components, is turn on your computer. The operating system takes care
of all the starting functions that must occur to get your computer to a usable state.
Various pieces of hardware need to be initialized. After the start-up procedure is
complete, the operating system awaits further instructions. If you shut down the
computer, the operating system also has a procedure that makes sure all the
hardware is shut down correctly. Before turning your computer off again, you
might want to do something useful, which means that one or more applications
are executed. Most boot ROMs do some hardware initialization but not much.
Initialization of I/O devices is part of the UNIX kernel.

Process Management

After the operating system completes hardware initialization, you can execute an
application. This executing application is called a process. It is the operating
system's job to manage execution of the application. When you execute a
program, the operating system creates a new process. Many processes can exist
simultaneously, but only one process can actually be executing on a CPU at one
time. The operating system switches between your processes so quickly that it can
appear that the processes are executing simultaneously. This concept is referred to
as time-sharing or multitasking.

When you exit your program (or it finishes executing), the process terminates, and
the operating system manages the termination by reclaiming any resources that
were being used.

Most applications perform some tasks between the time the process is created and
the time it terminates. To perform these tasks, the program makes requests to the
operating system, and the operating system responds to the requests and allocates
necessary resources to the program. When an executing process needs to use
some hardware, the operating system provides access for the process.

To perform its task, a process may need to access hardware resources. The process may
need to read or write to a file, send data to a network card (to communicate with another
computer), or send data to a printer. The operating system provides such services for the
process. This is referred to as resource allocation. A piece of hardware is a resource, and
the operating system allocates available resources to the different processes that are
running.

See Table 1.1 for a summary of different actions and what the operating system (OS)
does to manage them.
Operating system functions.
Action OS Does This
You turn on the computer Hardware management
You execute an application Process management
Application reads a tape Hardware management
Application waits for data Process management
Process waits while other process runs Process management
Process displays data on screen Hardware management
Process writes data to tape Hardware management
You quit, the process terminates Process management
You turn off the computer Hardware management

From the time you turn on your computer until you turn it off, the operating system is
coordinating the operations. As hardware is initialized, accessed, or shut down, the
operating system manages these resources. As applications execute, request, and receive
resources, or terminate, the operating system takes care of these actions. Without an
operating system, no application can run and your computer is just an expensive
paperweight.

B) Unix Architecture

System Architecture

At the center of the UNIX onion is a program called the kernel. It is absolutely
crucial to the operation of the UNIX system. The kernel provides the essential services
that make up the heart of UNIX systems; it allocates memory, keeps track of the physical
location of files on the computer’s hard disks, loads and executes binary programs such
as shells, and schedules the task swapping without which UNIX systems would be
incapable of doing more than one thing at a time.

The kernel accomplishes all these tasks by providing an interface between the
other programs running under its control and the physical hardware of the computer; this
interface, the system call interface, effectively insulates the other programs on the UNIX
system from the complexities of the computer. For example, when a running program
needs access to a file, it cannot simply open the file; instead it issues a system call which
asks the kernel to open the file. The kernel takes over and handles the request, then
notifies the program whether the request succeeded or failed. To read data in from the file
takes another system call; the kernel determines whether or not the request is valid, and if
it is, the kernel reads the required block of data and passes it back to the program. Unlike
DOS (and some other operating systems), UNIX system programs do not have access to
the physical hardware of the computer. All they see are the kernel services, provided by
the system call interface.

Although there is a well-defined, technical and commercial standard for what


constitutes “Unix,” in common usage, Unix refers to a set of operating systems, from
private vendors

and in various open-licensed versions, that act similarly from the view of users
and administrators. Within any Unix version, there are several different “shells” which
affect how commands are interpreted. Your default is that you are using Solaris
(developed by Sun Microsystems primarily for use on hardware sold by Sun) within the
“c-shell.” Most of the basic commands here will work the same in other Unix variants
and shells, including Linux and the Mac OS X command-line environment.

All Unix commands and file references are case sensitive: “This” is a different
filename than “this” because of the capitalization difference. All Unix commands are
lowercase and from two to nine characters long. Many commands have options that are
invoked by a hyphen followed by one or more letters. Multiple options can often be
requested by adding multiple letters to a single hyphen. For example, ls -al combines the
-a and -l options.

A standard Unix system provides commands username, passwd, chsh, and


additional options on chdgrp to change usernames, passwords, default groups, and shell
environments.
Wildcards: * is a “wildcard” character that can refer to any character string and ?
is a wildcard character that can refer to any single character. E.g., mv *.f95 code would
move

every Fortran 95 program file on the current directory into a subdirectory called
code. Filenames: in our version of Unix, they may be up to 255 characters, and they may
include any character except the regular slash /. (Avoid using backslashes, blank spaces,
or nonprinting characters in filenames – they are allowed but will cause problems for
you.)

A pathname beginning with / is an absolute path from the top of the system tree.
A pathname not beginning with / is a relative path down from the current working
directory.

Directory shortcuts include: ˜ as a replacement for your home directory,


˜username as a shorthand for username’s home directory, .. (two periods) for the
subdirectory one level up from the current directory, and . (one period) for the current
directory.

4. Describe the following:

A) Unix Kernel

A Unix kernel — the core or key components of the operating system — consists of
many kernel subsystems like process management, memory management, file
management, device management and network management.

Each of the subsystems has some features:

 Concurrency: As Unix is a multiprocessing OS, many processes run concurrently


to improve the performance of the system.
 Virtual memory (VM): Memory management subsystem implements the virtual
memory concept and a user need not worry about the executable program size and the
RAM size.
 Paging: It is a technique to minimize the internal as well as the external
fragmentation in the physical memory.
 Virtual file system (VFS): A VFS is a file system used to help the user to hide the
different file systems complexities. A user can use the same standard file system
related calls to access different file systems.

The kernel provides these and other basic services: interrupt and trap handling, separation
between user and system space, system calls, scheduling, timer and clock handling, file
descriptor management.
Features

Some key features of the Unix architecture concept are:

 Unix systems use a centralized operating system kernel which manages system
and process activities.
 All non-Kernel software is organized into separate, kernel-managed processes.
 Unix systems are preemptively multitasking: multiple processes can run at the
same time, or within small time slices and nearly at the same time, and any process
can be interrupted and moved out of execution by the kernel. This is known
as thread management.
 Files are stored on disk in a hierarchical file system, with a single top location
throughout the system (root, or "/"), with both files and directories, subdirectories,
sub-subdirectories, and so on below it.
 With few exceptions, devices and some types of communications between
processes are managed and visible as files or pseudo-files within the file system
hierarchy. This is known as everything's a file.

The UNIX operating system supports the following features and capabilities:[1]

 Multitasking and multiuser.


 Kernel written in high-level language.
 Programming interface.
 Use of files as abstractions of devices and other objects.
 Character-based default UI.
 Built-in networking. (TCP/IP is standard)
 Persistent system service processes called "daemons" and managed by init or
inetd.

B) Unix Startup Scripts


In the beginning, there was "init". If you had a Unix system, you had "init" and it was
almost certainly process id 1. Process 0 was the swapper (not visible in "ps"); it started
init with a fork and, one way or another, init was responsible for starting everything else.
There were variations, but not many. BSD systems simply used /etc/rc and /etc/ttys.
You'd configure terminals in /etc/ttys and add anything else to /etc/rc. The System V
Unixes used the more complex /etc/inittab file to direct init's actions, but really that
wasn't much more than the /etc/ttys - life was pretty simple. That didn't take long to
change.
Basic inittab
The Automating Program Startup article describes init and inittab as they worked on SCO
Unix and Linux at that time. Linux inittab soon became mostly standardized, though with
some confusion of /etc/init.d vs. /etc/rc.d/init.d and Red Hat's use of "chkconfig" (or the
GUI "ntsysv" or "serviceconf" ) to control the startup scripts. With any Unix or Linux
system that uses inittab, you simply need to start with /etc/inittab and follow the trail
from there. For example, a recent Centos system has these entries in /etc/inittab
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6

From that, you know (if you read the older article) that when the system enters a
particular run state, it will be running the /etc/rc script and passing the run state as an
argument. The /etc/rc script will take different actions based on what run state is desired;
you can examine the script to see just what it does and how it does it.
A recent SCO system uses separate scripts for each run level:
r0:056:wait:/etc/rc0 1> /dev/console 2>&1 </dev/console
r1:1:wait:/etc/rc1 1> /dev/console 2>&1 </dev/console
r2:2:wait:/etc/rc2 1> /dev/console 2>&1 </dev/console
r3:3:wait:/etc/rc3 1> /dev/console 2>&1 </dev/console
sd:0:wait:/etc/uadmin 2 0 >/dev/console 2>&1 </dev/console
fw:5:wait:/etc/uadmin 2 2 >/dev/console 2>&1 </dev/console
rb:6:wait:/etc/uadmin 2 1 >/dev/console 2>&1 </dev/console

Again. you'd examine the individual scripts to see what they do, but in general, on Linux
or any other system, you'll find these scripts look for "S" or "K" scripts in a particular
directory and take appropriate action (see the older article for more detail on those and
variants like SCO's "P" scripts).
Note that on Centos, /etc/rc3.d is a link to /etc/rc.d/rc3.d. Other systems may not have
these links but will follow the same concepts.
But now we start to get a little more complicated. Let's say that you want a particular
process to start. We'll use "httpd" as an example because it is something that is commonly
found on Unix systems and you may or may not want it running. What makes it run?
We'll look at the SCO and Centos systems as examples.
SCO's default run-level is 2. Most Linux systems use 3 for normal multiuser mode and 5
if X11 is desired. You can find out where the system is now with "who -r"; a SCO system
would indicate "2" normally and a Linux box would show "3" or "5". Since SCO defaults
to "2" and inittab tells init to run /etc/rc2 for that run-level, we look at that script and find
that it in turns runs through scripts found in /etc/rc2.d. One of those scripts is P90apache.
If it's not there, you'd type "apache enable" to create it. If it is there and you don't want it
to start, you could do one of four things:
o Remove the script from /etc/rc2.d with "rm"
o run "apache disable" to remove the script
o Rename the script so that it does not start with "S", "K" or "P"
o Edit the script to add "exit 0" to the top

Note that you could get more clever than "exit 0". You could test for the existence of
some file and continue the startup if it exists or exit if not.
For Centos, we'll look in /etc/rc5.d and will probably find either K15httpd or S85httpd
(the numbers may be different on your system). Both of these are links to
/etc/rc.d/init.d/httpd. Centos uses Red Hat's "chkconfig" to enable or disable common
startup scripts:
# pwd
/etc/rc5.d
# ls *httpd
K15httpd
# chkconfig httpd on
# ls *httpd
S85httpd
# chkconfig httpd off
# ls *httpd
K15httpd
#
However, just as you can on SCO, you could control this manually by renaming, editing
or removing scripts (and on systems that don't use chkconfig, you may have to).
What if you want to add your own script? On SCO, you'd create an appropriate "S" script
in /etc/rc2.d and a matching "K" script in /etc/rc0.d. For a Linux system, you could do the
same thing (though in /etc/rc.d/rc5.d or /etc/rc.d/rc3.d) or you could let chkconfig manage
all that for you. All you need is a "chkconfig" comment line that might look like this:
# chkconfig: - 91 17

Look at any of the existing scripts to see examples. The "91" says what will follow the
"S" when chkconfig links a startup script to this; the "17" is used for "K" scripts. You put
your script in /etc/rc.d/init.d and activate it:
# chkconfig --add mystuff
# chkconfig --list mystuff
mystuff 0:off 1:off 2:off 3:off 4:off 5:off 6:off
# chkconfig mystuff on
# chkconfig --list mystuff
mystuff 0:off 1:off 2:on 3:on 4:on 5:on 6:off

If you examine the rc[3-4] directories, you'll see your command has been added:
# ls /etc/rc.d/rc[3-4].d/*mystuff
/etc/rc.d/rc3.d/S91mystuff /etc/rc.d/rc4.d/S91mystuff

6. Explain the following with respect to Interprocess communication in


Unix:
Ans:
A) Communication via pipes

Once we got our processes to run, we suddenly realize that they cannot communicate.
One of the mechanisms that allow related-processes to communicate is the pipe, or the
anonymous pipe.

A pipe is a one-way mechanism that allows two related processes (i.e. one is an
ancestor of the other) to send a byte stream from one of them to the other one.

If we want a two-way communication, we’ll need two pipes. The system assures us of
one thing: The order in which data is written to the pipe, is the same order as that in
which data is read from the pipe. The system also assures that data won’t get lost in the
middle, unless one of the processes (the sender or the receiver) exits prematurely.
C) Named Pipes

A named pipe (also called a named FIFO, or just FIFO) is a pipe whose
access point is a file kept on the file system.

By opening this file for reading, a process gets access to the reading end of the pipe.

By opening the file for writing, the process gets access to the writing end of the pipe.

If a process opens the file for reading, it is blocked until another process opens the
file for writing. The same goes the other way around.

Creating A Named Pipe

A named pipe may be created either via the ‘mknod’ (or its newer replacement,
‘mkfifo’), or via the mknod() system call

To create a named pipe with the file named ‘prog_pipe’, we can use the following
command:

mknod prog_pipe p

We could also provide a full path to where we want the named pipe created. If we
then type ‘ls -l prog_pipe’, we will see something like this:

prw-rw-r– 1 user1 0 Nov 7 01:59 prog_pipe

The ‘p’ on the first column denotes this is a named pipe. Just like any file in the
system, it has access permissions, that define which users may open the named pipe, and
whether for reading, writing or both.

D) Message Queues

A message queue is a queue onto which messages can be placed. A message is


composed of a message type (which is a number), and message data.

A message queue can be either private, or public. If it is private, it can be accessed


only by its creating process or child processes of that creator. If it’s public, it can be
accessed by any process that knows the queue’s key.

Several processes may write messages onto a message queue, or read messages from
the queue. Messages may be read by type, and thus not have to be read in a FIFO
order as is the case with pipes.
Creating A Message Queue – msgget()

In order to use a message queue, it has to be created first. The msgget() system call is
used to do just that. This system call accepts two parameters – a queue key, and
flags. The key may be one of:

IPC_PRIVATE – used to create a private message queue.

A positive integer – used to create (or access) a publicly-accessible message queue.

The second parameter contains flags that control how the system call is to be
processed. It may contain flags like IPC_CREAT or IPC_EXCL and it also contains
access permission bits.

Example of a code that creates a private message queue:

#include <stdio.h> /* standard I/O routines. */


#include <sys/types.h> /* standard system data types.
#include <sys/ipc.h> /* common system V IPC structures. */
#include <sys/msg.h> /* message-queue specific functions. */
int queue_id = msgget(IPC_PRIVATE, 0600); // octal number.
if (queue_id == -1) { perror("msgget"); exit(1); }

1. the system call returns an integer identifying the created queue. Later on we can use
this key in order to access the queue for reading and writing messages.

2. The queue created belongs to the user whose process created the queue. Thus, since the
permission bits are ‘0600′, only processes run on behalf of this user will have access to
the queue.

D) Message Structure

Before we go to writing messages to the queue or reading messages from it, we


need to see how a message looks. The system defines a structure named ‘msgbuf’ for this
purpose. Here is how it is defined:

struct msgbuf {
long mtype; /* message type, a positive number (cannot be
zero). */
char mtext[1]; /* message body array. usually larger than
one byte. */
};
Lets create an "hello world" message:
/* first, define the message string */
char* msg_text = "hello world";
/* allocate a message with enough space for length of string and */ /* one extra byte for
the terminating null character. */
struct msgbuf* msg = (struct msgbuf*)malloc(sizeof(struct msgbuf) + strlen(msg_text));
/* set the message type. for example – set it to ‘1′. */
msg->mtype = 1; /* finally, place the "hello world" string inside the message. */
strcpy(msg->mtext, msg_text);

Writing Messages Onto A Queue – msgsnd()

Once we created the message queue, and a message structure, we can place it on the
message queue, using the msgsnd() system call. This system call copies our message
structure and places that as the last message on the queue. It takes the following
parameters:

int msqid – id of message queue, as returned from the msgget() call.


struct msgbuf* msg – a pointer to a properly initializes message structure, such as the one
we prepared in the previous section.
int msgsz – the size of the data part (mtext) of the message, in bytes.
int msgflg – flags specifying how to send the message. may be a logical "or" of the
following:
IPC_NOWAIT – if the message cannot be sent immediately, without blocking the
process, return ‘-1′, and set errno to EAGAIN.
to set no flags, use the value ‘0′.
in order to send our message on the queue, we’ll use msgsnd() like this:
int rc = msgsnd(queue_id, msg, strlen(msg_text)+1, 0);
if (rc == -1) {
perror("msgsnd");
exit(1);
}

Reading A Message From The Queue – msgrcv()

We may use the system call msgrcv() In order to read a message from a message queue.
This system call accepts the following list of parameters:

int msqid – id of the queue, as returned from msgget().

struct msgbuf* msg – a pointer to a pre-allocated msgbuf structure. It should generally be


large enough to contain a message with some arbitrary data (see more below).

int msgsz – size of largest message text we wish to receive. Must NOT be larger than the
amount of space we allocated for the message text in ‘msg’.

int msgtyp – Type of message we wish to read. may be one of:

0 – The first message on the queue will be returned.


a positive integer – the first message on the queue whose type (mtype) equals this integer
(unless a certain flag is set in msgflg, see below).

a negative integer – the first message on the queue whose type is less than or equal to the
absolute value of this integer.

int msgflg – a logical ‘or’ combination of any of the following flags:

IPC_NOWAIT – if there is no message on the queue matching what we want to read,


return ‘-1′, and set errno to ENOMSG.

MSG_EXCEPT – if the message type parameter is a positive integer, then return the first
message whose type is NOT equal to the given integer.

Lets then try to read our message from the message queue:

/* message structure large enough to read our "hello world". */

struct msgbuf* recv_msg = (struct msgbuf*)malloc(sizeof(struct msgbuf)+strlen("hello


world")); /*

use msgrcv() to read the message. We agree to get any type, and thus */ /* use ‘0′ in the
message type parameter, and use no flags (0). */

int rc = msgrcv(queue_id, recv_msg, strlen("hello world")+1, 0, 0);

if (rc == -1) { perror("msgrcv"); exit(1); }


Master of Computer Application (MCA) – Semester 2
MC0070 – Operating Systems with UNIX – 4 Credits
(Book ID: B0682 & B0683)
Assignment Set – 2 (60 Marks)

1. Describe the following with respect to Deadlocks in Operating Systems:


Ans:
A) Livelocks
There is a variant of deadlock called livelock. This is a situation in which two or more
process continuously change their state in response to changes in the other process
without doing any useful work. This is similar to dead lock in that no progress is made
but differs in that neither process is blocked or waiting of anything.

B) Killing Zombies
Recall that if a child dies before its parent calls wait, the child becomes a zombie. In
some applications, a web server for example, the parent forks off lots of children but
doesn’t care whether the child is dead or alive. For example, a web server might fork a
new process to handle each connection. Such an application is at risk of producing many
zombies, and zombies can clog up the process table.
When a child dies, it sends SIGCHLD signal to its parent. The parent process can prevent
zombies from being created by creating a signal handler routine for SIGCHLD which
calls wait whenever it receivers a SIGCHLD signal. There is no danger that this will
cause the parent to block because it would only call wait when it knows that a child has
just died.
There are several versions of wait on a Unix system. The system call waitpid has this
prototype
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_loc, int options)

C) Pipes
A second form of redirection is a pipe. A pipe is a connection between two processes in
which one process writes data to the pipe and the other reads from the pipe. Thus, it
allows one process to pass data to another process.
The Unix system call to create a pipe is
Int pipe(int fd[2])
This function takes an array of two ints (file descriptors) as an argument. It creates a pipe
with fd[0] at one end and fd[1] at the other. Reading from the pipe and writing to the pipe
are done with read and write calls that you have seen and used before. Although both
ends are opened for both reading and writing, by convention a process writes to fd[1] and
reads from fd[0]. Pipes only make sense if the process calls fork after creating the pipe.

2. Explain the following:


A) Requirements for mutual exclusion
B) Mutual exclusion by using lock variables
C) Semaphore Implementation

Ans –

A) Requirements for mutual exclusion

Following are the six requirements for mutual exclusion.

1. Mutual exclusion must be enforced: Only one process at a time is allowed into its
critical section, among all processes that have critical sections for the same resource or
shared object.

2. A process that halts in its non critical section must do so without interfering with other
processes.

3. It must not be possible for a process requiring access to a critical section to be delayed
indefinitely.

4. When no process is in a critical section, any process that requests entry to its critical
section must be permitted to enter without delay.

5. No assumptions are made about relative process speed or number of


processors.

6. A process remains inside its critical section for a finite time only.

Following are some of the methods for achieving mutual exclusion.

B) Mutual exclusion by using lock variables


In this method, we consider a single, shared, (lock) variable, initially 0. When a process
wants to enter in its critical section, it first test the lock value. If lock is 0, the process first
sets it to 1 and then enters the critical section. If the lock is already 1, the process just
waits until (lock) variable becomes 0. Thus, a 0 means that no process in its critical
section and 1 mean some process is in its critical section.
C) Semaphore Implementation
To achieve desired effect, view semaphores as variables that have an integer value upon
which three operations are defined:

• A semaphore may be initialized to a non-negative value


• The wait operation decrements the semaphore value. If the value becomes
negative, the process executing the wait is blocked.
• The signal operations increment the semaphore value. If the value is not positive,
then the process blocked by wait operation is unblocked.

3. Describe the concept of space management in file systems.

Ans –

Block Size and Extents

All of the file organizations I’ve mentioned store the contents of a file in a set of disk
blocks. How big should a block be? The problem with small blocks is I/O overhead.
There is a certain overhead to read or write a block beyond the time to actually transfer
the bytes. If we double the block size, a typical file will have half as many blocks.
Reading or writing the whole file will transfer the same amount of data, but it will
involve half as many disk I/O operations. The overhead for an I/O operations includes a
variable amount of latency (seek time and rotational delay) that depends on how close the
blocks are to each other, as well as a fixed overhead to start each operation and respond
to the interrupt when it completes.

Many years ago, researchers at the University of California at Berkeley studied the
original Unix file system. They found that when they tried reading or writing a single
very large file sequentially, they were getting only about 2% of the potential speed of the
disk. In other words, it took about 50 times as long to read the whole file as it would if
they simply read that many sequential blocks directly from the raw disk (with no file
system software). They tried doubling the block size (from 512 bytes to 1K) and the
performance more than doubled. The reason the speed more than doubled was that it took
less than half as many I/O operations to read the file. Because the blocks were twice as
large, twice as much of the file’s data was in blocks pointed to directly by the inode.
Indirect blocks were twice as large as well, so they could hold twice as many pointers.
Thus four times as much data could be accessed through the singly indirect block without
resorting to the doubly indirect block.

Most files in a typical Unix system are very small. The Berkeley researchers made a
list of the sizes of all files on a typical disk and did some calculations of how much space
would be wasted by various block sizes. Simply rounding the size of each file up to a
multiple of 512 bytes resulted in wasting 4.2% of the space. Including overhead for
inodes and indirect blocks, the original 512-byte file system had a total space overhead of
6.9%. Changing to 1K blocks raised the overhead to 11.8%. With 2k blocks, the overhead
would be 22.4% and with 4k blocks it would be 45.6%. Would 4k blocks be worthwhile?
The answer depends on economics. In those days disks were very expensive, and a
wasting half the disk seemed extreme. These days, disks are cheap, and for many
applications people would be happy to pay twice as much per byte of disk space to get a
disk that was twice as fast.

As disks get cheaper and CPU’s get faster, wasted space is less of a problem and the
speed mismatch between the CPU and the disk gets worse. Thus the trend is towards
larger and larger disk blocks.

At first glance it would appear that the OS designer has no say in how big a block is.
Any particular disk drive has a sector size, usually 512 bytes, wired in. But it is possible
to use larger “blocks”. For example, if we think it would be a good idea to use 2K blocks,
we can group together each run of four consecutive sectors and call it a block. In fact, it
would even be possible to use variable-sized “blocks,” so long as each one is a multiple
of the sector size. A variable-sized “block” is called an extent. When extents are used,
they are usually used in addition to multi-sector blocks. For example, a system may use
2k blocks, each consisting of 4 consecutive sectors, and then group them into extents of 1
to 10 blocks. When a file is opened for writing, it grows by adding an extent at a time.
When it is closed, the unused blocks at the end of the last extent are returned to the
system. The problem with extents is that they introduce all the problems of external
fragmentation that we saw in the context of main memory allocation. Extents are
generally only used in systems such as databases, where high-speed access to very large
files is important.

Free Space

We have seen how to keep track of the blocks in each file. How do we keep track of
the free blocks – blocks that are not in any file? There are two basic approaches.

· Use a bit vector. That is simply an array of bits with one bit for each block on the
disk. A 1 bit indicates that the corresponding block is allocated (in some file) and a 0 bit
says that it is free. To allocate a block, search the bit vector for a zero bit, and set it to
one.

· Use a free list. The simplest approach is simply to link together the free blocks by
storing the block number of each free block in the previous free block. The problem with
this approach is that when a block on the free list is allocated, you have to read it into
memory to get the block number of the next block in the list. This problem can be solved
by storing the block numbers of additional free blocks in each block on the list. In other
words, the free blocks are stored in a sort of lopsided tree on disk. If, for example, 128
block numbers fit in a block, 1/128 of the free blocks would be linked into a list. Each
block on the list would contain a pointer to the next block on the list, as well as pointers
to 127 additional free blocks. When the first block of the list is allocated to a file, it has to
be read into memory to get the block numbers stored in it, but then we and allocate 127
more blocks without reading any of them from disk. Freeing blocks is done by running
this algorithm in reverse: Keep a cache of 127 block numbers in memory. When a block
is freed, add its block number to this cache. If the cache is full when a block is freed, use
the block being freed to hold all the block numbers in the cache and link it to the head of
the free list by adding to it the block number of the previous head of the list.

How do these methods compare? Neither requires significant space overhead on disk.
The bitmap approach needs one bit for each block. Even for a tiny block size of 512
bytes, each bit of the bitmap describes 512*8 = 4096 bits of free space, so the overhead is
less than 1/40 of 1%. The free list is even better. All the pointers are stored in blocks that
are free anyhow, so there is no space overhead (except for one pointer to the head of the
list). Another way of looking at this is that when the disk is full (which is the only time
we should be worried about space overhead!) the free list is empty, so it takes up no
space. The real advantage of bitmaps over free lists is that they give the space allocator
more control over which block is allocated to which file. Since the blocks of a file are
generally accessed together, we would like them to be near each other on disk. To ensure
this clustering, when we add a block to a file we would like to choose a free block that is
near the other blocks of a file. With a bitmap, we can search the bitmap for an appropriate
block. With a free list, we would have to search the free list on disk, which is clearly
impractical. Of course, to search the bitmap, we have to have it all in memory, but since
the bitmap is so tiny relative to the size of the disk, it is not unreasonable to keep the
entire bitmap in memory all the time. To do the comparable operation with a free list, we
would need to keep the block numbers of all free blocks in memory. If a block number is
four bytes (32 bits), that means that 32 times as much memory would be needed for the
free list as for a bitmap. For a concrete example, consider a 2 gigabyte disk with 8K
blocks and 4-byte block numbers. The disk contains 231/213 = 218 = 262,144 blocks. If they
are all free, the free list has 262,144 entries, so it would take one megabyte of memory to
keep them all in memory at once. By contrast, a bitmap requires 2 18 bits, or 215 = 32K
bytes (just four blocks). (On the other hand, the bit map takes the same amount of
memory regardless of the number of blocks that are free).

Reliability

Disks fail, disks sectors get corrupted, and systems crash, losing the contents of
volatile memory. There are several techniques that can be used to mitigate the effects of
these failures. We only have room for a brief survey.

Back-up Dumps

There are a variety of storage media that are much cheaper than (hard) disks but are
also much slower. An example is 8 millimeter video tape. A “two-hour” tape costs just a
few dollars and can hold two gigabytes of data. By contrast, a 2GB hard drive currently
casts several hundred dollars. On the other hand, while worst-case access time to a hard
drive is a few tens of milliseconds, rewinding or fast-forwarding a tape to desired
location can take several minutes. One way to use tapes is to make periodic back up
dumps. Dumps are really used for two different purposes:
· To recover lost files. Files can be lost or damaged by hardware failures, but far more
often they are lost through software bugs or human error (accidentally deleting the wrong
file). If the file is saved on tape, it can be restored.

· To recover from catastrophic failures. An entire disk drive can fail, or the whole
computer can be stolen, or the building can burn down. If the contents of the disk have
been saved to tape, the data can be restored (to a repaired or replacement disk). All that is
lost is the work that was done since the information was dumped.

Corresponding to these two ways of using dumps, there are two ways of doing
dumps. A physical dump simply copies all of the blocks of the disk, in order, to tape. It’s
very fast, both for doing the dump and for recovering a whole disk, but it makes it
extremely slow to recover any one file. The blocks of the file are likely to be scattered all
over the tape, and while seeks on disk can take tens of milliseconds, seeks on tape can
take tens or hundreds of seconds. The other approach is a logical dump, which copies
each file sequentially. A logical dump makes it easy to restore individual files. It is even
easier to restore files if the directories are dumped separately at the beginning of the tape,
or if the name(s) of each file are written to the tape along with the file.

The problem with logical dumping is that it is very slow. Dumps are usually done
much more frequently than restores. For example, you might dump your disk every night
for three years before something goes wrong and you need to do a restore. An important
trick that can be used with logical dumps is to only dump files that have changed
recently. An incremental dump saves only those files that have been modified since a
particular date and time. Fortunately, most file systems record the time each file was last
modified. If you do a backup each night, you can save only those files that have changed
since the last backup. Every once in a while (say once a month), you can do a full backup
of all files. In Unix jargon, a full backup is called an epoch (pronounced “eepock”) dump,
because it dumps everything that has changed since “the epoch”–January 1, 1970, which
is the the earliest possible date in Unix.

Incremental dumps go fast because they dump only a small fraction of the files, and
they don’t take up a lot of tape. However, they introduce new problems:

· If you want to restore a particular file, you need to know when it was last modified so
that you know which dump tape to look at.

· If you want to restore the whole disk (to recover from a catastrophic failure), you have
to restore from the last epoch dump, and then from every incremental dump since then, in
order. A file that is modified every day will appear on every tape. Each restore will
overwrite the file with a newer version. When you’re done, everything will be up-to-date
as of the last dump, but the whole process can be extremely slow (and labor-intensive).

· You have to keep around all the incremental tapes since the last epoch. Tapes are cheap,
but they’re not free, and storing them can be a hassle.
The First problem can be solved by keeping a directory of what was dumped
when. A bunch of UW alumni (the same person who invented NFS) have made
themselves millionaires by marketing software to do this. The other problems can be
solved by a clever trick. Each dump is assigned a positive integer level. A level n dump is
an incremental dump that dumps all files that have changed since the most recent
previous dump with a level greater than or equal to n. An epoch dump is considered to
have infinitely high level. Levels are assigned to dumps as follows:

This scheme is sometimes called a ruler schedule for obvious reasons. Level-1
dumps only save files that have changed in the previous day. Level-2 dumps save files
that have changed in the last two days, level-3 dumps cover four days, level-4 dumps
cover 8 days, etc. Higher-level dumps will thus include more files (so they will take
longer to do), but they are done infrequently. The nice thing about this scheme is that you
only need to save one tape from each level, and the number of levels is the logarithm of
the interval between epoch dumps. Thus even if it did a dump each night and you only
did an epoch dump only once a year, you would need only nine levels (hence nine tapes).
That also means that a full restore needs at worst one restore from each of nine tapes
(rather than 365 tapes!). To figure out what tapes you need to restore from if your disk is
destroyed after dump number n, express n in binary, and number the bits from right to
left, starting with 1. The 1 bits tell you which dump tapes to use. Restore them in order of
decreasing level. For example, 20 in binary is 10100, so if the disk is destroyed after the
20th dump, you only need to restore from the epoch dump and from the most recent
dumps at levels 5 and 3.

4. Explain the theory of working with files and directories in Unix file system

Ans:

File and Directory Names

Unlike some operating systems, UNIX gives you great flexibility in how you name
files and directories. As previously mentioned, you cannot use the slash character because
it is the pathname separator and the name of the file tree’s root directory . However,
almost everything else is legal. Filenames can contain alphabetic (both upper- and
lowercase), numeric, and punctuation characters, control characters, shell wild-card
characters (such as *), and even spaces, tabs, and newlines. However, just because you
can do something doesn’t mean you should. Your life will be much simpler if you stick
with upper- and lowercase alphabetics, digits, and punctuation characters such as ., -, and
_.

CAUTION: Using shell wild-card characters such as * in filenames can cause


problems. Your shell expands such wild-card characters to match other files. Suppose
that you create a filenamed * that you want to display with cat, and you still have your
files cowboys and prufrock. You might think that the command cat * will do the trick, but
remember that * is a shell wild card that matches anything. Your shell expands * to
match the files *, cowboys, and prufrock, so cat displays all three. You can avoid this
problem by quoting the asterisk with a backslash:

$ cat *

Quoting, temporarily removes a wild card’s special meaning and prevents your
shell from expanding it. However, having to quote wild cards is inconvenient, so you
should avoid using such special characters in filenames.

You also should avoid using a hyphen or plus sign as the first character of a
filename, because command options begin with those characters. Suppose that you name
a file -X and name another unix_lore. If you enter cat *, your shell expands the * wild
card and runs cat as follows:

$ cat -X unix_lore

The cat command interprets -X as an option string rather than a filename. Because
cat doesn’t have a -X option, the preceding command results in an error message. But if
cat did have a -X option, the result might be even worse, as the command might do
something completely unexpected. For these reasons, you should avoid using hyphens at
the beginning of filenames.

Filenames can be as long as 255 characters in System V Release 4 UNIX. Unlike


DOS, which uses the dot character to separate the filename from a three character suffix,
UNIX does not attach any intrinsic significance to dot – a filenamed lots.of.italian.recipes
is as legal as lots-of-italian-recipes. However, most UNIX users follow the dot-suffix
conventions listed in Table 5.1. Some language compilers like cc require that their input
files follow these conventions, so the table labels these conventions as "Required" in the
last column.
File suffix conventions.

Suffix Program Example Required


.c C program files ls.c Yes
.f FORTRAN program files math.f Yes
.pl Perl program files hose.pl No
.h include files term.h No
.d, .dir The file is a directory recipes.d, No
recipes.dir No
.gz A file compressed with the foo.gz Yes
GNV project’s gzip
.Z A compressed file term.h.Z Yes
.zip A file compressed with PKZIP book.zip Yes

Choosing good filenames is harder than it looks. Although long names may seem
appealing at first, you may change your mind after you enter cat lots-of-italian-recipes a
few times. Of course, shell wild cards can help (as in cat lots-of*), but as you gain
experience, you’ll find that you prefer shorter names.

Working with Files

Now that you know how to create, list, and view files, create directories, and move
around the UNIX file tree, it’s time to learn how to copy, rename, and remove files.

Copying Files with cp

To copy one or more files, you use the cp command. You might want to use cp to make a
backup copy of a file before you edit it, or to copy a file from a friend’s directory into
your own.

Suppose that you want to edit a letter but also keep the first draft in case you later decide
that you like it best. You could enter the following:

$ cd letters
$ ls
andrea zach
$ cp andrea andrea.back
$ ls
andrea andrea.back zach

(When it works, cp prints no output, following the UNIX tradition that "no news is good
news.")
Now you have two identical files: the original andrea file and a new filenamed
andrea.back. The first file that you give to cp is sometimes called the target, and the
second the destination. The destination can be a file (as in the preceding example) or a
directory. For instance, you might decide to create a subdirectory of letters in which to
keep backups of all your correspondence:

$ cd letters
$ mkdir backups
$ ls
andrea backups zach
$ cp andrea backups
$ ls backups
andrea

Note that the destination of the cp command is simply backups, not


backups/andrea. When you copy a file into a directory, cp creates the new file with the
same name as the original unless you specify something else. To give the file a different
name, enter it as follows:

$ cp andrea backups/andrea.0
$ ls backups
andrea.0

As you can see, ls works differently when you give it a directory rather than a file
as its command-line argument. When you enter ls some_file, ls prints that file’s name if
the file exists; otherwise, the command prints the following error message:

some_file: No such file or directory

If you enter ls some_dir, ls prints the names of any files in some_dir; otherwise,
the command prints nothing. If the directory doesn’t exist, ls prints the following error
message:

some_dir: No such file or directory

You can also use cp to copy several files at once. If plan to edit both of your
letters and want to save drafts of both, you could enter the following:

$ cd letters
$ ls
andrea backups zach
$ cp andrea zach backups
$ ls backups
andrea zach
When copying more than one file at a time, you must specify an existing directory as the
destination. Suppose that you enter the following:

$ cd letters
$ ls
andrea backups zach
$ cp andrea zach both
cp: both not found

The cp command expects its last argument to be an existing directory, and prints
an error message when it can’t find the directory.

If what you want is to catenate two files into a third, use cat and shell redirection:

$ cat andrea zach > both

You can also use the directory names dot and dot-dot as the destination in cp
commands. Suppose that a colleague has left some files named data1 and data2 in the
system temporary directory /tmp so that you can copy them to your home directory. You
could enter the following:

$ cd
$ cp /tmp/data1 .
$ cp /tmp/data2 .
$ ls
data1 data2
Alternatively, because the destination is dot, a directory, you can copy both files at once:
$ cp /tmp/data1 /tmp/data2 .
$ ls
data1 data2

To copy the files to the parent directory of your CWD, use dot-dot rather than dot.

By default, cp silently overwrites (destroys) existing files. In the preceding


example, if you already have a filenamed data1 and you type cp /tmp/data1 ., you lose
your copy of data1 forever, replacing it with /tmp/data1. You can use cp’s -i (interactive)
option to avoid accidental overwrites:

$ cp -i /tmp/data1 .

cp: overwrite./data1(y/n)?

When you use the -i option, cp asks whether you want to overwrite existing files.
If you do, type y; if you don’t, type n. If you’re accident-prone or nervous, and your shell
enables you to do so, you may want to create an alias that always uses cp –i..
Moving Files with mv

The mv command moves files from one place to another. Because each UNIX file
has a unique pathname derived from its location in the file tree, moving a file is
equivalent to renaming it: you change the pathname. The simplest use of mv is to rename
a file in the current directory. Suppose that you’ve finally grown tired of typing cat
recipe-for-linguini and want to give your fingers a rest. Instead, you can enter the
following:

$ mv recipe-for-linguini linguini

There is an important difference between cp and mv: cp leaves the original file in
its place, but mv removes it. Suppose that you enter the following command:

$ mv linguini /tmp

This command removes the copy of linguini in your CWD. So, if you want to
retain your original file, use cp instead of mv.

Like cp, mv can handle multiple files if the destination is a directory. If your
journal is to be a long-term project, you may want to put the monthly files in
subdirectories that are organized by the year. Enter the following commands:

$ cd journal
$ ls
Apr_93 Dec_93 Jan_93 Jun_93 May_93 Oct_93
Aug_93 Feb_93 Jul_93 Mar_93 Nov_93 Sep_93
$ mkdir 93
$ mv *_93 93
$ ls
93
$ ls 93
Apr_93 Dec_93 Jan_93 Jun_93 May_93 Oct_93
Aug_93 Feb_93 Jul_93 Mar_93 Nov_93 Sep_93

Note that, by default, ls sorts filenames in dictionary order down columns. Often,
such sorting is not what you want. The following tip suggests ways that you can work
around this problem. Also note that mv, like other UNIX commands, enables you to use
shell wild cards such as *.

TIP: You can work around ls’s default sorting order by prefixing filenames with
punctuation (but not hyphens or plus signs), digits, or capitalization. For instance, if you
want to sort the files of month names in their natural order, prefix them with 00, 01, and
so on:

$ cd journal/93
$ ls
01_jan 03_mar 05_may 07_jul 09_sep 11_nov
02_feb 04_apr 06_jun 08_aug 10_oct 12_dec
Like cp, mv silently overwrites existing files by default:
$ ls
borscht strudel
$ mv borscht strudel
$ ls

strudel

This command replaces the original file strudel with the contents of bortsch, and
strudel’s original contents are lost forever. If you use mv’s -i option, the mv command,
like cp, asks you before overwriting files.

Also like cp, mv requires that you specify dot or dot-dot as the destination
directory. In fact, this requirement is true of all UNIX commands that expect a directory
argument.

Removing Files with rm

You can remove unwanted files with rm. This command takes as its arguments
the names of one or more files, and removes those files—forever. Unlike operating
systems like DOS, which can sometimes recover deleted files, UNIX removes files once
and forever. Your systems administrator may be able to recover a deleted file from a
backup tape, but don’t count on it. (Besides, systems administrators become noticeably
cranky after a few such requests.) Be especially careful when using shell wild cards to
remove files—you may end up removing more than you intended.

TIP: Shell wild-card expansions may be dangerous to your mental health,


especially if you use them with commands like rm. If you’re not sure which files will
match the wild cards that you’re using, first use echo to check. For instance, before
entering rm a*, first enter echo a*. If the files that match a* are the ones that you expect,
you can enter the rm command, confident that it will do only what you intend.

To remove the file andrea.back, enter the following command:

$ rm andrea.back
Like cp and mv, rm prints no output when it works.
If you are satisfied with your edited letters and want to remove the backups to save disk
space, you could enter the following:
$ cd letters/backups
$ ls
andrea zach
$ rm *
$ ls

Because you have removed all the files in the subdirectory backups, the second ls
command prints nothing.

Like cp and mv, rm has an interactive option, -i. If you enter rm -i *, rm asks you
whether you really want to remove each individual file. As before, you type y for yes and
n for no. This option can be handy if you accidentally create a filename with a
nonprinting character, such as a control character. Nonprinting characters don’t appear in
file listings, and they make the file hard to work with. If you want to remove the file,
enter rm -i *; then type y for the file you that you want to remove, while typing n for the
others. The -i option also comes in handy if you want to remove several files that have
such dissimilar names that you cannot specify them with wild cards. Again, simply enter
rm -i *, and then type n for each file that you don’t want to remove.

5. Explain the working of file substitution in Unix. Also describe the usage of pipes
in Unix Operating system.

Ans:
Pipelines in command line interfaces

All widely used Unix and Windows shells have a special syntax construct for the creation
of pipelines. In typical usage one writes the filter commands in sequence, separated by
the ASCII vertical bar character "|" (which, for this reason, is often called "pipe
character"). The shell starts the processes and arranges for the necessary connections
between their standard streams (including some amount of buffer storage).
Error stream
By default, the standard error streams ("stderr") of the processes in a pipeline are not
passed on through the pipe; instead, they are merged and directed to the console.
However, many shells have additional syntax for changing this behaviour. In
the csh shell, for instance, using "|&" instead of "| " signifies that the standard error
stream too should be merged with the standard output and fed to the next process.
The Bourne Shell can also merge standard error, using 2>&1, as well as redirect it to a
different file.
Pipemill
In the most commonly used simple pipelines the shell connects a series of sub-processes
via pipes, and executes external commands within each sub-process. Thus the shell itself
is doing no direct processing of the data flowing through the pipeline.

However, it's possible for the shell to perform processing directly. This construct
generally looks something like:
command | while read var1 var2 ...; do
# process each line, using variables as parsed into $var1, $var2, etc
# (note that this is a subshell: var1, var2 etc will not be available
# after the while loop terminates)
done
... which is referred to as a "pipemill" (since the while is "milling" over the results from
the initial command.)

When using programs such as ssh, stdin is being passed to the remote command. As such
the default standard input handling of ssh drains the remaining hosts from the while
loop[1]. To prevent this, redirect stdin from /dev/null. (< /dev/null) In the case of ssh, you
may also use -n to prevent ssh reading from stdin.
Creating pipelines programmatically

Pipelines can be created under program control. The Unix pipe() system call asks the
operating system to construct a new anonymous pipe object. This results in two new,
opened file descriptors in the process: the read-only end of the pipe, and the write-only
end. The pipe ends appear to be normal, anonymous file descriptors, except that they
have no ability to seek.

To avoid deadlock and exploit parallelism, the Unix process with one or more new pipes
will then, generally, call fork() to create new processes. Each process will then close the
end(s) of the pipe that it will not be using before producing or consuming any data.
Alternatively, a process might create a new thread and use the pipe to communicate
between them.

Named pipes may also be created using mkfifo() or mknod() and then presented as the
input or output file to programs as they are invoked. They allow multi-path pipes to be
created, and are especially effective when combined with standard error redirection, or
with tee.
Implementation
In most Unix-like systems, all processes of a pipeline are started at the same time, with
their streams appropriately connected, and managed by the scheduler together with all
other processes running on the machine. An important aspect of this, setting Unix pipes
apart from other pipe implementations, is the concept of buffering: a sending program
may produce 5000 bytes per second, and a receiving program may only be able to accept
100 bytes per second, but no data is lost. Instead, the output of the sending program is
held in a queue. When the receiving program is ready to read data, the operating system
sends its data from the queue, then removes that data from the queue. If the queue buffer
fills up, the sending program is suspended (blocked) until the receiving program has had
a chance to read some data and make room in the buffer. In Linux, the size of the buffer
is 65536 bytes.
Network pipes
Tools like netcat and socat can connect pipes to TCP/IP sockets, following the Unix
philosophy of "everything is a file".

5. Describe the following with respect to Unix:

A) Making Calculations with dc and bc


B) Various Commands for getting user information
C) Switching Accounts with su
Ans:

A) Making Calculations with dc and bc

UNIX has two calculator programs that you can use from the command line: dc and
bc. The dc (desk calculator) program uses Reverse Polish Notation (RPN), familiar to
everyone who has used Hewlett-Packard pocket calculators, and the bc (basic calculator)
program uses the more familiar algebraic notation. Both programs perform essentially the
same calculations.

Calculating with bc

The basic calculator, bc, can do calculations to any precision that you specify.
Therefore, if you know how to calculate pi and want to know its value to 20, 50, or 200
places, for example, use bc. This tool can add, subtract, multiply, divide, and raise a
number to a power. It can take square roots, compute sines and cosines of angles,
calculate exponentials and logarithms, and handle arctangents and Bessel functions. In
addition, it contains a programming language whose syntax looks much like that of the C
programming language. This means that you can use the following:
· Simple and array variables

· Expressions

· Tests and loops

· Functions that you define

Also, bc can take input from the keyboard, from a file, or from both.

Here are some examples of bc receiving input from the keyboard:

$ bc

2*3

To do multiplication, all you have to do is enter the two values with an asterisk
between them. To exit from bc, just type Ctrl+d. However, you can also continue giving
bc more calculations to do.

Here’s a simple square root calculation (as a continuation of the original bc command):

sqrt(11)

The default behavior of bc is to treat all numbers as integers. To get floating-point


numbers (that is, numbers with decimal points in them), use the scale command. For
example, the following input tells bc that you want it to set four decimal places and then
try the square root example again:

scale=4

sqrt(11)

3.3166

In addition to setting the number of decimal places with scale, you can set the
number of significant digits with length.

You need not always use base-10 for all your calculations, either. For example,
suppose that you want to calculate the square root of the base-8 (octal) number, 11. First
change the input base to 8 and then enter the same square root command as before to do
the calculation:
ibase=8
sqrt(11)
3.0000
Ctrl+D
$

This result is correct because octal 11 is decimal 9 and the square root of 9 is 3 in both
octal and decimal.

You can use a variable even without a program:

$ bc
x=5
10*x
50

Here’s a simple loop in bc’s C-like syntax:

y=1
while(y<5){
y^2
y=y+1
}
1
4
9
16

The first line sets y to the value 1. The next four lines establish a loop: the middle
two lines repeat as long as the value of y is less than 5 (while(y<5)). Those two repeated
lines cause bc to print the value of y-squared and then add one to the value of y. Note that
bc doesn’t display the value of a variable when it’s on a line with an equals sign (or a
while statement). Also, note the positions of the braces.

Here’s another, more compact kind of loop. It sets the initial value for y, tests the
value of y, and adds one to the value of y, all on one line:

for (y = 1; y <= 5; y = y + 1){


3*y
}
3
6
9
12
15
Initially, y is set to 1. Then the loop tests whether the variable is less than or equal
to 5. Because it is, bc performs the calculation 3*y and prints 3. Next, 1 is added to the
present value of y, making it 2. That’s also less than 5, so bc performs the 3*y
calculation, which results in 6 being printed. y is incremented to 3, which is then tested;
because 3 is less than 5, 3*y is calculated again. At some point, bc increments y to 6,
which is neither less than 5 nor equal to it, so that the loop terminates with no further
calculation or display.

You can define and use new functions for the bc program. A bc function is a
device that can take in one or more numbers and calculate a result. For example, the
following function, s, adds three numbers:

define s(x,y,z){
return(x+y+z)
}

To use the s function, you enter a command such as the following:

s(5,9,22)
36

Each variable name and each function name must be a single lowercase letter. If
you are using the math library, bc -l, (discussed below), the letters a, c, e, j, l, and s are
already used.

If you have many functions that you use fairly regularly, you can type them into a
text file and start bc by entering bc myfile.bc (where myfile is the name of text file). The
bc program then knows those functions and you can invoke them without having to type
their definitions again. If you use a file to provide input to bc, you can put comments in
that file. When bc reads the file, it ignores anything that you type between /* and */.

If scale is 0, the bc program does modulus division (using the % symbol), which
provides the remainder that results from the division of two integers, as in the following
example:

scale=4
5/2
2.5000
5%2
0
scale=0
5/2
2
5%2
1
If scale is not 0, the numbers are treated as floating point even if they are typed as
integers.

In addition to including C’s increment operators (++ and —), bc also provides
some special assignment operators: +=, -=, *=, /=, and ^=.

The built-in math functions include the following:

Function Returns
a(x) The arc tangent of x
c(x) The cosine of x
e(x) e raised to the x power
The Bessel function of n and x, where n is an
j(n,x)
integer and x is any real number
l(x) The natural logarithm of x
s(x) The sine of x

To use these math functions, you must invoke bc with the -l option, as follows:

$ bc -l

Calculating with dc

As mentioned earlier, the desk calculator, dc, uses RPN, so unless you’re
comfortable with that notation, you should stick with bc. Also, dc does not provide a
built-in programming language, built-in math functions, or the capability to define
functions. It can, however, take its input from a file.

If you are familiar with stack-oriented calculators, you’ll find that dc is an


excellent tool. It can do all the calculations that bc can and it also lets you manipulate the
stack directly.

To display values, you must enter the p command. For example, to add and print
the sum of 5 and 9, enter

+p

14

See your UNIX reference manual (different versions use different titles), or if you
have them, view the on-line man pages for details on dc.
B) Various commands for getting user information

To get information about users (including yourself), you can use several commands.
The who command reports on users who are presently logged in, and finger reports on
anyone who has an account on the computer. The id command reports information about
the user who invokes it.

The who Command

The who command normally reports certain information about logged-in users.
By using its options, you can specify that it report information about the processes
initiated by init, and that it report reboots, changes to the system clock, and logoffs. If
you invoke who with no options or arguments, you get the following output:

$ who

juucp tty00 Sep 28 11:13

pjh slan05 Sep 28 12:08

The output shows that two users are currently logged in: the user juucp, who
logged in at 11:13, and the user pjh, who logged in at 12:08. Notice that juucp is logged
in on a tty line (actually, juucp is a neighboring site that is called in over a modem) and
that pjh logged in over a network (STARLAN, which is shortened to slan in who’s
output).

The -u option adds the "time since the last activity" (also called the idle time) and
the process ID number for each logged-in user. A "process ID number" or PID is an
interger number assigned by UNIX to uniquely identify a given process (usually, a
process is a program that is running). PIDs are needed in UNIX because they allow—yea,
encourage—simultaneous running of multiple processes.

$ who -u
juucp tty00 Sep 28 11:13 . 5890
pjh slan05 Sep 28 12:08 . 7354

The -T option reports a plus sign (+) if you are able to send messages to the user’s
terminal, or a minus sign (-) if it is not:

$ who -T
juucp + tty00 Sep 28 11:13
pjh + slan05 Sep 28 12:08

The -q (quick) option simply shows login IDs and a count of the logged-in users:
$ who -q
juucp pjh
# users=2

There’s a special case for who: who am i. This case is useful if you are logged in
from several terminals under different accounts, and you forget which one you are
currently using:

$ who am i
pjh slan05 Sep 28 12:08

The finger Command

You can use the finger command with or without arguments. Without arguments,
finger’s output looks a little like who’s:

$ finger

Login Name TTY Idle When


Where
Pjh Pete Holsberg pts000 6d Mon 13:03
Ajh Alan Holsberg sxt/002 Sat 15:00

This output lists all currently logged users—with a heading line—plus the user’s
full name and the name of the remote computer (in the "Where" column) if the person is
logging in over a network.

This command is more useful if you give it a person’s login ID as an argument, as


in the following example:

$ finger lam
Login name: lam In real life: Pak Lam dp168
Directory: /home/stu/lam Shell: /usr/bin/ksh
On since Feb 23 19:07:31 on pts016 from pc2
2 days 21 hours Idle Time
No unread mail
No Plan.

Here, finger displays personal information for the user lam: his real name, home
directory, which shell he uses, and when he last logged in and from which computer
(pc2). The last line indicates that he does not have a text file called .plan in his home
directory. The finger command displays the contents of .plan and .project if they exist. As
you can see, users can reveal as much or as little of themselves as they choose.
If your computer is on a network and you know another person’s e-mail address,
you can display information about that person by issuing a command such as the
following:

$ finger holsberg@pilot.njin.net

The finger command provides many options that can suppress one or more fields
of the normal, long output. However, because finger responds so quickly, simply
disregarding that extra information when it appears onscreen is easier than learning the
appropriate option.

The id Command

The id command reports four things: the user ID number, login name, group ID
number, and group name of the person who invokes it. If the real and effective IDs are
not the same, id prints both sets of values.

When a system administrator creates an account for a user, that user is given a
login ID and also placed in a group. This is important because UNIX provides access to
files according to whether the user is the owner of the file and whether the user belongs
to the group that has been granted access to the file.

In the following example, the user ID is 102, the login name is pjh, and the user
belongs to the root group, which is group number 0:

$ id

uid=102(pjh) gid=0(root)

C) Switching Accounts with su

If you have more than one account on a system, you need not log out of one and then
log into the second to use the second account. Instead, you can simply use the su (switch
user) command. The system administrator uses su frequently to check a user’s complaint,
because su enables the administrator to become that user and run the programs that were
causing problems.

The usual su command syntax is


su – userID

The minus sign tells su to cause the current user to take on the identity, userID.
To do this, su executes the user’s shell—as specified in the shell field of /etc/passwd—
and invokes /etc/profile and that user’s .profile file. The su command then displays the
user’s normal environment. If the user omits the minus sign, su invokes the user’s shell,
but the environment is the same as before. Of course, before you can switch to another
user, you must know that user’s password—unless you are the system administrator, in
which case your privileges enable you to assume identities without using passwords.
Suppose, the system administrator wishes to become user lam:

#su – lam
$
To reassume identity as sysadm, he merely logs out of lam’s account.

Vous aimerez peut-être aussi