COMP1521 Revision 11 Sample Solutions

Revision Exercise: Print file contents (PS)

write a c program show_file so that, given a single command line argument containing the path to a file, it reads and prints the contents of that file to standard output. For example:

cat sample.txt
Hello, world!
./show_file sample.txt
Hello, world!
cat three_lines.bin
one
two
three
./show_file three_lines.bin
one
two
three

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest show_file

Revision Exercise: Copy File (PS)

Write a C program copy_file so that, given two command line arguments — the first being the path to a source file to be read, and the second being the path to a destination file — it copies the contents of the source file to the destination file.

If the destination file already exists, it should be overwritten.
If the destination file does not exist, it should be created.

For example:

echo "Hello, world!" > sample.txt
cat sample.txt
Hello, world!
./copy_file sample.txt copy.txt
cat copy.txt
Hello, world!

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest copy_file

Revision Exercise: Print the type of a file (PS)

Write a C program file_type so that, given one command line argument — the path to a source file. print out whether the file is a regular file, a directory, or a symbolic link.

For example:

echo "HIIII" > sample.txt
./file_type sample.txt
file
mkdir some_directory
./file_type some_directory
directory
ln -s sample.txt some_symlink
./file_type some_symlink
symbolic link

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest file_type

Revision Exercise: Remove the first half of a file (PS)

Computer viruses are pieces of code that infect computers and can corrupt data and replicate themselves. An example of this would be a virus that deletes the first half of files. For educational purposes only you'll be writing a c program to do this.

Write a C program halving_virus so that, given one command line argument, a path to a file, it removes the first half of the file. That is to say, if the source file is four bytes long, bytes 2, 3 should be kept in the file and bytes 0, 1 should be removed from the file.
Odd file sizes are to be rounded such that a source file that has 5 bytes should only keep bytes 3, 4, 5.

If the size of the source file is less than or equal to one byte, your program should remove all contents of the file.

For example:

echo "Hello, world!" > sample.txt
cat sample.txt
Hello, world!
./halving_virus sample.txt
Halved sample.txt
cat sample.txt
world!
echo 1234 > five_bytes.txt
cat five_bytes.txt
1234
./halving_virus five_bytes.txt
Halved five_bytes.txt
cat five_bytes.txt
34
echo 123 > four_bytes.txt
cat four_bytes.txt
123
./halving_virus four_bytes.txt
Halved four_bytes.txt
cat four_bytes.txt
3

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest halving_virus

Revision Exercise: Extract File Permissions (PS)

Write a C program extract_permissions so that, given one command line argument — the path to a source file. Print out the equivalent octal number of the permission, it's bitwise representation, and the formatted permissions string.


To get For example:
# copy and run the following commands to make some example files
mkdir examples; touch examples/000.s examples/777.c examples/sample.txt
chmod 000 examples/000.s
chmod 777 examples/777.c
ls -l examples
total 0
---------- 1 z5555555 z5555555 0 Apr 29 12:27 000.s
-rwxrwxrwx 1 z5555555 z5555555 0 Apr 29 12:27 777.c
-rw-r--r-- 1 z5555555 z5555555 0 Apr 29 12:27 sample.txt

./extract_permissions ./examples/sample.txt
Octal: 664, Bitwise: 110110100, String: rw-r--r--
./extract_permissions ./examples/000.s
Octal: 0, Bitwise: 000000000, String: ---------
./extract_permissions ./examples/777.c
Octal: 777, Bitwise: 111111111, String: rwxrwxrwx

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest extract_permissions

Revision Exercise: Hackerman (CR-DN)

Write a C program hackerman so that, given one command line argument — the directory to be searched, hackerman recursively searches through the directory and it's sub-directories to find passwords.

The password will always be the contents of a file named "password", although the file's extension may vary. (e.g. password.bin, password, password.txt are all valid password files!!)

For security purposes, the admins have limited your ability to access certain files and directories, however passwords may be hidden behind these security measures and they will need to be found anyways. You should try to change the permissions of files and directories you find to gain access. To do this you can use chmod(2) to make the file public and group readable.

If the password is found, print the password to stdout along with the filename where it was found.
If the password cannot be found, your program should print "Passwords not found\n" and then exit(3) with status 0

Use the following command to get a directory to test your program with

cp -r  /web/cs1521/25T1/activities/hackerman/hackerman_examples .

For example:

