COMP 3150Operating Systems

01 Objectives

By the end of this laboratory you will be able to

  • Navigate the Linux file system and manage files and directories using the shell.
  • Inspect and modify file permissions and ownership.
  • Inspect users and groups on a running system.
  • Write a small shell script that performs a real task and handles errors.
  • Compile a multi-file C program using the GCC / Make / Git / GDB workflow.
  • Produce a lab report documenting each step and the reasoning behind it.

02 Background

Every subsequent laboratory in this course assumes you can work fluently in the Linux shell. Lab 1 is where that fluency is built. The exercises here are deliberately small — the goal is not complexity, but familiarity with the tools you will rely on for the rest of the course.

The laboratory has four parts. Part A explores the file system and the shell. Part B examines permissions and users. Part C writes a small shell script and runs it. Part D builds a multi-file C program using the full toolchain and answers questions about the intermediate stages. Each part produces artifacts that go into the lab report.

Complete Lesson 1.0 and Lesson 2.5 first

This lab assumes you have completed the course VM setup (Lesson 1.0) and the development environment setup (Lesson 2.5). If gcc --version does not produce output, or ~/comp3150/ does not exist, return to those lessons before continuing.

03 Setup

Create your lab workspace and initialize a Git repository:

$ mkdir -p ~/comp3150/labs/lab-1
$ cd ~/comp3150/labs/lab-1
$ git init
Initialized empty Git repository in /home/alice/comp3150/labs/lab-1/.git/

$ cat > .gitignore << 'EOF'
*.o
lab1
build/
EOF

$ git add .gitignore
$ git commit -m "Initialise Lab 1 workspace"

Before you begin, take a snapshot of the VM named before-lab-1. If anything goes wrong during the lab, you can revert to this snapshot and start over.

04 Part A — File-system navigation

Complete the following steps in your lab directory. For each, record the command you used and the observed output in your lab report.

  1. Establish your workspace. Print the current working directory, then create a nested directory structure:
    mkdir -p src docs tests
    cd src
    touch main.c util.c
    cd ../docs
    touch notes.txt
    cd ../tests
    touch test_cases.txt
    cd ..
    Confirm the structure with find . -print.
  2. Practice navigation. From the lab directory:
    • Change into src using a relative path.
    • Change back to the lab directory using ...
    • Change into src using an absolute path.
    • Change into docs, then cd .., then cd - (this returns to the previous directory).
    Record the sequence of pwd outputs.
  3. Explore the system tree. Run the following and record one line of meaningful output from each:
    ls /etc | head -5
    ls /usr/bin | wc -l
    ls -la ~ | head -10
    ls -l /boot
    For the last command, how many files are in /boot? Which user owns them?
  4. Inspect a file's metadata. Write a short text file and inspect it with stat:
    echo "Laboratory 1" > docs/notes.txt
    stat docs/notes.txt
    Identify each of the following fields in the output and explain what it means: Size, Blocks, Access, Modify, Change. Add this analysis to your lab report.
  5. Use a pipeline. Count how many processes on the system are running as the root user:
    ps -ef | awk '$1 == "root"' | wc -l
    Then count how many distinct users have at least one running process:
    ps -ef | awk 'NR>1 {print $1}' | sort -u | wc -l
    Record both numbers and explain what they tell you about the workload on your VM.

05 Part B — Permissions, users, and groups

  1. Inspect your own identity. Run each of the following and interpret the output:
    id
    whoami
    groups
    echo $HOME
    echo $PATH
    What is your UID? What is your primary GID? How many supplementary groups do you belong to?
  2. Create and inspect permissions. Create a test file and observe its default mode:
    touch perm-test.txt
    ls -l perm-test.txt
    The mode is determined by the umask. Run umask and record the value. Then verify the formula from Lesson 2.4: 666 & ~umask should equal the observed mode.
  3. Modify permissions with symbolic notation. Apply each of the following and record the mode after each change:
    chmod u+x perm-test.txt
    ls -l perm-test.txt
    chmod g-w perm-test.txt
    ls -l perm-test.txt
    chmod o-r perm-test.txt
    ls -l perm-test.txt
    chmod u=rw,go=r perm-test.txt
    ls -l perm-test.txt
  4. Modify permissions with octal notation. Apply each of the following and record the resulting mode:
    chmod 644 perm-test.txt
    chmod 600 perm-test.txt
    chmod 000 perm-test.txt
    chmod 755 perm-test.txt
    After chmod 000, try to read the file with cat perm-test.txt. What happens? Can you restore access?
  5. Set the umask and observe its effect. Run:
    umask 077
    touch private.txt
    mkdir private-dir
    ls -l private.txt
    ls -ld private-dir
    
    umask 022
    touch public.txt
    mkdir public-dir
    ls -l public.txt
    ls -ld public-dir
    For each new file and directory, verify that the mode matches the formula from Lesson 2.4. Record the observed modes and your calculations in your lab report.
  6. Inspect a system user account. Look up the entry for your own account in the account database:
    grep "^$(whoami):" /etc/passwd
    grep "^$(whoami):" /etc/group
    Identify each field in the /etc/passwd line. What is your login shell? What is your home directory?
  7. Examine setuid binaries. List every setuid binary on the system:
    sudo find / -perm -4000 -type f 2>/dev/null
    For three of them, look up what the program does and explain in one sentence why it needs elevated privileges. Add this analysis to your lab report.

06 Part C — Shell scripting

