Skip to content

TIP

  • Please remember to setup your VPN if you try to connect to EOS machines from off-campus locations.
  • New in Fall 2020: you can now remote login to Arch/EOS via our new Virtual Labs
  • New in Fall 2024: The Virtual Labs URL has changed to http://computing.gvsu.edu

Introduction to Unix and System Dev Tools

The purpose of this assignment is to re-familiarize yourself with UNIX commands and system calls, with the syntax and use of C library functions, and with some of the programming utilities and development tools that will be used during the course of the semester. This lab should largely be review material from the Linux lab component of CIS163 and CIS361 Systems Programming.

This lab exercise concentrates on tools and utilities available on any Linux-based system. Many of the utilities used in this exercise have graphical equivalents available on our systems. Consult your Linux guide for more information on using the Gnome GUI, use the online help, or just ask the person sitting next to you.

Objectives

Upon completion of this lab assignment students will:

  • become familiar with UNIX commands,
  • become familiar with the syntax and use of C library functions and system calls.
  • be able to use a number of programming utilities and development tools.
  • be able to distinguish system calls from library functions

Activities

  • Perform the experiments described below, demonstrate your knowledge of the material by answering the numbered questions in this handout.
  • This exercise can be completed as a group assignment (i.e. work together with another student if you can)
  • Submit a detailed and typed lab report (one per group) to the number questions and all requested output (files, source code, etc.). Be sure the report is written such that it will be easy for the grader to find specific details:
    • Include the names of both students in the group

Important

In your lab report, be sure to copy the original question prior to writing your answer

Online Help

Most Unix systems have online manual pages installed. In a Linux-based system, these manual pages can be found under the directory /usr/share/man. Under this directory you will find subdirectories: man1, man2, ... each corresponds to one section of manual pages. Under one of these (sub)directories, the manual page for a certain Linux command, a system call, or a library subroutine is stored as a (flat) text file. Thus, in a typical Linux system one can find thousands of such files

SectionContents
1User Commands
2System Calls
3Library Subroutines
5File Formats
8System Administration

For this course, you will primarily reference sections 2 and 3. This large number of files may be daunting at first, but with sufficient practice of using the man command, Linux man pages actually become readable.

The man command

The following commands are a starting point for productively using the Linux man pages:

  • man man: describes how to use the man command

  • man num intro: displays information from the introduction to the requested section.

  • man topic: displays information on the requested topic.

  • man num topic: displays information on the requested topic in the requested section. This syntax is needed when a command is found under several sections, but you need the one from a particular section.

    • man -k keyword: lists manual pages which contain the requested keyword in their synopsis

For instance, to display the introduction to the system calls section:

bash
man 2 intro

to display the manual page of the fopen subroutine

bash
man fopen

to display the manual page(s) that deal with password:

bash
man -k password
man -k password | grep '(3)'    # filter only those in section 3

Note: Unix man pages are also available online in various formats.

TIP

When you open a manual page, the bottom of the screen should give you a quick help highlighted summary:

Manual page XXXX(yyy) line zzz (press h form help or q to quit)

The default pager program to browse man page is less and it understands several keyboard shortcuts to navigate your way around the document, among these shortcuts are:

KeyDescription
fscroll forward
bscroll backward
/patternSearch for a text (pattern) within the manual page
nsearch again (forward)
Nsearch again (backward)
  1. (2 pts) Browse a number of manual pages of your choice from section 1, 2, and 3. Observe that they contain common "headings" (NAME, SYNOPSIS, DESCRIPTION, SEE ALSO). Most manual pages in Sections 2 (System Calls) and 3 (Subroutines) also include RETURN VALUE and ERRORS. Briefly describe the purpose of any two "headings"
  2. (2 pts) Describe the difference between the Unix user command time and the System call time().

TIP

  • Towards the end a manual page you may also find C coding example describing how to use the function/system call
  • The SEE ALSO section shows other manual pages related to the current one you are browsing. Sometimes, more detailed information for your programming work can be found in the other manual pages.

Useful Unix Commands

You should be fluent with all file handling commands and familiar with the various options these commands provide. In particular, you should know how to use:

CommandDescription
cpcopy file
mvmove or rename a file/directory
rmremove (delete) a file
mkdirmake a new directory
rmdirremove (delete) a directory
lslist the contents of a directory
cdchange to another directory
pwdprint the name of the current working directory
chmodchange access permissions of files and directories
catprint a file to stdout
more/lessprint a file to stdout, a screenful at a time

Also, familiarize yourself with these miscellaneous commands:

CommandDescription
scriptrecord a terminal session
telnetlogin to a host (telephone network protocol)
sshsecure login to a host
lprsend a file to a printer
greppattern match a string in files

Note: the desktop interface has a Windows-like file manager that graphically facilitates many of the above file tasks.

If you are unfamiliar with any of these commands, consult an introductory UNIX text or user guide (like Linux in a Nutshell by Siever, et al.). Alternatively, you can utilize the Help system as described above.

Include Files / C Header Files

Manual pages in sections 2 and 3 show the name of header files to include in a C program. A header file defines function prototypes, macros, data structures, and other useful components.

For instance, the SYNOPSIS of opendir shows the following include lines:

c
#include <sys/types.h>
#include <dirent.h>

The physical locations of these two header files are /usr/include/sys/types.h and /usr/include/dirent.h. Additionally, the directory /usr/include/bits will be frequently referenced as well. However, some compilers may install them at a different location and you can check the actual directory paths by typing:

bash
clang -print-search-dirs | tr ':' '\n'
# gcc -print-search-dirs
  1. (1 pt) What is the meaning (not its integer value) of the stream-based SEEK_CUR macro?

    • Start by using a keyword search on the man pages to find possible seek function calls (either from section 2 or 3)

      bash
      man -k seek
    • Use the man pages to discover which include files are referenced by those function calls.

    • Write a C code that includes the header file(s) you discovered in the previous step

      c
      #include <______.h>
      
      int main() {
        /* empty main which does nothing */
        return 0;
      }
    • Compile the above C program with following options

      bash
      gcc -E -CC -dD the-name-of-the-above-C-file.c  | less
      # OR use grep
      gcc -E -CC -dD the-name-of-the-above-C-file.c  | grep SEEK_CUR
    • Use the less search shortcut (the same '/' shortcut used for word search within a man page) to search for SEEK_CUR or use grep as shown.

  2. (1 pt) What is the command to list the contents of a directory in "long mode", including hidden files?

  3. (1 pt) What is the command syntax to make a directory readable/writable only by you?

Program Development

The typical program development cycle consists of Edit-Compile-Run-Debug sessions that repeat until the program functions as specified.

Edit

There are several text editors available on the system. Among these editors, vi is always available on every Unix system. Current Linux distributions provide vim (Vi IMproved) as part of the basic utilities. Another powerful text-based editor is emacs. Some of the choices of graphical text editors are: gvim, gedit, kate, kwrite)

Compile

Use either clang or gcc to compile your C programs. (Use clang++ or g++ for C++). Check out the man pages for useful command line options. In addition, always enable the "all" warning option (i.e -Wall). Sometime, you may also need to link your program with specific libraries (e.g. use the -lm flag to link with the math library). One of the biggest differences between C and C++ or Java is the C standard I/O library, so you should also do a man on printf() for output and scanf() for input to understand C-style I/O.

The basic command line for compiling a C or C++ program:

bash
clang -Wall -g name-of-your-C-program.c
# gcc -Wall -g name-of-your-C-program.c
clang++ -Wall -g name-of-your-C++-program.cpp
# g++ -Wall -g name-of-your-C++-program.cpp

# Use -lm if you need to link with the math lib
clang -Wall -g name-of-your-C-program.c -lm
gcc -Wall -g name-of-your-C-program.c -lm

Run

Unless the -o option is specified, a successful compilation of a C program will generate an executable file a.out. To run this program you will type either

bash
a.out

or

bash
./a.out

depending on how your PATH is configured. Recall that the prefix "./" refers to the directory you are currently in.

Debug

Use gdb to debug your programs. Debuggers can be very useful, not only to determine the source of problems in a program, but also to understand program execution better. Remember to compile your C (or C++) programs with the -g option to inform the compiler to include debugging information in the executable. Use ddd for a graphical frontend to gdb.