# copy and run the following commands get a directory to test your program on
cp -r  /web/cs1521/25T1/activities/hackerman/hackerman_examples .
ls -l hackerman_examples
total 16
drwxrwxrwx 2 z5555555 z5555555 4096 Feb  5 22:49 empty
drwxrwxrwx 2 z5555555 z5555555 4096 Feb  5 22:32 inner_folder
-rwxrwxrwx 1 z5555555 z5555555    8 Feb  5 22:16 password.txt
drwxrwxrwx 2 z5555555 z5555555 4096 Feb  5 22:36 security_folder
cat hackerman_examples/inner_folder/password
prettier
./hackerman hackerman_examples/inner_folder
Password heheheha found in 1521/admins/passwords/password.txt
cat hackerman_examples/security_folder/password.bin
cat: hackerman_examples/security_folder/password.bin: Permission denied
./hackerman hackerman_examples/security_folder
Password "hidden behind a firewall!" found in hackerman_examples/security_folder/password.bin
cat hackerman_examples/password.txt
glazeeee
./hackerman hackerman_examples
Password prettier found in hackerman_examples/inner_folder/password
Password glazeeee found in hackerman_examples/password.txt
Password "hidden behind a firewall!" found in hackerman_examples/security_folder/password.bin
ls -l hackerman_examples/empty
total 4
-rwxrwxrwx 1 z5360323 z5360323 9 Feb  5 22:49 pword_in_body
./hackerman empty
Passwords not found

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest hackerman

Revision Exercise: JSON decoder (CR)

Write a C program json_decoder so that, given two or more command line arguments — the first being the path to a source file to be read, and the rest being keys. your program should print the value of that key to stdout.

If the key is not found, print nothing.

as a reminder, JSON follows this generic format:
{
"key1": value1,
"key2": value2,
...
}


Run the following command to get an example JSON file to test your program with

cp /web/cs1521/25T1/activities/json_decoder/files.ln/months.json .

For example:

    cat months.json
    {
        "january": 1,
        "february": 2,
        "march": 3,
        "april": 4,
        "may": 5,
        "june": 6,
        "july": 7,
        "august": 8,
        "september": 9,
        "october": 10,
        "november": 11,
        "december": 12,
        "selected": "may"
    }    
    ./json_decoder months.json august
    8
    ./json_decoder months.json selected
    "may"
    ./json_decoder months.json january december
    1 12
    ./json_decoder months.json pluto
    this should print nothing!
    

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest json_decoder

Revision Exercise: Detect C Files (CR)

Run the following commands to get the files required for this question:

cp -n /web/cs1521/25T1/activities/detect_c_files/files.cp/detect_c_files.c detect_c_files.c
cp -n /web/cs1521/25T1/activities/detect_c_files/files.ln/check_c_file.c detect_c_file.c
cp -r /web/cs1521/25T1/activities/detect_c_files/detect_c_file_examples detect_c_files_examples

Add code to detect_c_files.c so that when given a list of pathnames as command line arguments, it checks each to see if it's a c file or not.

We have provided a c program check_c_file.c which takes a single pathname as a command line argument, and returns 1 if given a c file and 0 otherwise.

There are two parts to this question. First in the main function spawn a process to compile check_c_file.c.

Secondly, complete the spawn_programs function so that given a list of filenames, and the length of that list, you spawn processes to run ./check_c_file in parallel on each filename.

You should wait for each child process to return (see waitpid(3)), then use the return value to print whether the file is or is not c program.