Write a shell script called sysinfo.sh in your lab directory. The script reports a summary of the current system's state. It must satisfy the following requirements:

  1. Accept an optional command-line argument. If the argument is --verbose, the script prints additional detail. If any other argument is supplied, the script prints an error and exits with a non-zero status.
  2. Print a header line that includes the current date and the current user.
  3. Print the hostname, kernel version, and CPU architecture.
  4. Print the number of processes currently running (you may use ps -e --no-headers | wc -l).
  5. Print the total and available memory (you may use free -h).
  6. Print the total and free disk space on the root file system (you may use df -h /).
  7. If the --verbose flag is supplied, also print the current umask and the contents of the PATH environment variable.

The script must handle the following errors gracefully:

  • If a command it depends on is missing, it must print a clear error and exit with a non-zero status.
  • Any temporary files it creates must be cleaned up on exit, including on error.

When you have written the script:

  1. Make it executable: chmod +x sysinfo.sh.
  2. Run it without arguments. Capture the output.
  3. Run it with --verbose. Capture the output.
  4. Run it with an invalid argument. Capture the output and the exit code (use echo $? after the run).
  5. Run shellcheck sysinfo.sh if available in your VM. Note any warnings.
  6. Commit the script to your Git repository with a descriptive message.

07 Part D — Toolchain

Build a small multi-file C program using the full toolchain from Lesson 2.5. The program will compute factorials and print a table.

  1. Write the source files. Create three files:
    /* factorial.h */
    #ifndef FACTORIAL_H
    #define FACTORIAL_H
    long factorial(int n);
    #endif
    /* factorial.c */
    #include "factorial.h"
    long factorial(int n) {
        long result = 1;
        for (int i = 1; i <= n; i++) result *= i;
        return result;
    }
    /* main.c */
    #include <stdio.h>
    #include <stdlib.h>
    #include "factorial.h"
    
    int main(int argc, char **argv) {
        if (argc != 2) {
            fprintf(stderr, "usage: %s N\n", argv[0]);
            return 1;
        }
        int n = atoi(argv[1]);
        for (int i = 1; i <= n; i++)
            printf("%2d! = %ld\n", i, factorial(i));
        return 0;
    }
  2. Inspect the compilation pipeline. Run each of the following and record the size of the resulting intermediate file:
    gcc -E main.c -o main.i
    gcc -S main.c -o main.s
    gcc -c main.c -o main.o
    wc -l main.i main.s
    ls -lh main.i main.s main.o
    Describe in your lab report what each stage did.
  3. Write a Makefile. Create a Makefile that builds the program from the two object files. The default target should link the executable; there should also be a clean target. Use variables for the compiler and flags.
  4. Build and test. Run make to build the program. Run ./lab1 10 and confirm the output shows 1! through 10!. Then modify only factorial.c (add a comment line) and run make again. Did it recompile main.c? Explain.
  5. Compile with warnings. Rebuild with -Wall -Wextra -Werror added to the flags. Does the build still succeed? If it fails, fix the warnings.
  6. Debug with GDB. Introduce a deliberate bug into factorial.c — for example, change the loop condition to i < n instead of i <= n. Rebuild and run ./lab1 5. The output will be wrong. Then use GDB to identify the bug:
    gdb ./lab1
    (gdb) break factorial
    (gdb) run 5
    (gdb) print n
    (gdb) print i
    (gdb) continue
    (gdb) print result
    (gdb) quit
    Describe the exact point at which the divergence occurred. Fix the bug and verify the corrected output.
  7. Commit your work. Add all source files and the Makefile to Git and commit with a descriptive message.

08 Deliverables

Submit the following as your Lab 1 deliverables. Include them in a single archive or in the Git repository as instructed.

  • Source files: factorial.h, factorial.c, main.c, Makefile, and sysinfo.sh.
  • Lab report (Markdown, PDF, or plain text) with the following sections:
    1. Setup. Describe the VM configuration and any issues encountered.
    2. Part A. The recorded outputs from every step. Include a short paragraph explaining the significance of one observation.
    3. Part B. The recorded permission changes with the octal modes after each. The setuid analysis for three binaries. A short discussion of why setuid is a security concern.
    4. Part C. The complete script, the captured output for all three invocations, and the exit code for the invalid invocation.
    5. Part D. The intermediate file sizes, the description of each compilation stage, the effect of the incremental rebuild, the GDB session with the fix, and an explanation of the bug's root cause.
    6. Reflection. A 200–300 word reflection on what you learned that you did not already know before the lab.

09 Grading rubric

Lab 1 grading rubric
Criterion Weight What it evaluates
Part A — file-system navigation15%Accurate completion of all steps, correct interpretation of stat fields, well-formed pipeline observation.
Part B — permissions and users20%Correct permission changes with octal verification, umask calculation, setuid analysis, understanding of the security implications.
Part C — shell script25%Script satisfies all requirements, handles argument parsing and errors correctly, cleans up temporary files, is readable and idiomatic.
Part D — toolchain25%Program builds and runs, Makefile correct, incremental rebuild behaviour demonstrated, GDB session identifies the bug, correct explanation of root cause.
Report quality15%Clear structure, correct use of technical terminology, evidence of reasoning rather than mechanical transcription, reflection demonstrates learning.
Total100%

10 Summary

  • Lab 1 established your Linux workspace and verified that the development toolchain is complete.
  • You practised file-system navigation, permission modification, and umask behaviour — the skills assumed by every subsequent lab.
  • You wrote a shell script that handles errors and cleans up after itself — the shape of the automation scripts you will write throughout the course.
  • You built a multi-file C program with Make and debugged it with GDB — the workflow that every programming assignment in this course will follow.
👤