If you do not finish during the lecture period, please finish it as homework.
Write a Cgo program that reads the hostname from the libc function gethostname
and prints it to the console.
The corresponding C function is defined in unistd.h
and can be used as follows:
#include<unistd.h>
#include<stdio.h>
int main() {
char buffer[256];
gethostname(buffer, 256);
printf("%s\n", buffer);
return 0;
}
Start with the function GetHostname
that calls the C function and returns the hostname as a Go string.
func getHostname() string {
// TODO implement
}
Use C.char for the type char and C.GoString to convert the resulting C string to a Go string.
In the same way as in the previous exercise write a Cgo program that creates a new SQLITE database file and executes the following statements:
create table if not exists students
(
id integer not null primary key autoincrement,
name text
);
insert into students (name)
values ('Your Name');
insert into students (name)
values ('Another Name');
Write your own Cgo wrapper. Verify the content of the database using any SQLITE inspector (e.g. IntelliJ or https://sqlitebrowser.org/).
Windows users can use the Windows Subsystem for Linux and install the following packages:
sudo apt install gcc golang sqlite3 libsqlite3-dev
Here is an example code of how to use the libs
// compile with gcc sqlite.c -lsqlite3
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
void Exec(sqlite3 *db, char *sql) {
int rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
if (rc != SQLITE_OK) {
printf("sqlite3_open returned code %i", rc);
exit(1);
}
}
int main() {
sqlite3 *db;
int rc = sqlite3_open("test.db", &db);
if (rc != SQLITE_OK) {
printf("sqlite3_open returned code %i", rc);
return 1;
}
Exec(db, "create table if not exists students (id integer not null primary key autoincrement, name text);");
Exec(db, "insert into students (name) values ('Your Name');");
Exec(db, "insert into students (name) values ('Another Name');");
sqlite3_close(db);
return 0;
}
Hints:
- You can define your own database object with
var db *C.sqlite3
- Use
C.CString
to convert a Go string to a C string
Choose either the FUSE Filesystem Exercise or the Containerer Exercise.
Experiment with the test filesystem.
https://github.com/s-macke/concepts-of-programming-languages/blob/master/src/system/fuse/main.go
- Try to make the INode of each file unique or limit to one file first.
- Implement "write" to file capabilities. Store the content in RAM.
- Allow to create new files inside the directory.
Download the alpine distribution at https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/x86_64/alpine-minirootfs-3.16.3-x86_64.tar.gz Then create a new directory and extract the tarball into it and run chroot.
# prepare chroot
mkdir -p jail
cd jail
tar -xvzf PATH/TO/alpine-minirootfs-3.16.3-x86_64.tar.gz
cd ..
# run chroot and start the shell via /bin/sh
sudo chroot jail /bin/sh
# mount the process information pseudo-file system
mount -t proc none /proc
Look at the directory structure of the chroot environment and check, that you are inside of the jail.
Return to the host system with exit
Questions:
- What is your user id inside and outside of the container? (Hint
id
) - Can you see the processes outside of the chroot environment? (Hint:
ps aux
) - What is the pid (process id) inside and outside of the container of your shell
/bin/sh
? (Hintpstree -p
orps aux
)
func main() {
switch os.Args[1] {
case "run":
run()
default:
panic("help")
}
}
func must(err error) {
if err != nil {
panic(err)
}
}
func run() {
log.Printf("Running %v \n", os.Args[1:])
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
must(cmd.Run())
}
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWPID | syscall.CLONE_NEWUSER | syscall.CLONE_NEWUTS,
UidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getuid(),
Size: 1,
},
},
GidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getgid(),
Size: 1,
},
},
}
Questions:
- Try changing the hostname again. What is the hostname if you exit the container?
- Call
ps
. What do you see?
- Copy the run function and name the copy child().
- Remove cmd.SysProcAttr in the child() function.
- Modify the run() function to execute the following instead:
cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...)
Questions:
- Call
ps
. What do you see?
Use the alpine mini root as in the first part of the exercise.
In the child() function, add the following code:
must(syscall.Chroot("/jail")) // local fs
must(os.Chdir("/"))
must(syscall.Mount("proc", "proc", "proc", 0, ""))
must(cmd.Run())
must(syscall.Unmount("proc", 0))
Questions:
- Call
ps
. What do you see?