dcc detect_c_files.c -o detect_c_files
./detect_c_files detect_c_files.c check_c_file.c
detect_c_files.c is a C file
check_c_file.c is a C file
./detect_c_files detect_c_files.c detect_c_file_examples/*
detect_c_files.c is a C file
detect_c_file_examples/a.txt is NOT a C file
detect_c_file_examples/b.txt is NOT a C file
detect_c_file_examples/hello.c is a C file
detect_c_file_examples/hello.txt is NOT a C file
detect_c_file_examples/nonsense.c is a C file
detect_c_file_examples/test.s is NOT a C file
detect_c_file_examples/trick.c is a C file

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest detect_c_files

Revision Exercise: Append Date to File (DN)

Download date_file.c, or copy it to your CSE account using the following command:


cp -n /web/cs1521/25T2/activities/date_file/files.cp/date_file.c date_file.c

Your task is to add code to this function in date_file.c:

void append_date_to_file(char *filename) {
    // TODO: complete this function

    return;

}

Add code to the function append_date_to_file so that given a filename, you append the current date to the end of the file.
For example:

echo "helllooooo" > hi.txt
cat hi.txt
helllooooo
./date_file hi.txt
Appended date to hi.txt
cat hi.txt
helllooooo
Mon Apr 28

To do this, you should use posix_spawn to run the date command, with the following format string:

date '+%a %b %d'
Mon Apr 28

You will need to use pipes with posix spawn to capture the output and redirect it into the file. The lecture example spawn_read_pipe.c is an example of how to do this.

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest date_file

Revision Exercise: Robot Arms: threads and mutex (DN)

Download robot_arms.c, or copy it to your CSE account using the following command:


cp -n /web/cs1521/25T2/activities/robot_arms/files.cp/robot_arms.c robot_arms.c

In this question we are writing code to automate a robot manufacturing line. The robot we're making has four arms, each made using some of three components. To make robots as quickly as possible we're going to do it in parallel using threads.

You have been given robot_arms.c, which contains an empty main function, and four thread functions; arm1, arm2, arm3, and arm4. Each "assembles" a robot arm using a mix of components; component A, component B, and component C.

In main, you should create four threads to do the arm1, arm2, arm3, and arm4 in parallel.
You should wait until all four threads have finished before you return from main.

There are three components, A, B and C, each component can only be used to make one arm at a time. We use mutexes component_A_mutex, component_B_mutex, and component_C_mutex to represent them.

You should add code to lock and unlock each component mutex when the arm functions are using them. You should use pthread_mutex_lock(3) to lock the component before the arm acquires it, and pthread_mutex_unlock(3) once the arm is finished assembling.

Think about how you can avoid deadlock - a state where all arms are waiting for components held by others.

When your program is working, it should look like this:

dcc -pthread robot_arms.c -o robot_arms
./robot_arms
Arm 1 acquired Component A
Arm 2 acquired Component C
Arm 2 acquired Component B
Arm 2 is assembling
Arm 1 acquired Component C
Arm 1 is assembling
Arm 4 acquired Component A
Arm 4 acquired Component B
Arm 4 is assembling
Arm 3 acquired Component C
Arm 3 acquired Component A
Arm 3 is assembling

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest robot_arms

Revision Exercise: Implement a least-recently-used replacement algorithm

Your task is to simulate least-recently-used (LRU) replacement of virtual memory pages.

Write a C program, lru.c, which takes two arguments, both integers.

This will be respectively the size in frames of simulated physical memory and and the size in pages of simulated virtual memory.

lru.c should then read integers from stdin until EOF.

Each integer will be the number of a virtual page being accessed.

lru.c should print one line of output for indicate what action occurs with a physical memory with a given number of frames.

dcc lru.c -o lru
./lru 4 6
Simulating 4 frames of physical memory, 6 pages of virtual memory
5
Time 0: virtual page 5 loaded to physical frame 0
3
Time 1: virtual page 3 loaded to physical frame 1
5
Time 2: virtual page 5 -> physical frame 0
3
Time 3: virtual page 3 -> physical frame 1
0
Time 4: virtual page 0 loaded to physical frame 2
1
Time 5: virtual page 1 loaded to physical frame 3
2
Time 6: virtual page 2  - virtual page 5 evicted - loaded to physical frame 0
2
Time 7: virtual page 2 -> physical frame 0
3
Time 8: virtual page 3 -> physical frame 1
5
Time 9: virtual page 5  - virtual page 0 evicted - loaded to physical frame 2

The provided code includes an array containing a data structure mapping each physical frame to a virtual page, as well as its last access time. This is known as an inverted page table.

For each access this function is called:

INTERNAL ERROR MISSING FILE: "./activities/lru/activities/lru/files.cp/lru.c"

Note that the fourth argument, struct ipt_entry *ipt, is a pointer to the inverted page table. It can be effectively indexed as an array, e.g. ipt[0] is the first entry.

You can complete the lab by adding code to this function (you are also free to write your own program from scratch if you prefer).

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest lru

Revision Exercise: Implement address translation

You have been provided a stub C program, addr_translation.c, as follows.

Your task is to add code to this function in addr_translation.c:

INTERNAL ERROR MISSING FILE: "./activities/addr_translation/activities/addr_translation/files.cp/addr_translation.c"

Add code to the function addr_translation so that, given a uint32_t virtual address, it returns the corresponding uint32_t physical address.

The code in addr_translation_main.c will read from a file containing page table entries, and will load these entries into a hash map data structure. You aren't required to understand how this works, but you will need to make use of the hashmap_get function defined in addr_translation.h in order to retrieve the page table entry for a given virtual page number.

The function will return a struct page_table_entry, also defined in addr_translation.h. This structure contains the physical frame number, and a boolean indicating whether the page is valid or not. If the page is not valid, the function should return INVALID_ADDRESS. If there is no entry in the page table for the given virtual page number, hashmap_get will return NULL, and you should also return INVALID_ADDRESS.

Virtual addresses are structured so that the top 20 bits are the virtual page number, and the bottom 12 bits are the offset within the page.

Physical addresses are structured identically, except the top 20 bits are the physical frame number instead of the virtual page number.

Your goal is to use bitwise operations to extract the virtual page number from the virtual address, and then use the page table to find the physical page number. You should then combine the physical frame number with the offset to form the physical address. For example:

unzip examples.zip
... extracting ...
dcc -o addr_translation addr_translation.c addr_translation_hashmap.c addr_translation_main.c
cat examples/page_table_small.vpt
0 0xcd5f8
1 0x7156f 0x43d5b
1 0x3506f 0x1d2a4
1 0xe33be 0xa8ba0
1 0x0cb02 0xda99b
0 0x698d4
./addr_translation examples/page_table_small.vpt
0x7156ffff
0x43d5bfff
0x7156efff
0x00000000
0xcd5f8340
0x00000000
0x0cb02e8a
0xda99be8a

When you think your program is working you can use autotest to run some simple automated tests:

1521 autotest addr_translation