The following list shows some useful (sub)commands of gdb:

CommandDescription
helpself-explanatory
bset a breakpoint (to stop program execution at the specified location or function name)
lshow source code listing around the current line
ncontinue to the next line in a program (steps over function calls)
sstep to the next instruction in a program (steps into function calls)
run arg(s)run the program and pass arg(s) as the command line arguments of the program.
pdisplay (print) the value of a variable
wdisplay (watch) the value of a variable whenever it changes
btdisplay (backtrace) the current program execution stack

Sample Program #1

[Gist]

API rate limit exceeded for 54.209.88.255. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

  1. (2 pts) Perform the following steps:
    • Create the above program

    • Compile the program (remember to include debugging flag and link all necessary libraries)

      bash
      # This command is incomplete. You must include the math lib
      clang -Wall -g name-of-your-program.c
      # gcc -Wall -g name-of-your-program.c
    • Run the program (without a debugger)

      bash
      ./a.out
    • Start the debugger on your program (gdb a.out).

      bash
      gdb ./a.out
    • Do the following in the debugger session:

      • Set a breakpoint at the function main

        bash
        (gdb) b main
      • grab a screenshot of the debugger session

      • Run your program again, and step through it. When running the debugger

        bash
        (gdb) run
        (gdb) n      # continue to the [n]ext instruction

        WARNING

        you may receive a warning about missing debuginfos (which can be ignored)

        Missing separate debuginfos, use debuginfo-install glibc-2.xxxxxxx.x86_64
      • Use the debugger to print the value of num before and after it changes

        bash
        (gdb) p num
      • grab another screenshot of the debugger session

      • quit the debugger

        bash
        (gdb) q
    • Print/submit the screenshots as part of your lab reportß

Dynamic Memory Debugging

In the following section we will perform a more specific kind of debugging: (dynamic) memory debugging. In particular, we want to use tools that allow us to examine a program's use of memory while it is executing (hence "dynamic"). Proper use of these tools allows us to catch common memory errors (memory leaks, attempting to access de-allocated memory, attempting to access beyond allocated memory, etc.).

Finding Memory Leaks (Sample Program #2)

[Gist]

API rate limit exceeded for 54.209.88.255. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

Study the above code until you are certain of what it does. If necessary, open the manual page of malloc to learn more about the system calls. Although it appears to run correctly, there is a memory leak within the loop that will cause a problem if the loop is executed a sufficient number of times. There is also another apparent instance of "unrecovered" memory; it occurs outside the loop and is a less serious problem.

We will use valgrind to detect memory problems. Type the following at the command prompt:

bash
# Be sure to compile with -g
gcc -g name_of_your_program.c
valgrind --leak-check=full ./a.out

It takes some practice and good guessing to understand the errors identified in valgrind output.

Run the program and be sure the loop executes several times before typing "quit". Use the line numbers provided valgrind and your understanding of the code and the pattern of memory losses to determine the source of error.

  1. (2 pts) Describe precisely (nature of problem, location) the memory leak(s) in the above program.

    • Fix the problem(s) by adding necessary free() call(s). But, don't change the malloc() calls, mark your modification(s) with readable C comments
    • Add your name(s) as a C comment at the beginning of source code.
    • Print and submit the modified source code
    • To confirm that the memory leaks have been fixed, use valgrind again on your revised code.

Execution Debugging

The next utility program we will use in this lab is stracewhich is designed for profiling flow of execution through a program and its use of system/library calls.

TIP

Please read the man pages to discover strace operation and use

  • Run strace on the original Sample 2. You will see voluminous output generated by strace

    bash
    strace ./a.out
  • Read the manual again to discover the command-line option to get a less cluttered output in order to answer the next question below. Hint: look for "Filtering" option.

  1. (1 pt) How many times is the write() system call invoked when running Sample 2?. Note: run several different experiments, then try to answer as a formula.

  2. (1 pt) Use the example the source code and experiment to answer the question: what is the primary C library subroutine that causes the write() system call to be invoked by Sample 2?