diff --git a/chapters/app-interact/Makefile b/chapters/app-interact/Makefile new file mode 100644 index 0000000000..5daac051e1 --- /dev/null +++ b/chapters/app-interact/Makefile @@ -0,0 +1,35 @@ +# The script expect the source .svg files to be named as $TARGET-$i.svg, where $i is the frame number. +TARGETS = synchronization interruption +RVMD = reveal-md +MDPP = markdown-pp +FFMPEG = ffmpeg + +SLIDES ?= slides.mdpp +SLIDES_OUT ?= slides.md +SITE ?= _site +OPEN ?= xdg-open + +.PHONY: all html clean videos + +all: videos html + +html: $(SITE) + +$(SITE): $(SLIDES) + $(MDPP) $< -o $(SLIDES_OUT) + $(RVMD) $(SLIDES_OUT) --static $@ + +videos: + for TARGET in $(TARGETS); do \ + TARGET_DIR=$$(find -name $$TARGET -type d | grep media); \ + MEDIA_DIR=$$(dirname $$TARGET_DIR); \ + $(FFMPEG) -framerate 0.5 -f image2 -y \ + -i "$$TARGET_DIR/$$TARGET-%d.svg" -vf format=yuv420p $$MEDIA_DIR/$$TARGET-generated.gif; \ + done + +open: $(SITE) + $(OPEN) $ +The method you need to call is `org.freedesktop.DBus.Properties.Get` from the `/org/freedesktop/UPower/devices/DisplayDevice` object. + + +This method needs 2 arguments: an interface name and a property name. + +Those should be `org.freedesktop.UPower.Device` and `Percentage` respectively. + + +Then input all of the above into a `gdbus` call, which, if everything is correct, should output the battery percentage level as a number between 0 and 100. + +Note: if you are running on a desktop computer or inside a virtual machine, you will get the value `0.0`, because those systems don't have a battery. + +If you're having difficulties solving this exercise, go through [this](../../../reading/dbus.md) reading material. diff --git a/content/chapters/app-interact/lab/solution/dbus/get_battery_level.py b/chapters/app-interact/dbus/drills/tasks/dbus/solution/get_battery_level.py similarity index 100% rename from content/chapters/app-interact/lab/solution/dbus/get_battery_level.py rename to chapters/app-interact/dbus/drills/tasks/dbus/solution/get_battery_level.py diff --git a/content/chapters/app-interact/lab/solution/dbus/get_battery_level.sh b/chapters/app-interact/dbus/drills/tasks/dbus/solution/get_battery_level.sh similarity index 84% rename from content/chapters/app-interact/lab/solution/dbus/get_battery_level.sh rename to chapters/app-interact/dbus/drills/tasks/dbus/solution/get_battery_level.sh index 0b22fd7161..b81d943e3c 100755 --- a/content/chapters/app-interact/lab/solution/dbus/get_battery_level.sh +++ b/chapters/app-interact/dbus/drills/tasks/dbus/solution/get_battery_level.sh @@ -1,3 +1,4 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause gdbus call --system --dest org.freedesktop.UPower --object-path /org/freedesktop/UPower/devices/DisplayDevice --method org.freedesktop.DBus.Properties.Get "org.freedesktop.UPower.Device" "Percentage" diff --git a/content/chapters/app-interact/lab/support/dbus/get_battery_level.py b/chapters/app-interact/dbus/drills/tasks/dbus/support/get_battery_level.py similarity index 100% rename from content/chapters/app-interact/lab/support/dbus/get_battery_level.py rename to chapters/app-interact/dbus/drills/tasks/dbus/support/get_battery_level.py diff --git a/content/chapters/app-interact/lab/support/dbus/send_notification.sh b/chapters/app-interact/dbus/drills/tasks/dbus/support/send_notification.sh similarity index 89% rename from content/chapters/app-interact/lab/support/dbus/send_notification.sh rename to chapters/app-interact/dbus/drills/tasks/dbus/support/send_notification.sh index 9de05f9926..fc7d56f25d 100755 --- a/content/chapters/app-interact/lab/support/dbus/send_notification.sh +++ b/chapters/app-interact/dbus/drills/tasks/dbus/support/send_notification.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause gdbus call \ --session --dest org.freedesktop.Notifications \ diff --git a/content/chapters/app-interact/lab/support/dbus/send_notification_strace.sh b/chapters/app-interact/dbus/drills/tasks/dbus/support/send_notification_strace.sh similarity index 90% rename from content/chapters/app-interact/lab/support/dbus/send_notification_strace.sh rename to chapters/app-interact/dbus/drills/tasks/dbus/support/send_notification_strace.sh index c3a708f684..ea058eedfe 100755 --- a/content/chapters/app-interact/lab/support/dbus/send_notification_strace.sh +++ b/chapters/app-interact/dbus/drills/tasks/dbus/support/send_notification_strace.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause strace -s 1000 -f -e trace=socket,connect,sendmsg,recvmsg \ gdbus call \ diff --git a/chapters/app-interact/dbus/guides/calling-dbus-methods/README.md b/chapters/app-interact/dbus/guides/calling-dbus-methods/README.md new file mode 100644 index 0000000000..278bc6c76b --- /dev/null +++ b/chapters/app-interact/dbus/guides/calling-dbus-methods/README.md @@ -0,0 +1,44 @@ +# Calling D-Bus Methods + +The application behind `org.freedesktop.Notifications` is responsible with desktop notifications (the small bubbles of text that appear at the top of the screen when some event happens). +When an application wants to send a notification it needs to connect to D-Bus and call the `Notify` method from the `org.freedesktop.Notifications` interface. + +In this example, we want to call the `Notify` method ourselves. +To do this, we must first understand the signature of this method: + +`Notify (String arg_0, UInt32 arg_1, String arg_2, String arg_3, String arg_4, Array of [String] arg_5, Dict of {String, Variant} arg_6, Int32 arg_7) ↦ (UInt32 arg_8)` + +This doesn't tell us much, but we can find more documentation [here](https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html#basic-design), since `freedesktop` is an open standard. + +We'll set the arguments to the following (for our simple case, most of them will be unused): + +- `app_name`: `""` + +- `replaces_id`: `0` + +- `app_icon`: `""` + +- `summary`: `"This is the title"` + +- `body`: `"This is the content"` + +- `actions`: `[]` + +- `hints`: `{}` + +- `expire_timeout`: `-1` + +Now the question is how to actually call the method. +Normally, we would have to write an application that connects to D-Bus and executes the call. +But for demonstrative purposes there are easier ways. + +One way is directly from d-feet. +If we double-click on the `Notify` method in the right-side pane of d-feet, a window will open that allows us to call the method with any arguments that we want: + +![dfeet-execute-dialog](../media/dfeet_execute.png) + +Then we click the `Execute` button and the notification will appear: + +![dfeet-execute-](../media/dfeet_execute.gif) + +Another way is from the command-line. There's the `gdbus` tool that can do this: diff --git a/chapters/app-interact/dbus/guides/dbus-dfeet/README.md b/chapters/app-interact/dbus/guides/dbus-dfeet/README.md new file mode 100644 index 0000000000..b2dc521536 --- /dev/null +++ b/chapters/app-interact/dbus/guides/dbus-dfeet/README.md @@ -0,0 +1,33 @@ +# D-Bus Inspection with D-Feet + +In order to better understand these concepts, we'll use a graphical tool (`D-Feet`) to inspect all the available D-Bus objects on our system. + +Run D-Feet and select `Session Bus` from the top button: + +![dfeet-session-bus](../media/dfeet_session_bus.png) + +On the left panel, we can see all the processes connected to D-Bus with their associated `connection names`. +Scroll down and find `org.freedesktop.Notifications`. +On the right side, expand `/org/freedesktop/Notifications` and then expand the `org.freedesktop.Notifications` interface. +The window should look like this: + +![dfeet-notifications](../media/dfeet_notifications.png) + +Some observations: + +- The bus communication happens over a Unix socket, with the path `/run/user/1000/bus`. + +- `org.freedesktop.Notifications` on the left panel is the `connection name`. + +- The process that has connected with this name is `/usr/bin/gjs /usr/share/gnome-shell/org.gnome.Shell.Notifications` and has the pid of `4373`. + +- This process exposes one object: `/org/freedesktop/Notifications`. +Note that the object name is the same as the connection name, where the dots have been replaced with slashes. +This is not a requirement, as the objects exposed by a process can have any name. + + +- The object has 4 interfaces: `org.freedesktop.DBus.Introspectable`, `org.freedesktop.DBus.Peer`, `org.freedesktop.DBus.Properties` and `org.freedesktop.Notifications`. +Note that the last one (`org.freedesktop.Notifications`) is the same as the connection name, but this again is just a coincidence, not a requirement. + + +- The interface `org.freedesktop.Notifications` has some methods that can be called, such as `Notify`. diff --git a/chapters/app-interact/dbus/guides/dbus-usage-python/README.md b/chapters/app-interact/dbus/guides/dbus-usage-python/README.md new file mode 100644 index 0000000000..a858dbe0b2 --- /dev/null +++ b/chapters/app-interact/dbus/guides/dbus-usage-python/README.md @@ -0,0 +1,21 @@ +# D-Bus usage in Python + +Use the `dbus` python bindings to get the computer's battery level using a python script. +You can start from the documentation [here](https://dbus.freedesktop.org/doc/dbus-python/tutorial.html#). +You need to read the sections `Connecting to the Bus`, `Proxy objects`, and `Interfaces and methods`. + +There's also a skeleton you can use in `chapters/app-interact/arena/support/dbus/get_battery_level.py`. + +In summary, your script will start by connecting to the `System Bus`. +Then you'll use the `get_object` method to obtain a proxy object. +On this proxy object, you can actually do the method call as explained [here](https://dbus.freedesktop.org/doc/dbus-python/tutorial.html#interfaces-and-methods): + +```text +To call a method, call the method of the same name on the proxy object, passing in the interface name via the dbus_interface keyword argument +``` + +So, if you want to call the method `this.is.an.interface.method` with the arguments `A` and `B` you can do it like this: + +```python +result = proxy.method(A, B, dbus_interface = "this.is.an.interface") +``` diff --git a/chapters/app-interact/dbus/guides/firefox/README.md b/chapters/app-interact/dbus/guides/firefox/README.md new file mode 100644 index 0000000000..48055f2275 --- /dev/null +++ b/chapters/app-interact/dbus/guides/firefox/README.md @@ -0,0 +1,61 @@ +# Firefox + +Let's do the following experiment: + +- Open the Firefox browser + +- From a terminal run `firefox www.google.com` + +![firefox-url-open](../media/firefox_url_open.gif) + +Notice that the URL we passed in the command-line was opened in the existing Firefox window as a new tab. +Even though we started a separate Firefox process, which should have created a separate new window, this didn't actually happen. +Instead, the process that we started from the command-line exited immediately and the site was opened in the already running Firefox instance. + +Without any precise knowledge about Firefox internals, we can guess that something like this happened: + +- The newly started Firefox process detected that another instance of Firefox is already running + +- The newly started Firefox process sent a message to the existing running process, requesting it to open a URL in a new tab + +Since we're talking about message passing between 2 processes, there's a chance that maybe D-Bus was involved. +Let's check: we'll use a tool called `dbus-monitor` that will print all messages passed through D-Bus. + +```console +student@os:~$ dbus-monitor +``` + +Then, in another terminal, we'll run `firefox www.google.com` again. + +Going back to the `dbus-monitor` output, we find the following: + +```console +... +method call time=1655809062.813923 sender=:1.757 -> destination=org.mozilla.firefox.ZGVmYXVsdC1yZWxlYXNl serial=2 path=/org/mozilla/firefox/Remote; interface=org.mozilla.firefox; member=OpenURL + array of bytes [ + 02 00 00 00 1a 00 00 00 2f 00 00 00 2f 68 6f 6d 65 2f 61 64 72 69 61 6e + 73 00 2f 6f 70 74 2f 66 69 72 65 66 6f 78 2f 66 69 72 65 66 6f 78 00 77 + 77 77 2e 67 6f 6f 67 6c 65 2e 63 6f 6d 00 + ] +``` + +There was a D-Bus call to `org.mozilla.firefox.ZGVmYXVsdC1yZWxlYXNl`, on the object `/org/mozilla/firefox/Remote`, method `OpenURL` from the `org.mozilla.firefox` interface. +Indeed, we see that this object exists in d-feet as well: + +![dfeet-firefox](../media/dfeet_firefox.png) + +We can try to call the `OpenURL` method ourselves, directly from d-feet. +The method has only one argument of the type `Array of [Byte]`. +Although there's no documentation for it, we can use the same byte array that we saw in `dbus-monitor`: + +```console + array of bytes [ + 02 00 00 00 1a 00 00 00 2f 00 00 00 2f 68 6f 6d 65 2f 61 64 72 69 61 6e + 73 00 2f 6f 70 74 2f 66 69 72 65 66 6f 78 2f 66 69 72 65 66 6f 78 00 77 + 77 77 2e 67 6f 6f 67 6c 65 2e 63 6f 6d 00 + ] +``` + +(Note that `77 77 77 2e 67 6f 6f 67 6c 65 2e 63 6f 6d` at the end is the string `www.google.com`, so that's another confirmation that we're on the right track). + +![dfeet-url-open](../media/dfeet_url_open.gif) diff --git a/chapters/app-interact/dbus/guides/inspecting-low-level-communication/README.md b/chapters/app-interact/dbus/guides/inspecting-low-level-communication/README.md new file mode 100644 index 0000000000..5d9191fd80 --- /dev/null +++ b/chapters/app-interact/dbus/guides/inspecting-low-level-communication/README.md @@ -0,0 +1,44 @@ +# Inspecting the Low-level Communication + +Let's run `gdbus` under `strace` to see what's happening behind the scenes. +Run the script in `support/dbus/send_notification_strace.sh`: + +```console +strace: Process 61888 attached +[pid 61887] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 5 +[pid 61887] connect(5, {sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, 110) = 0 +[pid 61887] sendmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0", iov_len=1}], msg_iovlen=1, +msg_control=[{cmsg_len=28, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, cmsg_data={pid=61887, +uid=1000, gid=1000}}], +msg_controllen=32, msg_flags=0}, MSG_NOSIGNAL) = 1 +strace: Process 61889 attached + +[...] + +[pid 61889] sendmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\1\0\1T\0\0\0\3\0\0\0\237\0\0\0\1 +\1o\0\36\0\0\0/org/freedesktop/Notifications\0\0\2\1s\0\35\0\0\0org.freedesktop.Notifications\0\0\0\6\1s\0\35 +\0\0\0org.freedesktop.Notifications\0\0\0\10\1g\0\rsusssasa{sv}i\0\0\0\0\0\0\3\1s\0\6\0\0\0Notify\0\0\0\0\0\0 +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21\0\0\0This is the title\0\0\0\23\0\0\0This is the content\0\0\0\0\0\0\0\0\0 +\0\0\0\0\377\377\377\377", iov_len=260}], msg_iovlen=1, msg_controllen=0, + msg_flags=0}, MSG_NOSIGNAL) = 260 +[pid 61889] recvmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\2\1\1\4\0\0\0\312\0\0\0.\0\0\0", iov_len=16}], +msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 16 +[pid 61889] recvmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\6\1s\0\6\0\0\0:1.497\0\0\10\1g\0\1u\0\0\5\1u\0 +\3\0\0\0\7\1s\0\5\0\0\0:1.49\0\0\0\36\0\0\0", iov_len=52}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 52 +(uint32 30,) +[pid 61889] +++ exited with 0 +++ +[pid 61888] +++ exited with 0 +++ ++++ exited with 0 +++ +``` + +We see a Unix socket being created and a connection made to `/run/user/1000/bus`, as expected. +Then a series of messages are exchanged on the socket, which are part of the D-Bus protocol. +On a closer look, we can even identify some strings from our notification, like `This is the title` or `This is the content`: + +```console +[pid 61889] sendmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\1\0\1T\0\0\0\3\0\0\0\237\0\0\0\1 +\1o\0\36\0\0\0/org/freedesktop/Notifications\0\0\2\1s\0\35\0\0\0org.freedesktop.Notifications\0\0\0\6\1s\0\35 +\0\0\0org.freedesktop.Notifications\0\0\0\10\1g\0\rsusssasa{sv}i\0\0\0\0\0\0\3\1s\0\6\0\0\0Notify\0\0\0\0\0\0 +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21\0\0\0This is the title\0\0\0\23\0\0\0This is the content\0\0\0\0\0\0\0\0\0 +\0\0\0\0\377\377\377\377", iov_len=260}], msg_iovlen=1, msg_controllen=0, +``` diff --git a/content/chapters/app-interact/lab/media/dbus4.png b/chapters/app-interact/dbus/media/dbus4.png similarity index 100% rename from content/chapters/app-interact/lab/media/dbus4.png rename to chapters/app-interact/dbus/media/dbus4.png diff --git a/content/chapters/app-interact/lab/media/dfeet_execute.gif b/chapters/app-interact/dbus/media/dfeet_execute.gif similarity index 100% rename from content/chapters/app-interact/lab/media/dfeet_execute.gif rename to chapters/app-interact/dbus/media/dfeet_execute.gif diff --git a/content/chapters/app-interact/lab/media/dfeet_execute.png b/chapters/app-interact/dbus/media/dfeet_execute.png similarity index 100% rename from content/chapters/app-interact/lab/media/dfeet_execute.png rename to chapters/app-interact/dbus/media/dfeet_execute.png diff --git a/content/chapters/app-interact/lab/media/dfeet_firefox.png b/chapters/app-interact/dbus/media/dfeet_firefox.png similarity index 100% rename from content/chapters/app-interact/lab/media/dfeet_firefox.png rename to chapters/app-interact/dbus/media/dfeet_firefox.png diff --git a/content/chapters/app-interact/lab/media/dfeet_notifications.png b/chapters/app-interact/dbus/media/dfeet_notifications.png similarity index 100% rename from content/chapters/app-interact/lab/media/dfeet_notifications.png rename to chapters/app-interact/dbus/media/dfeet_notifications.png diff --git a/content/chapters/app-interact/lab/media/dfeet_session_bus.png b/chapters/app-interact/dbus/media/dfeet_session_bus.png similarity index 100% rename from content/chapters/app-interact/lab/media/dfeet_session_bus.png rename to chapters/app-interact/dbus/media/dfeet_session_bus.png diff --git a/content/chapters/app-interact/lab/media/dfeet_url_open.gif b/chapters/app-interact/dbus/media/dfeet_url_open.gif similarity index 100% rename from content/chapters/app-interact/lab/media/dfeet_url_open.gif rename to chapters/app-interact/dbus/media/dfeet_url_open.gif diff --git a/content/chapters/app-interact/lab/media/firefox_url_open.gif b/chapters/app-interact/dbus/media/firefox_url_open.gif similarity index 100% rename from content/chapters/app-interact/lab/media/firefox_url_open.gif rename to chapters/app-interact/dbus/media/firefox_url_open.gif diff --git a/content/chapters/app-interact/lab/media/gdbus_notify.gif b/chapters/app-interact/dbus/media/gdbus_notify.gif similarity index 100% rename from content/chapters/app-interact/lab/media/gdbus_notify.gif rename to chapters/app-interact/dbus/media/gdbus_notify.gif diff --git a/chapters/app-interact/dbus/reading/dbus.md b/chapters/app-interact/dbus/reading/dbus.md new file mode 100644 index 0000000000..42fc6a262d --- /dev/null +++ b/chapters/app-interact/dbus/reading/dbus.md @@ -0,0 +1,13 @@ +# D-Bus + +D-Bus is an Inter-Process Communication (IPC) mechanism that is commonly present on Linux. +It is particularly used by various components of the desktop environment (like GNOME) to communicate between one another, although the system itself is general-purpose and can be used in any other situations. + +As the name suggests, the communication model is that of a bus: processes connect to the bus, then exchange messages with other processes through the bus. +The bus itself is implemented by the dbus-daemon, and there are in fact multiple buses: one system bus, accessible system-wide, and one or more session buses, each one corresponding to one user login session. + +Every process that connects to D-Bus receives a unique connection name. +This name can be something human-readable, like `org.freedesktop.Notifications`, or some generated ID, like `:1.63`. +Once a process is connected, it can expose one or multiple `objects`. +An object has a path-like name, consisting of strings separated by a slash character (for example, `/org/freedesktop/Notifications`). +Each object contains one or more `interfaces`, which have the methods that can be called on that object. diff --git a/content/chapters/app-interact/lab/quiz/cgroups-vs-namespaces.md b/chapters/app-interact/os-cloud/drills/questions/cgroups-vs-namespaces.md similarity index 95% rename from content/chapters/app-interact/lab/quiz/cgroups-vs-namespaces.md rename to chapters/app-interact/os-cloud/drills/questions/cgroups-vs-namespaces.md index 948d5a85be..0668d83826 100644 --- a/content/chapters/app-interact/lab/quiz/cgroups-vs-namespaces.md +++ b/chapters/app-interact/os-cloud/drills/questions/cgroups-vs-namespaces.md @@ -1,4 +1,4 @@ -# Cgroups versus namespaces +# Cgroups Versus namespaces ## Question Text diff --git a/content/chapters/app-interact/lab/quiz/container-vs-vm.md b/chapters/app-interact/os-cloud/drills/questions/container-vs-vm.md similarity index 95% rename from content/chapters/app-interact/lab/quiz/container-vs-vm.md rename to chapters/app-interact/os-cloud/drills/questions/container-vs-vm.md index 35b43ca877..4725e418c0 100644 --- a/content/chapters/app-interact/lab/quiz/container-vs-vm.md +++ b/chapters/app-interact/os-cloud/drills/questions/container-vs-vm.md @@ -1,4 +1,4 @@ -# Container versus VM +# Container Versus VM ## Question Text diff --git a/content/chapters/app-interact/lab/quiz/vm-creation.md b/chapters/app-interact/os-cloud/drills/questions/vm-creation.md similarity index 100% rename from content/chapters/app-interact/lab/quiz/vm-creation.md rename to chapters/app-interact/os-cloud/drills/questions/vm-creation.md diff --git a/content/chapters/app-interact/lab/solution/os-cloud/db.sqldump b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/db.sqldump similarity index 97% rename from content/chapters/app-interact/lab/solution/os-cloud/db.sqldump rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/db.sqldump index 3d461babd6..3a574edad0 100644 --- a/content/chapters/app-interact/lab/solution/os-cloud/db.sqldump +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/db.sqldump @@ -1,113 +1,113 @@ --- MariaDB dump 10.19 Distrib 10.7.6-MariaDB, for debian-linux-gnu (x86_64) --- --- Host: localhost Database: os-cloud --- ------------------------------------------------------ --- Server version 10.7.6-MariaDB-1:10.7.6+maria~ubu2004 - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `disk` --- - -DROP TABLE IF EXISTS `disk`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `disk` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `size` bigint(20) DEFAULT NULL, - `template_name` varchar(255) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `disk` --- - -LOCK TABLES `disk` WRITE; -/*!40000 ALTER TABLE `disk` DISABLE KEYS */; -/*!40000 ALTER TABLE `disk` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `network` --- - -DROP TABLE IF EXISTS `network`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `network` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `bridge_interface_idx` int(11) NOT NULL, - `ip` int(10) unsigned NOT NULL, - `mask` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `network` --- - -LOCK TABLES `network` WRITE; -/*!40000 ALTER TABLE `network` DISABLE KEYS */; -/*!40000 ALTER TABLE `network` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `vm` --- - -DROP TABLE IF EXISTS `vm`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `vm` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `disk_id` int(10) unsigned NOT NULL, - `mem_size` int(10) unsigned NOT NULL, - `network_id` int(11) unsigned NOT NULL, - `tap_interface_idx` int(10) unsigned NOT NULL, - `ip` int(10) unsigned NOT NULL, - `qemu_pid` int(10) DEFAULT NULL, - `qemu_monitor_port` int(10) unsigned NOT NULL, - `qemu_serial_port` int(10) unsigned NOT NULL, - `state` int(10) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `network_id` (`network_id`), - KEY `disk_id` (`disk_id`), - CONSTRAINT `vm_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES `network` (`id`), - CONSTRAINT `vm_ibfk_2` FOREIGN KEY (`disk_id`) REFERENCES `disk` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `vm` --- - -LOCK TABLES `vm` WRITE; -/*!40000 ALTER TABLE `vm` DISABLE KEYS */; -/*!40000 ALTER TABLE `vm` ENABLE KEYS */; -UNLOCK TABLES; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2022-11-13 17:55:56 +-- MariaDB dump 10.19 Distrib 10.7.6-MariaDB, for debian-linux-gnu (x86_64) +-- +-- Host: localhost Database: os-cloud +-- ------------------------------------------------------ +-- Server version 10.7.6-MariaDB-1:10.7.6+maria~ubu2004 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `disk` +-- + +DROP TABLE IF EXISTS `disk`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `disk` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `size` bigint(20) DEFAULT NULL, + `template_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `disk` +-- + +LOCK TABLES `disk` WRITE; +/*!40000 ALTER TABLE `disk` DISABLE KEYS */; +/*!40000 ALTER TABLE `disk` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `network` +-- + +DROP TABLE IF EXISTS `network`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `network` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `bridge_interface_idx` int(11) NOT NULL, + `ip` int(10) unsigned NOT NULL, + `mask` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `network` +-- + +LOCK TABLES `network` WRITE; +/*!40000 ALTER TABLE `network` DISABLE KEYS */; +/*!40000 ALTER TABLE `network` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `vm` +-- + +DROP TABLE IF EXISTS `vm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `vm` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `disk_id` int(10) unsigned NOT NULL, + `mem_size` int(10) unsigned NOT NULL, + `network_id` int(11) unsigned NOT NULL, + `tap_interface_idx` int(10) unsigned NOT NULL, + `ip` int(10) unsigned NOT NULL, + `qemu_pid` int(10) DEFAULT NULL, + `qemu_monitor_port` int(10) unsigned NOT NULL, + `qemu_serial_port` int(10) unsigned NOT NULL, + `state` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `network_id` (`network_id`), + KEY `disk_id` (`disk_id`), + CONSTRAINT `vm_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES `network` (`id`), + CONSTRAINT `vm_ibfk_2` FOREIGN KEY (`disk_id`) REFERENCES `disk` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `vm` +-- + +LOCK TABLES `vm` WRITE; +/*!40000 ALTER TABLE `vm` DISABLE KEYS */; +/*!40000 ALTER TABLE `vm` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2022-11-13 17:55:56 diff --git a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/copy_files.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/copy_files.sh similarity index 95% rename from content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/copy_files.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/copy_files.sh index 73aa803eea..2841ad73ab 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/copy_files.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/copy_files.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e diff --git a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/create_disk_from_template.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/create_disk_from_template.sh similarity index 91% rename from content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/create_disk_from_template.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/create_disk_from_template.sh index 7d3a4590f2..e30408437c 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/create_disk_from_template.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/create_disk_from_template.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e diff --git a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome similarity index 50% rename from content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome index cce9590301..84815674b5 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause #!/bin/bash echo "Powered by OS Cloud" diff --git a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/setup_root_password.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/setup_root_password.sh similarity index 95% rename from content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/setup_root_password.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/setup_root_password.sh index f8e063e667..48fbf764e1 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/setup_root_password.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/setup_root_password.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e diff --git a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/utils.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/utils.sh similarity index 92% rename from content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/utils.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/utils.sh index e135d2e325..ef9ab08eba 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/utils.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/disk-templates/ubuntu_22.04/utils.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause nbd_connect_qcow2() { diff --git a/content/chapters/app-interact/lab/solution/os-cloud/docker-compose.yml b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/docker-compose.yml similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/docker-compose.yml rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/docker-compose.yml diff --git a/content/chapters/app-interact/lab/support/os-cloud/initial_setup.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/initial_setup.sh similarity index 93% rename from content/chapters/app-interact/lab/support/os-cloud/initial_setup.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/initial_setup.sh index e08ae72663..8f801eef20 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/initial_setup.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/initial_setup.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e @@ -19,4 +20,3 @@ done # Pull docker images docker pull mariadb:10.7 - diff --git a/content/chapters/app-interact/lab/solution/os-cloud/keys/ssh_key b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/keys/ssh_key similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/keys/ssh_key rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/keys/ssh_key diff --git a/content/chapters/app-interact/lab/solution/os-cloud/keys/ssh_key.pub b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/keys/ssh_key.pub similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/keys/ssh_key.pub rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/keys/ssh_key.pub diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/Dockerfile b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/Dockerfile similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/Dockerfile rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/Dockerfile diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/app.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/app.py similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/app.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/app.py diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/db.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/db.py similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/db.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/db.py diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/disk.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/disk.py similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/disk.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/disk.py diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/errors.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/errors.py similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/errors.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/errors.py diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/network.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/network.py similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/network.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/network.py diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/scripts/create_bridge.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/scripts/create_bridge.sh similarity index 84% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/scripts/create_bridge.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/scripts/create_bridge.sh index b83c4d9a09..a203dea6f9 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/scripts/create_bridge.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/scripts/create_bridge.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -e diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/scripts/create_tap_interface.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/scripts/create_tap_interface.sh similarity index 87% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/scripts/create_tap_interface.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/scripts/create_tap_interface.sh index b689127a95..319d9ce712 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/scripts/create_tap_interface.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/scripts/create_tap_interface.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -e diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/utils.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/utils.py similarity index 100% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/utils.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/utils.py diff --git a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/vm.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/vm.py similarity index 99% rename from content/chapters/app-interact/lab/solution/os-cloud/os-cloud/vm.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/vm.py index d67ef11014..17fd336933 100644 --- a/content/chapters/app-interact/lab/solution/os-cloud/os-cloud/vm.py +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/os-cloud/vm.py @@ -213,7 +213,6 @@ def vm_create( disk_size: int, ssh_pub_key: str, ): - if len(db.get_vm_by_name(name)) > 0: raise errors.VMAlreadyExistsException(name) diff --git a/content/chapters/app-interact/lab/support/os-cloud/setup_db.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/setup_db.sh similarity index 82% rename from content/chapters/app-interact/lab/support/os-cloud/setup_db.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/setup_db.sh index d69a4be213..83be7dfb81 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/setup_db.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/solution/setup_db.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause MYSQL_ROOT_PASSWORD=eiv2Siezofe7quahcido #gitleaks:allow MYSQL_OS_CLOUD_PASSWORD=iK3ahthae3ieZ6gohkay #gitleaks:allow @@ -56,7 +57,12 @@ echo 'Creating tables' docker exec -i mysql-tmp mysql -u os-cloud -p$MYSQL_OS_CLOUD_PASSWORD os-cloud < db.sqldump -docker exec -i mysql-tmp mysql -u os-cloud -p$MYSQL_OS_CLOUD_PASSWORD os-cloud -e "INSERT INTO network(name, bridge_interface_idx, ip, mask) values('default', 0, 3232235520, 4294901760)" +docker exec -i mysql-tmp \ + mysql -u os-cloud \ + -p$MYSQL_OS_CLOUD_PASSWORD \ + os-cloud \ + -e "INSERT INTO network(name, bridge_interface_idx, ip, mask) \ + values('default', 0, 3232235520, 4294901760)" echo 'Stopping db server' diff --git a/content/chapters/app-interact/lab/support/os-cloud/db.sqldump b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/db.sqldump similarity index 97% rename from content/chapters/app-interact/lab/support/os-cloud/db.sqldump rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/db.sqldump index 3d461babd6..3a574edad0 100644 --- a/content/chapters/app-interact/lab/support/os-cloud/db.sqldump +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/db.sqldump @@ -1,113 +1,113 @@ --- MariaDB dump 10.19 Distrib 10.7.6-MariaDB, for debian-linux-gnu (x86_64) --- --- Host: localhost Database: os-cloud --- ------------------------------------------------------ --- Server version 10.7.6-MariaDB-1:10.7.6+maria~ubu2004 - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `disk` --- - -DROP TABLE IF EXISTS `disk`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `disk` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `size` bigint(20) DEFAULT NULL, - `template_name` varchar(255) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `disk` --- - -LOCK TABLES `disk` WRITE; -/*!40000 ALTER TABLE `disk` DISABLE KEYS */; -/*!40000 ALTER TABLE `disk` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `network` --- - -DROP TABLE IF EXISTS `network`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `network` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `bridge_interface_idx` int(11) NOT NULL, - `ip` int(10) unsigned NOT NULL, - `mask` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `network` --- - -LOCK TABLES `network` WRITE; -/*!40000 ALTER TABLE `network` DISABLE KEYS */; -/*!40000 ALTER TABLE `network` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `vm` --- - -DROP TABLE IF EXISTS `vm`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `vm` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `disk_id` int(10) unsigned NOT NULL, - `mem_size` int(10) unsigned NOT NULL, - `network_id` int(11) unsigned NOT NULL, - `tap_interface_idx` int(10) unsigned NOT NULL, - `ip` int(10) unsigned NOT NULL, - `qemu_pid` int(10) DEFAULT NULL, - `qemu_monitor_port` int(10) unsigned NOT NULL, - `qemu_serial_port` int(10) unsigned NOT NULL, - `state` int(10) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `network_id` (`network_id`), - KEY `disk_id` (`disk_id`), - CONSTRAINT `vm_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES `network` (`id`), - CONSTRAINT `vm_ibfk_2` FOREIGN KEY (`disk_id`) REFERENCES `disk` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `vm` --- - -LOCK TABLES `vm` WRITE; -/*!40000 ALTER TABLE `vm` DISABLE KEYS */; -/*!40000 ALTER TABLE `vm` ENABLE KEYS */; -UNLOCK TABLES; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2022-11-13 17:55:56 +-- MariaDB dump 10.19 Distrib 10.7.6-MariaDB, for debian-linux-gnu (x86_64) +-- +-- Host: localhost Database: os-cloud +-- ------------------------------------------------------ +-- Server version 10.7.6-MariaDB-1:10.7.6+maria~ubu2004 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `disk` +-- + +DROP TABLE IF EXISTS `disk`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `disk` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `size` bigint(20) DEFAULT NULL, + `template_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `disk` +-- + +LOCK TABLES `disk` WRITE; +/*!40000 ALTER TABLE `disk` DISABLE KEYS */; +/*!40000 ALTER TABLE `disk` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `network` +-- + +DROP TABLE IF EXISTS `network`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `network` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `bridge_interface_idx` int(11) NOT NULL, + `ip` int(10) unsigned NOT NULL, + `mask` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `network` +-- + +LOCK TABLES `network` WRITE; +/*!40000 ALTER TABLE `network` DISABLE KEYS */; +/*!40000 ALTER TABLE `network` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `vm` +-- + +DROP TABLE IF EXISTS `vm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `vm` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `disk_id` int(10) unsigned NOT NULL, + `mem_size` int(10) unsigned NOT NULL, + `network_id` int(11) unsigned NOT NULL, + `tap_interface_idx` int(10) unsigned NOT NULL, + `ip` int(10) unsigned NOT NULL, + `qemu_pid` int(10) DEFAULT NULL, + `qemu_monitor_port` int(10) unsigned NOT NULL, + `qemu_serial_port` int(10) unsigned NOT NULL, + `state` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `network_id` (`network_id`), + KEY `disk_id` (`disk_id`), + CONSTRAINT `vm_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES `network` (`id`), + CONSTRAINT `vm_ibfk_2` FOREIGN KEY (`disk_id`) REFERENCES `disk` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `vm` +-- + +LOCK TABLES `vm` WRITE; +/*!40000 ALTER TABLE `vm` DISABLE KEYS */; +/*!40000 ALTER TABLE `vm` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2022-11-13 17:55:56 diff --git a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/copy_files.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/copy_files.sh similarity index 95% rename from content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/copy_files.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/copy_files.sh index 73aa803eea..2841ad73ab 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/copy_files.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/copy_files.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e diff --git a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/create_disk_from_template.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/create_disk_from_template.sh similarity index 91% rename from content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/create_disk_from_template.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/create_disk_from_template.sh index 7d3a4590f2..e30408437c 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/create_disk_from_template.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/create_disk_from_template.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e diff --git a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome similarity index 50% rename from content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome index cce9590301..84815674b5 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/files/99-os-cloud-welcome @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause #!/bin/bash echo "Powered by OS Cloud" diff --git a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/setup_root_password.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/setup_root_password.sh similarity index 95% rename from content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/setup_root_password.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/setup_root_password.sh index f8e063e667..48fbf764e1 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/disk-templates/ubuntu_22.04/setup_root_password.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/setup_root_password.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e diff --git a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/utils.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/utils.sh similarity index 92% rename from content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/utils.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/utils.sh index e135d2e325..ef9ab08eba 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/disk-templates/ubuntu_22.04/utils.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/disk-templates/ubuntu_22.04/utils.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause nbd_connect_qcow2() { diff --git a/content/chapters/app-interact/lab/support/os-cloud/docker-compose.yml b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/docker-compose.yml similarity index 100% rename from content/chapters/app-interact/lab/support/os-cloud/docker-compose.yml rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/docker-compose.yml diff --git a/content/chapters/app-interact/lab/solution/os-cloud/initial_setup.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/initial_setup.sh similarity index 93% rename from content/chapters/app-interact/lab/solution/os-cloud/initial_setup.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/initial_setup.sh index e08ae72663..6877cdffb8 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/initial_setup.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/initial_setup.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -o posix set -e diff --git a/content/chapters/app-interact/lab/support/os-cloud/keys/ssh_key b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/keys/ssh_key similarity index 100% rename from content/chapters/app-interact/lab/support/os-cloud/keys/ssh_key rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/keys/ssh_key diff --git a/content/chapters/app-interact/lab/support/os-cloud/keys/ssh_key.pub b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/keys/ssh_key.pub similarity index 100% rename from content/chapters/app-interact/lab/support/os-cloud/keys/ssh_key.pub rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/keys/ssh_key.pub diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/Dockerfile b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/Dockerfile similarity index 100% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/Dockerfile rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/Dockerfile diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/app.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/app.py similarity index 99% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/app.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/app.py index 14680dcd64..b56074855d 100644 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/app.py +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/app.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause import logging import os diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/db.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/db.py similarity index 99% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/db.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/db.py index dc3700b577..754d309c7c 100644 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/db.py +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/db.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause import logging import os import time diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/disk.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/disk.py similarity index 97% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/disk.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/disk.py index 8cdcfc0174..5083e65a8e 100644 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/disk.py +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/disk.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause import logging import os import subprocess diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/errors.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/errors.py similarity index 93% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/errors.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/errors.py index ca275b7ddf..af48b9690b 100644 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/errors.py +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/errors.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause class VMNotFoundException(Exception): pass diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/network.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/network.py similarity index 98% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/network.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/network.py index a165f876f7..dbdfe07db0 100644 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/network.py +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/network.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause import ipaddress import logging import socket diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/scripts/create_bridge.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/scripts/create_bridge.sh similarity index 84% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/scripts/create_bridge.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/scripts/create_bridge.sh index b83c4d9a09..a203dea6f9 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/scripts/create_bridge.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/scripts/create_bridge.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -e diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/scripts/create_tap_interface.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/scripts/create_tap_interface.sh similarity index 87% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/scripts/create_tap_interface.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/scripts/create_tap_interface.sh index b689127a95..319d9ce712 100755 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/scripts/create_tap_interface.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/scripts/create_tap_interface.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause set -e diff --git a/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/utils.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/utils.py new file mode 100644 index 0000000000..dbed5d40eb --- /dev/null +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/utils.py @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: BSD-3-Clause +DISK_TMP_PASSWORD = "123456" diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/vm.py b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/vm.py similarity index 99% rename from content/chapters/app-interact/lab/support/os-cloud/os-cloud/vm.py rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/vm.py index afea56a8f4..9be9aa5ee7 100644 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/vm.py +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/os-cloud/vm.py @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause import ipaddress import logging import os @@ -209,7 +210,6 @@ def vm_create( disk_size: int, ssh_pub_key: str, ): - if len(db.get_vm_by_name(name)) > 0: raise errors.VMAlreadyExistsException(name) diff --git a/content/chapters/app-interact/lab/solution/os-cloud/setup_db.sh b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/setup_db.sh similarity index 82% rename from content/chapters/app-interact/lab/solution/os-cloud/setup_db.sh rename to chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/setup_db.sh index d69a4be213..83be7dfb81 100755 --- a/content/chapters/app-interact/lab/solution/os-cloud/setup_db.sh +++ b/chapters/app-interact/os-cloud/drills/tasks/os-cloud/support/setup_db.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause MYSQL_ROOT_PASSWORD=eiv2Siezofe7quahcido #gitleaks:allow MYSQL_OS_CLOUD_PASSWORD=iK3ahthae3ieZ6gohkay #gitleaks:allow @@ -56,7 +57,12 @@ echo 'Creating tables' docker exec -i mysql-tmp mysql -u os-cloud -p$MYSQL_OS_CLOUD_PASSWORD os-cloud < db.sqldump -docker exec -i mysql-tmp mysql -u os-cloud -p$MYSQL_OS_CLOUD_PASSWORD os-cloud -e "INSERT INTO network(name, bridge_interface_idx, ip, mask) values('default', 0, 3232235520, 4294901760)" +docker exec -i mysql-tmp \ + mysql -u os-cloud \ + -p$MYSQL_OS_CLOUD_PASSWORD \ + os-cloud \ + -e "INSERT INTO network(name, bridge_interface_idx, ip, mask) \ + values('default', 0, 3232235520, 4294901760)" echo 'Stopping db server' diff --git a/chapters/app-interact/os-cloud/guides/containers-vs-vms/README.md b/chapters/app-interact/os-cloud/guides/containers-vs-vms/README.md new file mode 100644 index 0000000000..8d038403ed --- /dev/null +++ b/chapters/app-interact/os-cloud/guides/containers-vs-vms/README.md @@ -0,0 +1,44 @@ +# Containers vs VMs + +Containers are a lightweight virtualization technology that allows multiple isolated user-space instances to run on a single host operating system. +They are often compared to [`chroot`](https://linux.die.net/man/1/chroot) because they both provide isolated environments for running applications. + +Cgroups limit, account for, and isolate the resource usage (CPU, memory, disk I/O, network, etc.) of a collection of processes. +They can be used to enforce resource limits, prioritization, accounting, and control. +Namespaces isolate processes from each other by creating independent views of system resources. +There are different types of namespaces, such as user, PID, network, mount, IPC, and UTS. +You can read more about them [here](https://www.nginx.com/blog/what-are-namespaces-cgroups-how-do-they-work/), [here](https://www.baeldung.com/linux/cgroups-and-namespaces) and a particularly good read about namespaces can be found [here](https://blog.quarkslab.com/digging-into-linux-namespaces-part-1.html) + +[Quiz](../drills/questions/questions/cgroups-vs-namespaces.md) + +However, containers take this isolation a step further by using kernel features such as namespaces and cgroups to provide a more complete and secure isolation of resources. + +Virtual machines, on the other hand, are a heavier form of virtualization that involves running a complete guest operating system on top of a host operating system using a hypervisor. +This allows multiple guest operating systems to run on a single physical machine, each with its own set of virtualized hardware resources. + +![VMs vs Containers](../media/containers-vs-vms.svg) + +One key difference between containers and VMs is the level of abstraction. +Containers virtualize the operating system, allowing multiple containers to share the same kernel while providing the illusion of running on separate machines. +VMs virtualize the hardware, allowing multiple guest operating systems to run on the same physical machine while providing the illusion of running on separate physical hardware. + +Another difference is the resource overhead. +Containers are generally more lightweight than VMs because they share the host kernel and do not require a separate guest operating system to be installed. +This means that containers can start up faster and use less memory than VMs. + +[Quiz](../drills/questions/container-vs-vm.md) + +## Containers + +Our app will make use of `docker` containers. +A container is an OS-level virtualization method in which a group of userspace processes are isolated from the rest of the system. + +Take for example a database server. +Instead of running it directly on the host system, we'll run it in its own container. +This way, the server process will be isolated from other processes on the system. +It will also have its own filesystem. + +Besides isolation, containers are also useful for portability. +Since a container comes with its own filesystem image, we can pack it together will all the dependencies, so that the app will run correctly no matter what packages are installed on the host system. + +Finally, since our application will consist of more than 1 container, we'll also use `docker-compose`, which is a tool that helps us with running multi-container applications. diff --git a/content/chapters/app-interact/lab/media/containers-vs-vms.svg b/chapters/app-interact/os-cloud/media/containers-vs-vms.svg similarity index 100% rename from content/chapters/app-interact/lab/media/containers-vs-vms.svg rename to chapters/app-interact/os-cloud/media/containers-vs-vms.svg diff --git a/content/chapters/app-interact/lab/media/nested_virt_vbox.png b/chapters/app-interact/os-cloud/media/nested_virt_vbox.png similarity index 100% rename from content/chapters/app-interact/lab/media/nested_virt_vbox.png rename to chapters/app-interact/os-cloud/media/nested_virt_vbox.png diff --git a/content/chapters/app-interact/lab/media/nested_virt_vmware.png b/chapters/app-interact/os-cloud/media/nested_virt_vmware.png similarity index 100% rename from content/chapters/app-interact/lab/media/nested_virt_vmware.png rename to chapters/app-interact/os-cloud/media/nested_virt_vmware.png diff --git a/content/chapters/app-interact/lab/media/os_cloud.svg b/chapters/app-interact/os-cloud/media/os_cloud.svg similarity index 100% rename from content/chapters/app-interact/lab/media/os_cloud.svg rename to chapters/app-interact/os-cloud/media/os_cloud.svg diff --git a/content/chapters/app-interact/lab/media/os_cloud_networking.svg b/chapters/app-interact/os-cloud/media/os_cloud_networking.svg similarity index 100% rename from content/chapters/app-interact/lab/media/os_cloud_networking.svg rename to chapters/app-interact/os-cloud/media/os_cloud_networking.svg diff --git a/content/chapters/app-interact/lab/content/os-cloud.md b/chapters/app-interact/os-cloud/reading/os-cloud.md similarity index 58% rename from content/chapters/app-interact/lab/content/os-cloud.md rename to chapters/app-interact/os-cloud/reading/os-cloud.md index e58a9584b6..1cd95f2d8c 100644 --- a/content/chapters/app-interact/lab/content/os-cloud.md +++ b/chapters/app-interact/os-cloud/reading/os-cloud.md @@ -3,51 +3,6 @@ In this section, we are going to build a "toy cloud" called `OS Cloud`. Similar to a real cloud (like `aws`), `OS Cloud` will allow us to create and manage virtual machines, through an `http` API. -## Containers vs VMs - -Containers are a lightweight virtualization technology that allows multiple isolated user-space instances to run on a single host operating system. -They are often compared to [`chroot`](https://linux.die.net/man/1/chroot) because they both provide isolated environments for running applications. - -Cgroups limit, account for, and isolate the resource usage (CPU, memory, disk I/O, network, etc.) of a collection of processes. -They can be used to enforce resource limits, prioritization, accounting, and control. -Namespaces isolate processes from each other by creating independent views of system resources. -There are different types of namespaces, such as user, PID, network, mount, IPC, and UTS. -You can read more about them [here](https://www.nginx.com/blog/what-are-namespaces-cgroups-how-do-they-work/), [here](https://www.baeldung.com/linux/cgroups-and-namespaces) and a particularly good read about namespaces can be found [here](https://blog.quarkslab.com/digging-into-linux-namespaces-part-1.html) - -[Quiz](../quiz/cgroups-vs-namespaces.md) - -However, containers take this isolation a step further by using kernel features such as namespaces and cgroups to provide a more complete and secure isolation of resources. - -Virtual machines, on the other hand, are a heavier form of virtualization that involves running a complete guest operating system on top of a host operating system using a hypervisor. -This allows multiple guest operating systems to run on a single physical machine, each with its own set of virtualized hardware resources. - -![VMs vs Containers](../media/containers-vs-vms.svg) - -One key difference between containers and VMs is the level of abstraction. -Containers virtualize the operating system, allowing multiple containers to share the same kernel while providing the illusion of running on separate machines. -VMs virtualize the hardware, allowing multiple guest operating systems to run on the same physical machine while providing the illusion of running on separate physical hardware. - -Another difference is the resource overhead. -Containers are generally more lightweight than VMs because they share the host kernel and do not require a separate guest operating system to be installed. -This means that containers can start up faster and use less memory than VMs. - -[Quiz](../quiz/container-vs-vm.md) - -## Containers - -Our app will make use of `docker` containers. -A container is an OS-level virtualization method in which a group of userspace processes are isolated from the rest of the system. - -Take for example a database server. -Instead of running it directly on the host system, we'll run it in its own container. -This way, the server process will be isolated from other processes on the system. -It will also have its own filesystem. - -Besides isolation, containers are also useful for portability. -Since a container comes with its own filesystem image, we can pack it together will all the dependencies, so that the app will run correctly no matter what packages are installed on the host system. - -Finally, since our application will consist of more than 1 container, we'll also use `docker-compose`, which is a tool that helps us with running multi-container applications. - ## Prerequisites Make sure the following packages are installed: @@ -63,7 +18,7 @@ If not, maybe you need to add it to the `docker` group: sudo usermod -aG docker student ``` -Then, after relogin: +Then, after re-login: ```console student@os:~$ docker ps @@ -132,12 +87,12 @@ Let's create one (the command will take about 1 minute to complete): ```console student@os:~/.../support/os-cloud$ curl -H "Content-Type: application/json" \ - -d '{ "name": "my_vm", "image": "ubuntu_22.04", "network": "default", "mem_size": "2G", "disk_size": "10G"}' \ - localhost:5000/vm_create + -d '{ "name": "my_vm", "image": "ubuntu_22.04", "network": "default", "mem_size": "2G", "disk_size": "10G"}' \ + localhost:5000/vm_create {"id":1,"status":"ok"} ``` -[Quiz](../quiz/vm-creation.md) +[Quiz](../drills/questions/vm-creation.md) Check the virtual machine list again: @@ -178,6 +133,330 @@ student@os:~/.../support/os-cloud$ curl -s -H "Content-Type: application/json" - We recognize some parameters that we specified at creation time, like `mem_size` and `disk_size`. Also, the IP address `192.168.0.2` has been allocated for our machine. +## Virtual Machine Creation + +Take a look at the `vm_create` function in `support/os-cloud/os-cloud/vm.py`. +The steps undertaken are roughly: + +1. some initial allocations: the virtual machine IP address, network interface, qemu ports, etc + +1. the virtual machine disk is created, based on the template specified by the user (like `ubuntu_22.04`) + +1. the virtual machine is started with this new disk, in order to do some more customizations (the `ubuntu_22_04_vm_prepare` function) + +1. the virtual machine is restarted again with the final disk in place + +## Disk Creation + +All the disk templates are in `chapters/app-interact/os-cloud/support/disk-templates`. +This directory will be mounted in `/disk-templates` inside the container. + +The first step of disk creation is to create a `qcow2` disk file based on the template specified by the user (step 2 from the explanation above). + +This is done in the `create_disk_from_template` function in `chapters/app-interact/os-cloud/support/os-cloud/disk.py`. +The function will first create a disk object in the database, then it will call 2 shell scripts: `create_disk_from_template.sh` and `setup_root_password.sh`. + +The second step is to start the virtual machine with this disk and do some customizations (step 3 from above). + +This is done in the `ubuntu_22_04_vm_prepare` function in `chapters/app-interact/os-cloud/support/os-cloud/vm.py`. +The code will connect to the vm's qemu serial console using `pexpect`. +Then it will use a series of `expect_exact` + `sendline` pairs to interact with the virtual machine, as if those commands were typed in the command-line. + +## OS-Cloud: More Disk Customization + +You might have probably noticed that there are 2 types of disk customizations: + +- One type is for things that can be done without running the virtual machine. +If we only want to modify some files inside the disk filesystem, we can do so by mounting the disk. +This is done, for example, in the `disk-templates/ubuntu_22.04/setup_root_password.sh` script. +There we use `nbd_connect_qcow2` + `mount` to mount the disk, then we modify the `/etc/shadow` file to change the root password. + +- The second case is for operations that must be done with the virtual machine running. +These are handled in the `ubuntu_22_04_vm_prepare` function: the virtual machine is first started (`start_qemu_for_vm`), then `pexpect` is used to interact with the virtual machine via the `qemu` serial console. +Here we do things like running `ssh-keygen` - a binary that is part of the disk filesystem, which depends on other parts of the operating system from the disk to be running. +Note that in `ubuntu_22_04_vm_prepare`, for convenience, we also do some customizations that fall into the first category (like modifying `/etc/ssh/sshd_config`). + +### Copy Additional Files to the Newly Created Disk + +This is a customization from the first category. +In `disk-templates/ubuntu_22.04/files` there is a file called `99-os-cloud-welcome` (a script that prints a greeting message). +We want to copy this file to `/etc/update-motd.d` in our newly created disk, so that it will run whenever a user logs in. + +To do this, you will create a script called `copy_files.sh` in `disk-templates/ubuntu_22.04`. +This script will receive a path to a `qcow2` disk file as an argument, it will mount the disk, and then copy the file to the necessary location. +Then, in the `create_disk_from_template` function in `disk.py` you will call this script, similar with how the other scripts are called. + +You can use `disk-templates/ubuntu_22.04/setup_root_password.sh` as an example. + +### SSH Key Setup + +We want to be able to log into the virtual machine using an ssh key, instead of the password `123456`. +Notice that the `vm_create` API also accepts an `ssh_key` parameter. +Here, the user can provide an ssh public key, which the system will install in `/root/.ssh/authorized_keys` in the newly created virtual machine. + +Your task is to implement this feature, as a customization from the second category (that is, implemented in the `ubuntu_22_04_vm_prepare` function). +The key will be accessible to the function as the `ssh_pub_key` parameter. +Then it's only a matter of writing the key to the appropriate place, using a command like `echo key > /root/.ssh/authorized_keys`. +Note that the `/root/.ssh` directory might not exist, so you need to create it as well. + +After the feature is complete, you can test it using the keys in the `support/os-cloud/keys` directory. +This directory contains a pair of public-private keys. +The directory will also be mounted inside the `os-cloud` container in `/keys`. + +You will create another virtual machine, passing the public key to `vm_create`: + +```console +student@os:~/.../support/os-cloud$ curl -H "Content-Type: application/json" \ + -d '{ "name": "my_vm2", "image": "ubuntu_22.04", "network": "default", "mem_size": "2G", "disk_size": "10G", "ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8CDHgeE4NIIIih3wSz58GDkfPLUk2m9gmbZB1f6o8Lzawzb3HVFpslAUWK0f/Ymw9cloInpMo50gWMYFSyJ7ZrOWWak54BedpHDkFAxxy+JCE9b+pkKsrAT7wiir7gn2LHlhj55FLZkC9PpM9cBcrMfzlcP9Bf+2cnpDdINybSLmOUmrI23ANteM4lEVaa2yEbCaJk6dFB8+atz5zPjvVI0Hd+kJK7yJ0xV6Zc2ADle7TKW3dyiXOE9qFKe9933Rj7ocqNXCAO1cxUoJCVuVS7lh+1pSSPXLWLTOhVp/XiLGWVP6KRYmmn710MWKm9Kj1tPiGUphUraL20SJiRT6/ os-cloud-user"}' \ + localhost:5000/vm_create +{"id":2,"status":"ok"} +``` + +Obtain the IP address that was allocated to the new vm: + +```console +student@os:~/.../support/os-cloud$ curl -s -H "Content-Type: application/json" -d '{ "id": 2 }' localhost:5000/vm_info | jq . +{ + "disk_size": 10737418240, + "id": 2, + "ip": "192.168.0.3", + "mem_size": 2147483648, + "name": "my_vm2", + "network": "default", + "os": "ubuntu_22.04", + "state": "RUNNING" +} +``` + +Then go inside the `os-cloud` container and ssh to the vm using the private key in `/keys`. +It should work without prompting for the password: + +```console +student@os:~/.../support/os-cloud$ docker-compose exec os-cloud bash +root@ac93d3d6cab2:/app# ssh -i /keys/ssh_key root@192.168.0.3 +Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-56-generic x86_64) +[...] +Powered by OS Cloud +Last login: Mon Jan 2 19:34:53 2023 from 192.168.0.1 +root@ubuntu:~# +``` + +## OS-Cloud: Internet Access + +Notice that our virtual machines don't have Internet access: + +```console +Powered by OS Cloud +Last login: Mon Jan 2 19:52:47 UTC 2023 on ttyS0 +root@ubuntu:~# curl google.com +curl: (6) Could not resolve host: google.com +``` + +In this task, we want to fix this problem. +To do this, we must first understand how the networking for the virtual machines is done. + +First, there is the concept of a `network`, which you saw in the previous section. +There is a network called `default`, with the address of `192.168.0.0/24`. +All virtual machines are part of this network, that's why they were allocated ip addresses like `192.168.0.2`. + +Let's go inside the `os-cloud` container and take a look at the network interfaces: + +```console +$ docker-compose exec os-cloud bash +root@8333e5cefb0d:/app# ip a +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever +2: br0: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 8a:68:b7:5b:6b:45 brd ff:ff:ff:ff:ff:ff + inet 192.168.0.1/16 scope global br0 + valid_lft forever preferred_lft forever +3: tap0: mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000 + link/ether 8a:68:b7:5b:6b:45 brd ff:ff:ff:ff:ff:ff +4: tap1: mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000 + link/ether fa:f8:7f:83:50:8f brd ff:ff:ff:ff:ff:ff +77: eth0@if78: mtu 1500 qdisc noqueue state UP group default + link/ether 02:42:ac:16:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet 172.22.0.3/16 brd 172.22.255.255 scope global eth0 + valid_lft forever preferred_lft forever + +root@8333e5cefb0d:/app# ps -ef | grep qemu +root 19 8 29 09:15 ? 00:01:26 qemu-system-x86_64 -m 2048 -hda /vm-disks/1/disk.qcow2 -net nic,macaddr=52:54:00:12:34:00 -net tap,ifname=tap0,script=no -monitor telnet::10001,server,nowait -serial telnet::10002,server,nowait -nographic -enable-kvm +root 29 8 28 09:15 ? 00:01:24 qemu-system-x86_64 -m 2048 -hda /vm-disks/2/disk.qcow2 -net nic,macaddr=52:54:00:12:34:01 -net tap,ifname=tap1,script=no -monitor telnet::10003,server,nowait -serial telnet::10004,server,nowait -nographic -enable-kvm +``` + +Here we have 2 virtual machines running. +Each virtual machine uses a `tap` interface (the `-net tap,ifname=tap0,script=no` parameter for `qemu`). +This means that the `ens0` interface inside the virtual machine corresponds to the `tap0` interface outside the virtual machine. +All the tap interfaces are bridged together into the `br0` bridge, which has the ip address `192.168.0.1`. +Also, each virtual machine has the default gateway configured to be `192.168.0.1`. + +In summary, it looks something like this: + +![os-cloud](../media/os_cloud_networking.svg) + +All the traffic coming from the virtual machines passes through the `br0` interface. +So, in order to make the Internet work, all we have to do is a simple `NAT`, with a command like: + +```console +root@8333e5cefb0d:/app# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j MASQUERADE +``` + +Now, the virtual machines should have Internet access: + +```console +root@8333e5cefb0d:/app# ssh root@192.168.0.2 +[...] +root@ubuntu:~# curl google.com + +301 Moved +

301 Moved

+The document has moved +here. + +``` + +Now your task is to run the `iptables` command above automatically when the system starts, so that it's not necessary to run it manually like we did in the above example. + +A good place to do this is in the `create_one_network` function in `network.py`. +There you can add another `subprocess.run` call to run `iptables`. +The `192.168.0.0/24` value should not be hardcoded, but you can take it from the `ip_with_prefixlen` member of the `Net` object. + +## Task: Create a New Disk by Hand + +Navigate to `chapters/app-interact/os-cloud/drills/tasks/os-cloud/support`. +Let's replicate the above-mentioned steps and create a new disk ourselves. + +First, we have to call the 2 scripts from the `create_disk_from_template` function: + +```console +student@os:~/.../support$ ./disk-templates/ubuntu_22.04/create_disk_from_template.sh ./disk-templates/ubuntu_22.04/ubuntu_22.04.qcow2 my-disk.qcow2 10737418240 +Image resized. + +student@os:~/.../support$ ls -lh my-disk.qcow2 +-rw-r--r-- 1 student student 619M Nov 20 15:41 my-disk.qcow2 + +student@os:~/.../support$ sudo ./disk-templates/ubuntu_22.04/setup_root_password.sh my-disk.qcow2 123456 +``` + +Now we can start a qemu instance using this disk: + +```console +student@os:~/.../support$ qemu-system-x86_64 -enable-kvm -m 2G -hda my-disk.qcow2 -nographic +... +Ubuntu 22.04 LTS ubuntu ttyS0 + +ubuntu login: root +Password: +... +root@ubuntu:~# +``` + +Here we can further run customization commands, like the ones in the `ubuntu_22_04_vm_prepare` function, or any other things that we want. + +When we're done, we run the `halt` command: + +```console +root@ubuntu:~# halt +root@ubuntu:~# Stopping Session 1 of User root... +[ OK ] Removed slice /system/modprobe. +[ OK ] Stopped target Graphical Interface. +... + Starting System Halt... +[ 86.431398] reboot: System halted +``` + +When the `System halted` message is printed, press `CTRL+A X` to exit qemu (that is, press `CTRL+A`, release `CTRL` and `A`, press `X`). + +## Task: Implement `vm_stop` + +The `vm_stop` command will stop a particular virtual machine, meaning it will stop the qemu process for that vm. +The implementation starts in `api_vm_stop` in `app.py`, which is the function that handles the `http` request for the stop operation. +Here you need to do the following: + +- extract the virtual machine `id` from the request + +- use the `vm.vm_get` function to convert this ID into a `VM` structure + +- call `vm.vm_stop` and pass the `VM` object to it + +In `vm.vm_stop`: + +- call `stop_qemu_for_vm` + +- change the vm pid in the database to `-1` + +- change the vm state in the database to `VM_STATE_STOPPED` + +After modifying the code, you should run `docker-compose up --build` again. +Also, if your database became inconsistent, you can clean it up by re-running the `setup_db.sh` script. +Then delete all vm disks with `sudo rm -rf vm-disks/*`. + +With `vm_stop` implemented, the system should work like this: + +```console +student@os:~/.../support$ curl -s localhost:5000/vm_list | jq . +[ + { + "id": 1, + "name": "my_vm" + } +] +student@os:~/.../support$ curl -H "Content-Type: application/json" -d '{ "id": 1}' localhost:5000/vm_scurl -s -H "Content-Type: application/json" -d '{ "id": 1 }' localhost:5000/vm_info | jq . +{ + "disk_size": 10737418240, + "id": 1, + "ip": "192.168.0.2", + "mem_size": 2147483648, + "name": "my_vm", + "network": "default", + "os": "ubuntu_22.04", + "state": "RUNNING" +} +``` + +The vm is in the `RUNNING` state. +Now let's stop it: + +```console +student@os:~/.../support$ curl -H "Content-Type: application/json" -d '{ "id": 1}' localhost:5000/vm_stop +{"status":"ok"} +student@os:~/.../support$ curl -s -H "Content-Type: application/json" -d '{ "id": 1 }' localhost:5000/vm_info | jq . +{ + "disk_size": 10737418240, + "id": 1, + "ip": "192.168.0.2", + "mem_size": 2147483648, + "name": "my_vm", + "network": "default", + "os": "ubuntu_22.04", + "state": "STOPPED" +} +``` + +Now the state is `STOPPED`. +Inside the container, the qemu process should be gone as well: + +```console +student@os:~/.../support$ docker-compose exec os-cloud bash +root@b0600eff8903:/app# ps -ef +UID PID PPID C STIME TTY TIME CMD +root 1 0 0 10:00 ? 00:00:00 /sbin/docker-init -- python3 -u app.py +root 7 1 0 10:00 ? 00:00:00 python3 -u app.py +root 33 0 0 10:00 pts/3 00:00:00 bash +root 41 33 0 10:00 pts/3 00:00:00 ps -ef +``` + +Finally, the vm can be started again using `vm_start`: + +```console +student@os:~/.../support$ curl -H "Content-Type: application/json" -d '{ "id": 1}' localhost:5000/vm_start +{"status":"ok"} +``` + +If you're having difficulties solving this exercise, go through [this](../../../reading/os-cloud.md) reading material. + ## More Implementation Details The application consists of 2 containers: @@ -278,8 +557,8 @@ So, when we're calling `curl` like in the example above: ```console curl -H "Content-Type: application/json" \ - -d '{ "name": "my_vm", "image": "ubuntu_22.04", "network": "default", "mem_size": "2G", "disk_size": "10G"}' \ - localhost:5000/vm_create + -d '{ "name": "my_vm", "image": "ubuntu_22.04", "network": "default", "mem_size": "2G", "disk_size": "10G"}' \ + localhost:5000/vm_create ``` It will do an `HTTP POST` request (because of the `-d` parameter) to `/vm_create`. @@ -348,163 +627,3 @@ This explains why our vm received the ip address `192.168.0.2`. - There is a disk with the size of `10GB`, based on the `ubuntu_22.04` template, exactly like we requested. This disk is assigned to our vm (`disk_id` is `1`). The disk file will reside in `support/os-cloud/vm-disks/1/disk.qcow2`, or `/vm-disks/1/disk.qcow2` inside the container. - -## Virtual Machine Creation - -Take a look at the `vm_create` function in `support/os-cloud/os-cloud/vm.py`. -The steps undertaken are roughly: - -1. some initial allocations: the virtual machine IP address, network interface, qemu ports, etc - -1. the virtual machine disk is created, based on the template specified by the user (like `ubuntu_22.04`) - -1. the virtual machine is started with this new disk, in order to do some more customizations (the `ubuntu_22_04_vm_prepare` function) - -1. the virtual machine is restarted again with the final disk in place - -## Disk Creation - -All the disk templates are in `support/os-cloud/disk-templates`. -This directory will be mounted in `/disk-templates` inside the container. - -The first step of disk creation is to create a `qcow2` disk file based on the template specified by the user (step 2 from the explanation above). - -This is done in the `create_disk_from_template` function in `support/os-cloud/os-cloud/disk.py`. -The function will first create a disk object in the database, then it will call 2 shell scripts: `create_disk_from_template.sh` and `setup_root_password.sh`. - -The second step is to start the virtual machine with this disk and do some customizations (step 3 from above). - -This is done in the `ubuntu_22_04_vm_prepare` function in `support/os-cloud/os-cloud/vm.py`. -The code will connect to the vm's qemu serial console using `pexpect`. -Then it will use a series of `expect_exact` + `sendline` pairs to interact with the virtual machine, as if those commands were typed in the command-line. - -## Practice: Create a New Disk by Hand - -Let's replicate the above-mentioned steps and create a new disk ourselves. - -First, we have to call the 2 scripts from the `create_disk_from_template` function: - -```console -student@os:~/.../support/os-cloud$ ./disk-templates/ubuntu_22.04/create_disk_from_template.sh ./disk-templates/ubuntu_22.04/ubuntu_22.04.qcow2 my-disk.qcow2 10737418240 -Image resized. - -student@os:~/.../support/os-cloud$ ls -lh my-disk.qcow2 --rw-r--r-- 1 student student 619M Nov 20 15:41 my-disk.qcow2 - -student@os:~/.../support/os-cloud$ sudo ./disk-templates/ubuntu_22.04/setup_root_password.sh my-disk.qcow2 123456 -``` - -Now we can start a qemu instance using this disk: - -```console -student@os:~/.../support/os-cloud$ qemu-system-x86_64 -enable-kvm -m 2G -hda my-disk.qcow2 -nographic -... -Ubuntu 22.04 LTS ubuntu ttyS0 - -ubuntu login: root -Password: -... -root@ubuntu:~# -``` - -Here we can further run customization commands, like the ones in the `ubuntu_22_04_vm_prepare` function, or any other things that we want. - -When we're done, we run the `halt` command: - -```console -root@ubuntu:~# halt -root@ubuntu:~# Stopping Session 1 of User root... -[ OK ] Removed slice Slice /system/modprobe. -[ OK ] Stopped target Graphical Interface. -... - Starting System Halt... -[ 86.431398] reboot: System halted -``` - -When the `System halted` message is printed, press `CTRL+A X` to exit qemu (that is, press `CTRL+A`, release `CTRL` and `A`, press `X`). - -## Practice: Implement `vm_stop` - -The `vm_stop` command will stop a particular virtual machine, meaning it will stop the qemu process for that vm. -The implementation starts in `api_vm_stop` in `app.py`, which is the function that handles the `http` request for the stop operation. -Here you need to do the following: - -- extract the virtual machine `id` from the request - -- use the `vm.vm_get` function to convert this ID into a `VM` structure - -- call `vm.vm_stop` and pass the `VM` object to it - -In `vm.vm_stop`: - -- call `stop_qemu_for_vm` - -- change the vm pid in the database to `-1` - -- change the vm state in the database to `VM_STATE_STOPPED` - -After modifying the code, you should run `docker-compose up --build` again. -Also, if your database became inconsistent, you can clean it up by re-running the `setup_db.sh` script. -Then delete all vm disks with `sudo rm -rf vm-disks/*`. - -With `vm_stop` implemented, the system should work like this: - -```console -student@os:~/.../support/os-cloud$ curl -s localhost:5000/vm_list | jq . -[ - { - "id": 1, - "name": "my_vm" - } -] -student@os:~/.../support/os-cloud$ curl -H "Content-Type: application/json" -d '{ "id": 1}' localhost:5000/vm_scurl -s -H "Content-Type: application/json" -d '{ "id": 1 }' localhost:5000/vm_info | jq . -{ - "disk_size": 10737418240, - "id": 1, - "ip": "192.168.0.2", - "mem_size": 2147483648, - "name": "my_vm", - "network": "default", - "os": "ubuntu_22.04", - "state": "RUNNING" -} -``` - -The vm is in the `RUNNING` state. -Now let's stop it: - -```console -student@os:~/.../support/os-cloud$ curl -H "Content-Type: application/json" -d '{ "id": 1}' localhost:5000/vm_stop -{"status":"ok"} -student@os:~/.../support/os-cloud$ curl -s -H "Content-Type: application/json" -d '{ "id": 1 }' localhost:5000/vm_info | jq . -{ - "disk_size": 10737418240, - "id": 1, - "ip": "192.168.0.2", - "mem_size": 2147483648, - "name": "my_vm", - "network": "default", - "os": "ubuntu_22.04", - "state": "STOPPED" -} -``` - -Now the state is `STOPPED`. -Inside the container, the qemu process should be gone as well: - -```console -student@os:~/.../support/os-cloud$ docker-compose exec os-cloud bash -root@b0600eff8903:/app# ps -ef -UID PID PPID C STIME TTY TIME CMD -root 1 0 0 10:00 ? 00:00:00 /sbin/docker-init -- python3 -u app.py -root 7 1 0 10:00 ? 00:00:00 python3 -u app.py -root 33 0 0 10:00 pts/3 00:00:00 bash -root 41 33 0 10:00 pts/3 00:00:00 ps -ef -``` - -Finally, the vm can be started again using `vm_start`: - -```console -student@os:~/.../support/os-cloud$ curl -H "Content-Type: application/json" -d '{ "id": 1}' localhost:5000/vm_start -{"status":"ok"} -``` diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/.gitignore b/chapters/app-interact/overview/guides/comm-channels/.gitignore similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/.gitignore rename to chapters/app-interact/overview/guides/comm-channels/.gitignore diff --git a/chapters/app-interact/overview/guides/comm-channels/Makefile b/chapters/app-interact/overview/guides/comm-channels/Makefile new file mode 100644 index 0000000000..c340a0822d --- /dev/null +++ b/chapters/app-interact/overview/guides/comm-channels/Makefile @@ -0,0 +1,43 @@ +BINARIES = send_receive_pipe reader writer \ + send_fifo receive_fifo \ + send_unix_socket receive_unix_socket \ + send_net_dgram_socket receive_net_dgram_socket \ + send_net_stream_socket receive_net_stream_socket + +CC = gcc +MAKEFILE_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +INCLUDES_DIR := $(MAKEFILE_DIR)utils +LOGGER_DIR := $(INCLUDES_DIR)/log +SOCK_DIR := $(INCLUDES_DIR)/sock + +CPPFLAGS += -I$(INCLUDES_DIR) +CFLAGS += -g -Wall -Wextra +LDFLAGS += -z lazy + +# Object Files +LOGGER_OBJ = $(LOGGER_DIR)/log.o +SOCK_OBJ = $(SOCK_DIR)/sock_util.o + +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) + +# Build All Binaries +all: $(BINARIES) + +# Rule to Build Each Binary +%: %.c $(LOGGER_OBJ) $(SOCK_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +# Rule for Logger Object +$(LOGGER_OBJ): $(LOGGER_DIR)/log.c $(LOGGER_DIR)/log.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Rule for Socket Object +$(SOCK_OBJ): $(SOCK_DIR)/sock_util.c $(SOCK_DIR)/sock_util.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Clean Rule +clean: + -rm -f $(BINARIES) $(OBJS) $(LOGGER_OBJ) $(SOCK_OBJ) + +.PHONY: all clean diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/reader.c b/chapters/app-interact/overview/guides/comm-channels/reader.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/reader.c rename to chapters/app-interact/overview/guides/comm-channels/reader.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/receive_fifo.c b/chapters/app-interact/overview/guides/comm-channels/receive_fifo.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/receive_fifo.c rename to chapters/app-interact/overview/guides/comm-channels/receive_fifo.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/receive_net_dgram_socket.c b/chapters/app-interact/overview/guides/comm-channels/receive_net_dgram_socket.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/receive_net_dgram_socket.c rename to chapters/app-interact/overview/guides/comm-channels/receive_net_dgram_socket.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/receive_net_stream_socket.c b/chapters/app-interact/overview/guides/comm-channels/receive_net_stream_socket.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/receive_net_stream_socket.c rename to chapters/app-interact/overview/guides/comm-channels/receive_net_stream_socket.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/receive_unix_socket.c b/chapters/app-interact/overview/guides/comm-channels/receive_unix_socket.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/receive_unix_socket.c rename to chapters/app-interact/overview/guides/comm-channels/receive_unix_socket.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/send_fifo.c b/chapters/app-interact/overview/guides/comm-channels/send_fifo.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/send_fifo.c rename to chapters/app-interact/overview/guides/comm-channels/send_fifo.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/send_net_dgram_socket.c b/chapters/app-interact/overview/guides/comm-channels/send_net_dgram_socket.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/send_net_dgram_socket.c rename to chapters/app-interact/overview/guides/comm-channels/send_net_dgram_socket.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/send_net_stream_socket.c b/chapters/app-interact/overview/guides/comm-channels/send_net_stream_socket.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/send_net_stream_socket.c rename to chapters/app-interact/overview/guides/comm-channels/send_net_stream_socket.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/send_receive_pipe.c b/chapters/app-interact/overview/guides/comm-channels/send_receive_pipe.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/send_receive_pipe.c rename to chapters/app-interact/overview/guides/comm-channels/send_receive_pipe.c diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/send_unix_socket.c b/chapters/app-interact/overview/guides/comm-channels/send_unix_socket.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/send_unix_socket.c rename to chapters/app-interact/overview/guides/comm-channels/send_unix_socket.c diff --git a/content/chapters/app-interact/lab/solution/utils/log/CPPLINT.cfg b/chapters/app-interact/overview/guides/comm-channels/utils/log/CPPLINT.cfg similarity index 100% rename from content/chapters/app-interact/lab/solution/utils/log/CPPLINT.cfg rename to chapters/app-interact/overview/guides/comm-channels/utils/log/CPPLINT.cfg diff --git a/content/chapters/app-interact/lab/solution/utils/log/log.c b/chapters/app-interact/overview/guides/comm-channels/utils/log/log.c similarity index 100% rename from content/chapters/app-interact/lab/solution/utils/log/log.c rename to chapters/app-interact/overview/guides/comm-channels/utils/log/log.c diff --git a/content/chapters/app-interact/lab/support/utils/log/log.h b/chapters/app-interact/overview/guides/comm-channels/utils/log/log.h similarity index 59% rename from content/chapters/app-interact/lab/support/utils/log/log.h rename to chapters/app-interact/overview/guides/comm-channels/utils/log/log.h index c8d1dee06a..7acb55aab6 100644 --- a/content/chapters/app-interact/lab/support/utils/log/log.h +++ b/chapters/app-interact/overview/guides/comm-channels/utils/log/log.h @@ -24,27 +24,27 @@ extern "C" #define LOG_VERSION "0.1.0" - typedef struct { - va_list ap; - const char *fmt; - const char *file; - struct tm *time; - void *udata; - int line; - int level; - } log_Event; +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; - typedef void (*log_LogFn)(log_Event *ev); - typedef void (*log_LockFn)(bool lock, void *udata); +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); - enum { - LOG_TRACE, - LOG_DEBUG, - LOG_INFO, - LOG_WARN, - LOG_ERROR, - LOG_FATAL - }; +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) @@ -53,14 +53,14 @@ extern "C" #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) - const char *log_level_string(int level); - void log_set_lock(log_LockFn fn, void *udata); - void log_set_level(int level); - void log_set_quiet(bool enable); - int log_add_callback(log_LogFn fn, void *udata, int level); - int log_add_fp(FILE *fp, int level); +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); - void log_log(int level, const char *file, int line, const char *fmt, ...); +void log_log(int level, const char *file, int line, const char *fmt, ...); #ifdef __cplusplus } diff --git a/chapters/app-interact/overview/guides/comm-channels/utils/sock/sock_util.c b/chapters/app-interact/overview/guides/comm-channels/utils/sock/sock_util.c new file mode 100644 index 0000000000..b426f20c29 --- /dev/null +++ b/chapters/app-interact/overview/guides/comm-channels/utils/sock/sock_util.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Useful socket functions + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../utils.h" +#include "../log/log.h" +#include "sock_util.h" + +/* + * Connect to a TCP server identified by name (DNS name or dotted decimal + * string) and port. + */ + +int tcp_connect_to_server(const char *name, unsigned short port) +{ + struct hostent *hent; + struct sockaddr_in server_addr; + int s; + int rc; + + hent = gethostbyname(name); + DIE(hent == NULL, "gethostbyname"); + + s = socket(PF_INET, SOCK_STREAM, 0); + DIE(s < 0, "socket"); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, + sizeof(server_addr.sin_addr.s_addr)); + + rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); + DIE(rc < 0, "connect"); + + return s; +} + +int tcp_close_connection(int sockfd) +{ + int rc; + + rc = shutdown(sockfd, SHUT_RDWR); + DIE(rc < 0, "shutdown"); + + return close(sockfd); +} + +/* + * Create a server socket. + */ + +int tcp_create_listener(unsigned short port, int backlog) +{ + struct sockaddr_in address; + int listenfd; + int sock_opt; + int rc; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + + sock_opt = 1; + rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + &sock_opt, sizeof(int)); + DIE(rc < 0, "setsockopt"); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + + rc = bind(listenfd, (SSA *) &address, sizeof(address)); + DIE(rc < 0, "bind"); + + rc = listen(listenfd, backlog); + DIE(rc < 0, "listen"); + + return listenfd; +} + +/* + * Use getpeername(2) to extract remote peer address. Fill buffer with + * address format IP_address:port (e.g. 192.168.0.1:22). + */ + +int get_peer_address(int sockfd, char *buf, size_t len) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) + return -1; + + snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return 0; +} diff --git a/chapters/app-interact/overview/guides/comm-channels/utils/sock/sock_util.h b/chapters/app-interact/overview/guides/comm-channels/utils/sock/sock_util.h new file mode 100644 index 0000000000..906976dc94 --- /dev/null +++ b/chapters/app-interact/overview/guides/comm-channels/utils/sock/sock_util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Useful socket macros and structures + */ + +#ifndef SOCK_UTIL_H_ +#define SOCK_UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* default backlog for listen(2) system call */ +#define DEFAULT_LISTEN_BACKLOG 5 + +/* "shortcut" for struct sockaddr structure */ +#define SSA struct sockaddr + + +int tcp_connect_to_server(const char *name, unsigned short port); +int tcp_close_connection(int s); +int tcp_create_listener(unsigned short port, int backlog); +int get_peer_address(int sockfd, char *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/content/chapters/app-interact/lab/solution/utils/utils.h b/chapters/app-interact/overview/guides/comm-channels/utils/utils.h similarity index 100% rename from content/chapters/app-interact/lab/solution/utils/utils.h rename to chapters/app-interact/overview/guides/comm-channels/utils/utils.h diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/writer.c b/chapters/app-interact/overview/guides/comm-channels/writer.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/comm-channels/writer.c rename to chapters/app-interact/overview/guides/comm-channels/writer.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/.gitignore b/chapters/app-interact/overview/guides/fibonacci-server/.gitignore similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/.gitignore rename to chapters/app-interact/overview/guides/fibonacci-server/.gitignore diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/CPPLINT.cfg b/chapters/app-interact/overview/guides/fibonacci-server/CPPLINT.cfg similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/CPPLINT.cfg rename to chapters/app-interact/overview/guides/fibonacci-server/CPPLINT.cfg diff --git a/chapters/app-interact/overview/guides/fibonacci-server/Makefile b/chapters/app-interact/overview/guides/fibonacci-server/Makefile new file mode 100644 index 0000000000..2936ecffab --- /dev/null +++ b/chapters/app-interact/overview/guides/fibonacci-server/Makefile @@ -0,0 +1,50 @@ +BINARIES = server mt_server mp_server mt_pool_server mp_pool_server_works + +CC = gcc +MAKEFILE_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +INCLUDES_DIR := $(MAKEFILE_DIR)utils +LOGGER_DIR := $(INCLUDES_DIR)/log +SOCK_DIR := $(INCLUDES_DIR)/sock + +CPPFLAGS += -I$(INCLUDES_DIR) +CFLAGS += -g -Wall -Wextra +LDFLAGS += -z lazy + +LOGGER_OBJ = $(LOGGER_DIR)/log.o +SOCK_OBJ = $(SOCK_DIR)/sock_util.o +CONNECTIONS_OBJ = connection.o +TASK_OBJ = task.o + +all: $(BINARIES) + +server: server.o $(LOGGER_OBJ) $(SOCK_OBJ) $(CONNECTIONS_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +mt_server: mt_server.o $(LOGGER_OBJ) $(SOCK_OBJ) $(CONNECTIONS_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +mp_server: mp_server.o $(LOGGER_OBJ) $(SOCK_OBJ) $(CONNECTIONS_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +mt_pool_server: mt_pool_server.o $(LOGGER_OBJ) $(SOCK_OBJ) $(CONNECTIONS_OBJ) $(TASK_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +mp_pool_server_works: mp_pool_server_works.o $(LOGGER_OBJ) $(SOCK_OBJ) $(CONNECTIONS_OBJ) $(TASK_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +$(LOGGER_OBJ): $(LOGGER_DIR)/log.c $(LOGGER_DIR)/log.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +$(SOCK_OBJ): $(SOCK_DIR)/sock_util.c $(SOCK_DIR)/sock_util.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +$(CONNECTIONS_OBJ): connection.c connection.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +$(TASK_OBJ): task.c task.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(BINARIES) *.o $(LOGGER_OBJ) $(SOCK_OBJ) $(CONNECTIONS_OBJ) $(TASK_OBJ) + +.PHONY: all clean diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/connection.c b/chapters/app-interact/overview/guides/fibonacci-server/connection.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/connection.c rename to chapters/app-interact/overview/guides/fibonacci-server/connection.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/connection.h b/chapters/app-interact/overview/guides/fibonacci-server/connection.h similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/connection.h rename to chapters/app-interact/overview/guides/fibonacci-server/connection.h diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/mp_pool_server.c b/chapters/app-interact/overview/guides/fibonacci-server/mp_pool_server.c similarity index 98% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/mp_pool_server.c rename to chapters/app-interact/overview/guides/fibonacci-server/mp_pool_server.c index c77326342a..afa291218d 100644 --- a/content/chapters/app-interact/lecture/demo/fibonacci-server/mp_pool_server.c +++ b/chapters/app-interact/overview/guides/fibonacci-server/mp_pool_server.c @@ -51,7 +51,7 @@ static void create_process_pool(size_t num_processes) * before the prctl() call. */ if (getppid() != parent_pid) - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); handle(); break; default: diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/mp_pool_server_works.c b/chapters/app-interact/overview/guides/fibonacci-server/mp_pool_server_works.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/mp_pool_server_works.c rename to chapters/app-interact/overview/guides/fibonacci-server/mp_pool_server_works.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/mp_server.c b/chapters/app-interact/overview/guides/fibonacci-server/mp_server.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/mp_server.c rename to chapters/app-interact/overview/guides/fibonacci-server/mp_server.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/mt_pool_server.c b/chapters/app-interact/overview/guides/fibonacci-server/mt_pool_server.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/mt_pool_server.c rename to chapters/app-interact/overview/guides/fibonacci-server/mt_pool_server.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/mt_server.c b/chapters/app-interact/overview/guides/fibonacci-server/mt_server.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/mt_server.c rename to chapters/app-interact/overview/guides/fibonacci-server/mt_server.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/server.c b/chapters/app-interact/overview/guides/fibonacci-server/server.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/server.c rename to chapters/app-interact/overview/guides/fibonacci-server/server.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/task.c b/chapters/app-interact/overview/guides/fibonacci-server/task.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/task.c rename to chapters/app-interact/overview/guides/fibonacci-server/task.c diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/task.h b/chapters/app-interact/overview/guides/fibonacci-server/task.h similarity index 100% rename from content/chapters/app-interact/lecture/demo/fibonacci-server/task.h rename to chapters/app-interact/overview/guides/fibonacci-server/task.h diff --git a/content/chapters/app-interact/lab/support/utils/log/CPPLINT.cfg b/chapters/app-interact/overview/guides/fibonacci-server/utils/log/CPPLINT.cfg similarity index 100% rename from content/chapters/app-interact/lab/support/utils/log/CPPLINT.cfg rename to chapters/app-interact/overview/guides/fibonacci-server/utils/log/CPPLINT.cfg diff --git a/content/chapters/app-interact/lab/support/utils/log/log.c b/chapters/app-interact/overview/guides/fibonacci-server/utils/log/log.c similarity index 100% rename from content/chapters/app-interact/lab/support/utils/log/log.c rename to chapters/app-interact/overview/guides/fibonacci-server/utils/log/log.c diff --git a/content/chapters/app-interact/lab/solution/utils/log/log.h b/chapters/app-interact/overview/guides/fibonacci-server/utils/log/log.h similarity index 59% rename from content/chapters/app-interact/lab/solution/utils/log/log.h rename to chapters/app-interact/overview/guides/fibonacci-server/utils/log/log.h index c8d1dee06a..7acb55aab6 100644 --- a/content/chapters/app-interact/lab/solution/utils/log/log.h +++ b/chapters/app-interact/overview/guides/fibonacci-server/utils/log/log.h @@ -24,27 +24,27 @@ extern "C" #define LOG_VERSION "0.1.0" - typedef struct { - va_list ap; - const char *fmt; - const char *file; - struct tm *time; - void *udata; - int line; - int level; - } log_Event; +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; - typedef void (*log_LogFn)(log_Event *ev); - typedef void (*log_LockFn)(bool lock, void *udata); +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); - enum { - LOG_TRACE, - LOG_DEBUG, - LOG_INFO, - LOG_WARN, - LOG_ERROR, - LOG_FATAL - }; +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) @@ -53,14 +53,14 @@ extern "C" #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) - const char *log_level_string(int level); - void log_set_lock(log_LockFn fn, void *udata); - void log_set_level(int level); - void log_set_quiet(bool enable); - int log_add_callback(log_LogFn fn, void *udata, int level); - int log_add_fp(FILE *fp, int level); +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); - void log_log(int level, const char *file, int line, const char *fmt, ...); +void log_log(int level, const char *file, int line, const char *fmt, ...); #ifdef __cplusplus } diff --git a/chapters/app-interact/overview/guides/fibonacci-server/utils/sock/sock_util.c b/chapters/app-interact/overview/guides/fibonacci-server/utils/sock/sock_util.c new file mode 100644 index 0000000000..b426f20c29 --- /dev/null +++ b/chapters/app-interact/overview/guides/fibonacci-server/utils/sock/sock_util.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Useful socket functions + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../utils.h" +#include "../log/log.h" +#include "sock_util.h" + +/* + * Connect to a TCP server identified by name (DNS name or dotted decimal + * string) and port. + */ + +int tcp_connect_to_server(const char *name, unsigned short port) +{ + struct hostent *hent; + struct sockaddr_in server_addr; + int s; + int rc; + + hent = gethostbyname(name); + DIE(hent == NULL, "gethostbyname"); + + s = socket(PF_INET, SOCK_STREAM, 0); + DIE(s < 0, "socket"); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, + sizeof(server_addr.sin_addr.s_addr)); + + rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); + DIE(rc < 0, "connect"); + + return s; +} + +int tcp_close_connection(int sockfd) +{ + int rc; + + rc = shutdown(sockfd, SHUT_RDWR); + DIE(rc < 0, "shutdown"); + + return close(sockfd); +} + +/* + * Create a server socket. + */ + +int tcp_create_listener(unsigned short port, int backlog) +{ + struct sockaddr_in address; + int listenfd; + int sock_opt; + int rc; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + + sock_opt = 1; + rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + &sock_opt, sizeof(int)); + DIE(rc < 0, "setsockopt"); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + + rc = bind(listenfd, (SSA *) &address, sizeof(address)); + DIE(rc < 0, "bind"); + + rc = listen(listenfd, backlog); + DIE(rc < 0, "listen"); + + return listenfd; +} + +/* + * Use getpeername(2) to extract remote peer address. Fill buffer with + * address format IP_address:port (e.g. 192.168.0.1:22). + */ + +int get_peer_address(int sockfd, char *buf, size_t len) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) + return -1; + + snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return 0; +} diff --git a/chapters/app-interact/overview/guides/fibonacci-server/utils/sock/sock_util.h b/chapters/app-interact/overview/guides/fibonacci-server/utils/sock/sock_util.h new file mode 100644 index 0000000000..906976dc94 --- /dev/null +++ b/chapters/app-interact/overview/guides/fibonacci-server/utils/sock/sock_util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Useful socket macros and structures + */ + +#ifndef SOCK_UTIL_H_ +#define SOCK_UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* default backlog for listen(2) system call */ +#define DEFAULT_LISTEN_BACKLOG 5 + +/* "shortcut" for struct sockaddr structure */ +#define SSA struct sockaddr + + +int tcp_connect_to_server(const char *name, unsigned short port); +int tcp_close_connection(int s); +int tcp_create_listener(unsigned short port, int backlog); +int get_peer_address(int sockfd, char *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/content/chapters/app-interact/lab/support/utils/utils.h b/chapters/app-interact/overview/guides/fibonacci-server/utils/utils.h similarity index 100% rename from content/chapters/app-interact/lab/support/utils/utils.h rename to chapters/app-interact/overview/guides/fibonacci-server/utils/utils.h diff --git a/content/chapters/app-interact/lecture/demo/interrupt/.gitignore b/chapters/app-interact/overview/guides/interrupt/.gitignore similarity index 100% rename from content/chapters/app-interact/lecture/demo/interrupt/.gitignore rename to chapters/app-interact/overview/guides/interrupt/.gitignore diff --git a/chapters/app-interact/overview/guides/interrupt/Makefile b/chapters/app-interact/overview/guides/interrupt/Makefile new file mode 100644 index 0000000000..01c94a0a70 --- /dev/null +++ b/chapters/app-interact/overview/guides/interrupt/Makefile @@ -0,0 +1,27 @@ +BINARIES = signal_printer rt_signal_printer signal_sender signal_sender_sleep rt_signal_sender + +CC = gcc +MAKEFILE_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +INCLUDES_DIR := $(MAKEFILE_DIR)utils +LOGGER_DIR := $(INCLUDES_DIR)/log + +CPPFLAGS += -I$(INCLUDES_DIR) +CFLAGS += -g -Wall -Wextra +LDFLAGS += -z lazy +LOGGER_OBJ = $(LOGGER_DIR)/log.o + +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) + +all: $(BINARIES) + +%: %.c $(LOGGER_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +$(LOGGER_OBJ): $(LOGGER_DIR)/log.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +clean: + -rm -f $(BINARIES) $(OBJS) $(LOGGER_OBJ) + +.PHONY: all clean diff --git a/content/chapters/app-interact/lecture/demo/interrupt/rt_signal_printer.c b/chapters/app-interact/overview/guides/interrupt/rt_signal_printer.c similarity index 99% rename from content/chapters/app-interact/lecture/demo/interrupt/rt_signal_printer.c rename to chapters/app-interact/overview/guides/interrupt/rt_signal_printer.c index f1ea66e26d..976fdf809b 100644 --- a/content/chapters/app-interact/lecture/demo/interrupt/rt_signal_printer.c +++ b/chapters/app-interact/overview/guides/interrupt/rt_signal_printer.c @@ -33,6 +33,7 @@ int main(void) while (1) { sigset_t oldset; + sigprocmask(0, NULL, &oldset); sigsuspend(&oldset); } diff --git a/content/chapters/app-interact/lecture/demo/interrupt/rt_signal_sender.c b/chapters/app-interact/overview/guides/interrupt/rt_signal_sender.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/interrupt/rt_signal_sender.c rename to chapters/app-interact/overview/guides/interrupt/rt_signal_sender.c diff --git a/content/chapters/app-interact/lecture/demo/interrupt/rt_signal_sender.sh b/chapters/app-interact/overview/guides/interrupt/rt_signal_sender.sh similarity index 92% rename from content/chapters/app-interact/lecture/demo/interrupt/rt_signal_sender.sh rename to chapters/app-interact/overview/guides/interrupt/rt_signal_sender.sh index 9a694a94df..77d33ea601 100755 --- a/content/chapters/app-interact/lecture/demo/interrupt/rt_signal_sender.sh +++ b/chapters/app-interact/overview/guides/interrupt/rt_signal_sender.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause pid=$(pgrep -f "rt_signal_printer") if test -z "$pid"; then diff --git a/content/chapters/app-interact/lecture/demo/interrupt/signal_printer.c b/chapters/app-interact/overview/guides/interrupt/signal_printer.c similarity index 99% rename from content/chapters/app-interact/lecture/demo/interrupt/signal_printer.c rename to chapters/app-interact/overview/guides/interrupt/signal_printer.c index 55f601cf47..13cc9623bd 100644 --- a/content/chapters/app-interact/lecture/demo/interrupt/signal_printer.c +++ b/chapters/app-interact/overview/guides/interrupt/signal_printer.c @@ -62,6 +62,7 @@ int main(void) while (1) { sigset_t oldset; + sigprocmask(0, NULL, &oldset); sigsuspend(&oldset); } diff --git a/content/chapters/app-interact/lecture/demo/interrupt/signal_printer.sh b/chapters/app-interact/overview/guides/interrupt/signal_printer.sh similarity index 88% rename from content/chapters/app-interact/lecture/demo/interrupt/signal_printer.sh rename to chapters/app-interact/overview/guides/interrupt/signal_printer.sh index f544be8413..910c274b1c 100755 --- a/content/chapters/app-interact/lecture/demo/interrupt/signal_printer.sh +++ b/chapters/app-interact/overview/guides/interrupt/signal_printer.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause DEBUG=0 diff --git a/content/chapters/app-interact/lecture/demo/interrupt/signal_sender.c b/chapters/app-interact/overview/guides/interrupt/signal_sender.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/interrupt/signal_sender.c rename to chapters/app-interact/overview/guides/interrupt/signal_sender.c diff --git a/content/chapters/app-interact/lecture/demo/interrupt/signal_sender.sh b/chapters/app-interact/overview/guides/interrupt/signal_sender.sh similarity index 91% rename from content/chapters/app-interact/lecture/demo/interrupt/signal_sender.sh rename to chapters/app-interact/overview/guides/interrupt/signal_sender.sh index 2b5bd25caf..09e83bd0a4 100755 --- a/content/chapters/app-interact/lecture/demo/interrupt/signal_sender.sh +++ b/chapters/app-interact/overview/guides/interrupt/signal_sender.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause pid=$(pgrep -f "signal_printer") if test -z "$pid"; then diff --git a/content/chapters/app-interact/lecture/demo/interrupt/signal_sender_sleep.c b/chapters/app-interact/overview/guides/interrupt/signal_sender_sleep.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/interrupt/signal_sender_sleep.c rename to chapters/app-interact/overview/guides/interrupt/signal_sender_sleep.c diff --git a/content/chapters/app-interact/lecture/demo/interrupt/signal_sender_sleep.sh b/chapters/app-interact/overview/guides/interrupt/signal_sender_sleep.sh similarity index 92% rename from content/chapters/app-interact/lecture/demo/interrupt/signal_sender_sleep.sh rename to chapters/app-interact/overview/guides/interrupt/signal_sender_sleep.sh index ed9c80607b..29979c50fd 100755 --- a/content/chapters/app-interact/lecture/demo/interrupt/signal_sender_sleep.sh +++ b/chapters/app-interact/overview/guides/interrupt/signal_sender_sleep.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause pid=$(pgrep -f "signal_printer") if test -z "$pid"; then diff --git a/chapters/app-interact/overview/guides/interrupt/utils/log/CPPLINT.cfg b/chapters/app-interact/overview/guides/interrupt/utils/log/CPPLINT.cfg new file mode 100644 index 0000000000..5aa9cb376c --- /dev/null +++ b/chapters/app-interact/overview/guides/interrupt/utils/log/CPPLINT.cfg @@ -0,0 +1 @@ +exclude_files=log\.c diff --git a/chapters/app-interact/overview/guides/interrupt/utils/log/log.c b/chapters/app-interact/overview/guides/interrupt/utils/log/log.c new file mode 100644 index 0000000000..ac65f4ed33 --- /dev/null +++ b/chapters/app-interact/overview/guides/interrupt/utils/log/log.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Copyright (c) 2020 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct +{ + void *udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char * const level_strings[] = { "TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL" }; + +#ifdef LOG_USE_COLOR +static const char * const level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m" }; +#endif + +static void +stdout_callback(log_Event *ev) +{ + char buf[16]; + + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, + "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, + level_colors[ev->level], + level_strings[ev->level], + ev->file, + ev->line); +#else + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +file_callback(log_Event *ev) +{ + char buf[64]; + + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +lock(void) +{ + if (L.lock) + L.lock(true, L.udata); +} + +static void +unlock(void) +{ + if (L.lock) + L.lock(false, L.udata); +} + +const char* +log_level_string(int level) +{ + return level_strings[level]; +} + +void +log_set_lock(log_LockFn fn, void *udata) +{ + L.lock = fn; + L.udata = udata; +} + +void +log_set_level(int level) +{ + L.level = level; +} + +void +log_set_quiet(bool enable) +{ + L.quiet = enable; +} + +int +log_add_callback(log_LogFn fn, void *udata, int level) +{ + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + +int +log_add_fp(FILE *fp, int level) +{ + return log_add_callback(file_callback, fp, level); +} + +static void +init_event(log_Event *ev, void *udata) +{ + if (!ev->time) { + time_t t = time(NULL); + + ev->time = localtime(&t); + } + ev->udata = udata; +} + +void +log_log(int level, const char *file, int line, const char *fmt, ...) +{ + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} diff --git a/chapters/app-interact/overview/guides/interrupt/utils/log/log.h b/chapters/app-interact/overview/guides/interrupt/utils/log/log.h new file mode 100644 index 0000000000..7acb55aab6 --- /dev/null +++ b/chapters/app-interact/overview/guides/interrupt/utils/log/log.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * Copyright (c) 2020 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_H */ diff --git a/chapters/app-interact/overview/guides/interrupt/utils/sock/sock_util.c b/chapters/app-interact/overview/guides/interrupt/utils/sock/sock_util.c new file mode 100644 index 0000000000..78581b2239 --- /dev/null +++ b/chapters/app-interact/overview/guides/interrupt/utils/sock/sock_util.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Useful socket functions + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "utils/utils.h" +#include "utils/log/log.h" +#include "utils/sock/sock_util.h" + +/* + * Connect to a TCP server identified by name (DNS name or dotted decimal + * string) and port. + */ + +int tcp_connect_to_server(const char *name, unsigned short port) +{ + struct hostent *hent; + struct sockaddr_in server_addr; + int s; + int rc; + + hent = gethostbyname(name); + DIE(hent == NULL, "gethostbyname"); + + s = socket(PF_INET, SOCK_STREAM, 0); + DIE(s < 0, "socket"); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, + sizeof(server_addr.sin_addr.s_addr)); + + rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); + DIE(rc < 0, "connect"); + + return s; +} + +int tcp_close_connection(int sockfd) +{ + int rc; + + rc = shutdown(sockfd, SHUT_RDWR); + DIE(rc < 0, "shutdown"); + + return close(sockfd); +} + +/* + * Create a server socket. + */ + +int tcp_create_listener(unsigned short port, int backlog) +{ + struct sockaddr_in address; + int listenfd; + int sock_opt; + int rc; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + + sock_opt = 1; + rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + &sock_opt, sizeof(int)); + DIE(rc < 0, "setsockopt"); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + + rc = bind(listenfd, (SSA *) &address, sizeof(address)); + DIE(rc < 0, "bind"); + + rc = listen(listenfd, backlog); + DIE(rc < 0, "listen"); + + return listenfd; +} + +/* + * Use getpeername(2) to extract remote peer address. Fill buffer with + * address format IP_address:port (e.g. 192.168.0.1:22). + */ + +int get_peer_address(int sockfd, char *buf, size_t len) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) + return -1; + + snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return 0; +} diff --git a/chapters/app-interact/overview/guides/interrupt/utils/sock/sock_util.h b/chapters/app-interact/overview/guides/interrupt/utils/sock/sock_util.h new file mode 100644 index 0000000000..906976dc94 --- /dev/null +++ b/chapters/app-interact/overview/guides/interrupt/utils/sock/sock_util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Useful socket macros and structures + */ + +#ifndef SOCK_UTIL_H_ +#define SOCK_UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* default backlog for listen(2) system call */ +#define DEFAULT_LISTEN_BACKLOG 5 + +/* "shortcut" for struct sockaddr structure */ +#define SSA struct sockaddr + + +int tcp_connect_to_server(const char *name, unsigned short port); +int tcp_close_connection(int s); +int tcp_create_listener(unsigned short port, int backlog); +int get_peer_address(int sockfd, char *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/chapters/app-interact/overview/guides/interrupt/utils/utils.h b/chapters/app-interact/overview/guides/interrupt/utils/utils.h new file mode 100644 index 0000000000..efdf6b59dd --- /dev/null +++ b/chapters/app-interact/overview/guides/interrupt/utils/utils.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef UTILS_H_ +#define UTILS_H_ 1 + +#include +#include +#include +#include +#include "log/log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR(assertion, call_description) \ + do { \ + if (assertion) \ + log_error("%s: %s", \ + call_description, strerror(errno)); \ + } while (0) + +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + log_fatal("%s: %s", \ + call_description, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_H_ */ diff --git a/content/chapters/app-interact/lecture/demo/lock/.gitignore b/chapters/app-interact/overview/guides/lock/.gitignore similarity index 100% rename from content/chapters/app-interact/lecture/demo/lock/.gitignore rename to chapters/app-interact/overview/guides/lock/.gitignore diff --git a/chapters/app-interact/overview/guides/lock/Makefile b/chapters/app-interact/overview/guides/lock/Makefile new file mode 100644 index 0000000000..26f07d3869 --- /dev/null +++ b/chapters/app-interact/overview/guides/lock/Makefile @@ -0,0 +1,50 @@ +# Executables to build +BINARIES = thread_mutex thread_sem proc_sem proc_flock + +# Compiler and Flags +CC = gcc +MAKEFILE_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +INCLUDES_DIR := $(MAKEFILE_DIR)utils +LOGGER_DIR := $(INCLUDES_DIR)/log +SOCK_DIR := $(INCLUDES_DIR)/sock + +CPPFLAGS += -I$(INCLUDES_DIR) +CFLAGS += -g -Wall -Wextra +LDFLAGS += -z lazy + +# External libraries (if not set outside, defaults to -lpthread) +LDLIBS ?= -lpthread + +# Object Files +LOGGER_OBJ = $(LOGGER_DIR)/log.o +SOCK_OBJ = $(SOCK_DIR)/sock_util.o + +# Build all binaries by default +all: $(BINARIES) + +# Rules for each binary +thread_mutex: thread_mutex.o $(LOGGER_OBJ) $(SOCK_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +thread_sem: thread_sem.o $(LOGGER_OBJ) $(SOCK_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +proc_sem: proc_sem.o $(LOGGER_OBJ) $(SOCK_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +proc_flock: proc_flock.o $(LOGGER_OBJ) $(SOCK_OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +# Logger Object +$(LOGGER_OBJ): $(LOGGER_DIR)/log.c $(LOGGER_DIR)/log.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Socket Object +$(SOCK_OBJ): $(SOCK_DIR)/sock_util.c $(SOCK_DIR)/sock_util.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Clean rule +clean: + -rm -f $(BINARIES) *.o $(LOGGER_OBJ) $(SOCK_OBJ) + +.PHONY: all clean diff --git a/content/chapters/app-interact/lecture/demo/lock/proc_flock.c b/chapters/app-interact/overview/guides/lock/proc_flock.c similarity index 98% rename from content/chapters/app-interact/lecture/demo/lock/proc_flock.c rename to chapters/app-interact/overview/guides/lock/proc_flock.c index c431acdf1a..f9c8e5d605 100644 --- a/content/chapters/app-interact/lecture/demo/lock/proc_flock.c +++ b/chapters/app-interact/overview/guides/lock/proc_flock.c @@ -32,7 +32,7 @@ static void release_lock(void) DIE(rc, "flock"); } -static unsigned long var = 0; +static unsigned long var; static void read_var(void) { diff --git a/content/chapters/app-interact/lecture/demo/lock/proc_sem.c b/chapters/app-interact/overview/guides/lock/proc_sem.c similarity index 98% rename from content/chapters/app-interact/lecture/demo/lock/proc_sem.c rename to chapters/app-interact/overview/guides/lock/proc_sem.c index 29c9f7fb0d..6741d64e72 100644 --- a/content/chapters/app-interact/lecture/demo/lock/proc_sem.c +++ b/chapters/app-interact/overview/guides/lock/proc_sem.c @@ -32,7 +32,7 @@ static void release_lock(void) DIE(rc, "sem_post"); } -static unsigned long var = 0; +static unsigned long var; static void read_var(void) { diff --git a/content/chapters/app-interact/lecture/demo/lock/thread_mutex.c b/chapters/app-interact/overview/guides/lock/thread_mutex.c similarity index 97% rename from content/chapters/app-interact/lecture/demo/lock/thread_mutex.c rename to chapters/app-interact/overview/guides/lock/thread_mutex.c index 0911e70cd7..8e16b8a85b 100644 --- a/content/chapters/app-interact/lecture/demo/lock/thread_mutex.c +++ b/chapters/app-interact/overview/guides/lock/thread_mutex.c @@ -24,7 +24,7 @@ static void release_lock(void) DIE(rc, "pthread_mutex_unlock"); } -static unsigned long var = 0; +static unsigned long var; static void *increase_var(void *arg) { diff --git a/content/chapters/app-interact/lecture/demo/lock/thread_sem.c b/chapters/app-interact/overview/guides/lock/thread_sem.c similarity index 97% rename from content/chapters/app-interact/lecture/demo/lock/thread_sem.c rename to chapters/app-interact/overview/guides/lock/thread_sem.c index 9c75408092..188ab3c6b1 100644 --- a/content/chapters/app-interact/lecture/demo/lock/thread_sem.c +++ b/chapters/app-interact/overview/guides/lock/thread_sem.c @@ -25,7 +25,7 @@ static void release_lock(void) DIE(rc, "sem_post"); } -static unsigned long var = 0; +static unsigned long var; static void *increase_var(void *arg) { diff --git a/chapters/app-interact/overview/guides/lock/utils/log/CPPLINT.cfg b/chapters/app-interact/overview/guides/lock/utils/log/CPPLINT.cfg new file mode 100644 index 0000000000..5aa9cb376c --- /dev/null +++ b/chapters/app-interact/overview/guides/lock/utils/log/CPPLINT.cfg @@ -0,0 +1 @@ +exclude_files=log\.c diff --git a/chapters/app-interact/overview/guides/lock/utils/log/log.c b/chapters/app-interact/overview/guides/lock/utils/log/log.c new file mode 100644 index 0000000000..ac65f4ed33 --- /dev/null +++ b/chapters/app-interact/overview/guides/lock/utils/log/log.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Copyright (c) 2020 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct +{ + void *udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char * const level_strings[] = { "TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL" }; + +#ifdef LOG_USE_COLOR +static const char * const level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m" }; +#endif + +static void +stdout_callback(log_Event *ev) +{ + char buf[16]; + + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, + "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, + level_colors[ev->level], + level_strings[ev->level], + ev->file, + ev->line); +#else + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +file_callback(log_Event *ev) +{ + char buf[64]; + + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +lock(void) +{ + if (L.lock) + L.lock(true, L.udata); +} + +static void +unlock(void) +{ + if (L.lock) + L.lock(false, L.udata); +} + +const char* +log_level_string(int level) +{ + return level_strings[level]; +} + +void +log_set_lock(log_LockFn fn, void *udata) +{ + L.lock = fn; + L.udata = udata; +} + +void +log_set_level(int level) +{ + L.level = level; +} + +void +log_set_quiet(bool enable) +{ + L.quiet = enable; +} + +int +log_add_callback(log_LogFn fn, void *udata, int level) +{ + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + +int +log_add_fp(FILE *fp, int level) +{ + return log_add_callback(file_callback, fp, level); +} + +static void +init_event(log_Event *ev, void *udata) +{ + if (!ev->time) { + time_t t = time(NULL); + + ev->time = localtime(&t); + } + ev->udata = udata; +} + +void +log_log(int level, const char *file, int line, const char *fmt, ...) +{ + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} diff --git a/chapters/app-interact/overview/guides/lock/utils/log/log.h b/chapters/app-interact/overview/guides/lock/utils/log/log.h new file mode 100644 index 0000000000..7acb55aab6 --- /dev/null +++ b/chapters/app-interact/overview/guides/lock/utils/log/log.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * Copyright (c) 2020 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_H */ diff --git a/chapters/app-interact/overview/guides/lock/utils/sock/sock_util.c b/chapters/app-interact/overview/guides/lock/utils/sock/sock_util.c new file mode 100644 index 0000000000..b426f20c29 --- /dev/null +++ b/chapters/app-interact/overview/guides/lock/utils/sock/sock_util.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Useful socket functions + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../utils.h" +#include "../log/log.h" +#include "sock_util.h" + +/* + * Connect to a TCP server identified by name (DNS name or dotted decimal + * string) and port. + */ + +int tcp_connect_to_server(const char *name, unsigned short port) +{ + struct hostent *hent; + struct sockaddr_in server_addr; + int s; + int rc; + + hent = gethostbyname(name); + DIE(hent == NULL, "gethostbyname"); + + s = socket(PF_INET, SOCK_STREAM, 0); + DIE(s < 0, "socket"); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, + sizeof(server_addr.sin_addr.s_addr)); + + rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); + DIE(rc < 0, "connect"); + + return s; +} + +int tcp_close_connection(int sockfd) +{ + int rc; + + rc = shutdown(sockfd, SHUT_RDWR); + DIE(rc < 0, "shutdown"); + + return close(sockfd); +} + +/* + * Create a server socket. + */ + +int tcp_create_listener(unsigned short port, int backlog) +{ + struct sockaddr_in address; + int listenfd; + int sock_opt; + int rc; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + + sock_opt = 1; + rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + &sock_opt, sizeof(int)); + DIE(rc < 0, "setsockopt"); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + + rc = bind(listenfd, (SSA *) &address, sizeof(address)); + DIE(rc < 0, "bind"); + + rc = listen(listenfd, backlog); + DIE(rc < 0, "listen"); + + return listenfd; +} + +/* + * Use getpeername(2) to extract remote peer address. Fill buffer with + * address format IP_address:port (e.g. 192.168.0.1:22). + */ + +int get_peer_address(int sockfd, char *buf, size_t len) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) + return -1; + + snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return 0; +} diff --git a/chapters/app-interact/overview/guides/lock/utils/sock/sock_util.h b/chapters/app-interact/overview/guides/lock/utils/sock/sock_util.h new file mode 100644 index 0000000000..906976dc94 --- /dev/null +++ b/chapters/app-interact/overview/guides/lock/utils/sock/sock_util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Useful socket macros and structures + */ + +#ifndef SOCK_UTIL_H_ +#define SOCK_UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* default backlog for listen(2) system call */ +#define DEFAULT_LISTEN_BACKLOG 5 + +/* "shortcut" for struct sockaddr structure */ +#define SSA struct sockaddr + + +int tcp_connect_to_server(const char *name, unsigned short port); +int tcp_close_connection(int s); +int tcp_create_listener(unsigned short port, int backlog); +int get_peer_address(int sockfd, char *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/chapters/app-interact/overview/guides/lock/utils/utils.h b/chapters/app-interact/overview/guides/lock/utils/utils.h new file mode 100644 index 0000000000..efdf6b59dd --- /dev/null +++ b/chapters/app-interact/overview/guides/lock/utils/utils.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef UTILS_H_ +#define UTILS_H_ 1 + +#include +#include +#include +#include +#include "log/log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR(assertion, call_description) \ + do { \ + if (assertion) \ + log_error("%s: %s", \ + call_description, strerror(errno)); \ + } while (0) + +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + log_fatal("%s: %s", \ + call_description, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_H_ */ diff --git a/content/chapters/app-interact/lecture/demo/shared-mem/.gitignore b/chapters/app-interact/overview/guides/shared-mem/.gitignore similarity index 100% rename from content/chapters/app-interact/lecture/demo/shared-mem/.gitignore rename to chapters/app-interact/overview/guides/shared-mem/.gitignore diff --git a/chapters/app-interact/overview/guides/shared-mem/Makefile b/chapters/app-interact/overview/guides/shared-mem/Makefile new file mode 100644 index 0000000000..973884b9b8 --- /dev/null +++ b/chapters/app-interact/overview/guides/shared-mem/Makefile @@ -0,0 +1,63 @@ +# List of executables to build +BINARIES = shmem_threads shmem_file_reader shmem_file_writer shmem_shm_reader shmem_shm_writer + +# Default library flags if not provided externally +LDLIBS ?= -lpthread -lrt + +# Include directories +INCLUDES_DIR := utils +LOGGER_DIR := $(INCLUDES_DIR)/log + +CPPFLAGS += -I$(INCLUDES_DIR) +CFLAGS += -g -Wall -Wextra +LDFLAGS += -z lazy + +# Shared object file +LOGGER_OBJ = $(LOGGER_DIR)/log.o + +# Build all executables by default +all: $(BINARIES) + +# Compile shared logger object +$(LOGGER_OBJ): $(LOGGER_DIR)/log.c $(LOGGER_DIR)/log.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Specialized compilation for file and shm variants +shmem_file_reader.o: shmem_reader.c utils/log/log.h utils/utils.h + $(CC) $(CPPFLAGS) -DSHMEM_FILE $(CFLAGS) -c -o $@ $< + +shmem_file_writer.o: shmem_writer.c utils/log/log.h utils/utils.h + $(CC) $(CPPFLAGS) -DSHMEM_FILE $(CFLAGS) -c -o $@ $< + +shmem_shm_reader.o: shmem_reader.c utils/log/log.h utils/utils.h + $(CC) $(CPPFLAGS) -DSHMEM_SHM $(CFLAGS) -c -o $@ $< + +shmem_shm_writer.o: shmem_writer.c utils/log/log.h utils/utils.h + $(CC) $(CPPFLAGS) -DSHMEM_SHM $(CFLAGS) -c -o $@ $< + +shmem_threads.o: shmem_threads.c utils/log/log.h utils/utils.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +# Link each executable separately (no utils.o) +shmem_threads: shmem_threads.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +shmem_file_reader: shmem_file_reader.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +shmem_file_writer: shmem_file_writer.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +shmem_shm_reader: shmem_shm_reader.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +shmem_shm_writer: shmem_shm_writer.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +clean: + -rm -f $(BINARIES) *.o $(LOGGER_OBJ) \ + shmem_file_writer.o shmem_file_reader.o \ + shmem_shm_writer.o shmem_shm_reader.o \ + shmem_threads.o + +.PHONY: all clean diff --git a/content/chapters/app-interact/lecture/demo/shared-mem/shmem_reader.c b/chapters/app-interact/overview/guides/shared-mem/shmem_reader.c similarity index 95% rename from content/chapters/app-interact/lecture/demo/shared-mem/shmem_reader.c rename to chapters/app-interact/overview/guides/shared-mem/shmem_reader.c index 515b272175..8fe2b8a715 100644 --- a/content/chapters/app-interact/lecture/demo/shared-mem/shmem_reader.c +++ b/chapters/app-interact/overview/guides/shared-mem/shmem_reader.c @@ -89,11 +89,11 @@ int main(void) sem_reader_read_2 = open_semaphore(SEM_READER_READ_2); sem_wait(sem_writer_write_1); - printf("value is %d\n", * (int *) (map->ptr)); + printf("value is %d\n", *(int *) (map->ptr)); sem_post(sem_reader_read_1); sem_wait(sem_writer_write_2); - printf("value is %d\n", * (int *) (map->ptr)); + printf("value is %d\n", *(int *) (map->ptr)); sem_post(sem_reader_read_2); close_shared_file_mapping(map); diff --git a/content/chapters/app-interact/lecture/demo/shared-mem/shmem_threads.c b/chapters/app-interact/overview/guides/shared-mem/shmem_threads.c similarity index 97% rename from content/chapters/app-interact/lecture/demo/shared-mem/shmem_threads.c rename to chapters/app-interact/overview/guides/shared-mem/shmem_threads.c index e0110bd6eb..c872fb7d42 100644 --- a/content/chapters/app-interact/lecture/demo/shared-mem/shmem_threads.c +++ b/chapters/app-interact/overview/guides/shared-mem/shmem_threads.c @@ -13,7 +13,7 @@ static sem_t writer_write_1; static sem_t writer_write_2; static sem_t reader_read_1; -static int shared_value = 0; +static int shared_value; #define VALUE_1 100 #define VALUE_2 200 diff --git a/content/chapters/app-interact/lecture/demo/shared-mem/shmem_writer.c b/chapters/app-interact/overview/guides/shared-mem/shmem_writer.c similarity index 97% rename from content/chapters/app-interact/lecture/demo/shared-mem/shmem_writer.c rename to chapters/app-interact/overview/guides/shared-mem/shmem_writer.c index 815d5eec42..ea5e25396c 100644 --- a/content/chapters/app-interact/lecture/demo/shared-mem/shmem_writer.c +++ b/chapters/app-interact/overview/guides/shared-mem/shmem_writer.c @@ -102,11 +102,11 @@ int main(void) sem_reader_read_1 = create_semaphore(SEM_READER_READ_1); sem_reader_read_2 = create_semaphore(SEM_READER_READ_2); - * (int *) (map->ptr) = VALUE_1; + *(int *) (map->ptr) = VALUE_1; sem_post(sem_writer_write_1); sem_wait(sem_reader_read_1); - * (int *) (map->ptr) = VALUE_2; + *(int *) (map->ptr) = VALUE_2; sem_post(sem_writer_write_2); sem_wait(sem_reader_read_2); diff --git a/chapters/app-interact/overview/guides/shared-mem/utils/log/CPPLINT.cfg b/chapters/app-interact/overview/guides/shared-mem/utils/log/CPPLINT.cfg new file mode 100644 index 0000000000..5aa9cb376c --- /dev/null +++ b/chapters/app-interact/overview/guides/shared-mem/utils/log/CPPLINT.cfg @@ -0,0 +1 @@ +exclude_files=log\.c diff --git a/chapters/app-interact/overview/guides/shared-mem/utils/log/log.c b/chapters/app-interact/overview/guides/shared-mem/utils/log/log.c new file mode 100644 index 0000000000..ac65f4ed33 --- /dev/null +++ b/chapters/app-interact/overview/guides/shared-mem/utils/log/log.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Copyright (c) 2020 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct +{ + void *udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char * const level_strings[] = { "TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL" }; + +#ifdef LOG_USE_COLOR +static const char * const level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m" }; +#endif + +static void +stdout_callback(log_Event *ev) +{ + char buf[16]; + + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, + "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, + level_colors[ev->level], + level_strings[ev->level], + ev->file, + ev->line); +#else + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +file_callback(log_Event *ev) +{ + char buf[64]; + + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +lock(void) +{ + if (L.lock) + L.lock(true, L.udata); +} + +static void +unlock(void) +{ + if (L.lock) + L.lock(false, L.udata); +} + +const char* +log_level_string(int level) +{ + return level_strings[level]; +} + +void +log_set_lock(log_LockFn fn, void *udata) +{ + L.lock = fn; + L.udata = udata; +} + +void +log_set_level(int level) +{ + L.level = level; +} + +void +log_set_quiet(bool enable) +{ + L.quiet = enable; +} + +int +log_add_callback(log_LogFn fn, void *udata, int level) +{ + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + +int +log_add_fp(FILE *fp, int level) +{ + return log_add_callback(file_callback, fp, level); +} + +static void +init_event(log_Event *ev, void *udata) +{ + if (!ev->time) { + time_t t = time(NULL); + + ev->time = localtime(&t); + } + ev->udata = udata; +} + +void +log_log(int level, const char *file, int line, const char *fmt, ...) +{ + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} diff --git a/chapters/app-interact/overview/guides/shared-mem/utils/log/log.h b/chapters/app-interact/overview/guides/shared-mem/utils/log/log.h new file mode 100644 index 0000000000..7acb55aab6 --- /dev/null +++ b/chapters/app-interact/overview/guides/shared-mem/utils/log/log.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * Copyright (c) 2020 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_H */ diff --git a/chapters/app-interact/overview/guides/shared-mem/utils/sock/sock_util.c b/chapters/app-interact/overview/guides/shared-mem/utils/sock/sock_util.c new file mode 100644 index 0000000000..b426f20c29 --- /dev/null +++ b/chapters/app-interact/overview/guides/shared-mem/utils/sock/sock_util.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Useful socket functions + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../utils.h" +#include "../log/log.h" +#include "sock_util.h" + +/* + * Connect to a TCP server identified by name (DNS name or dotted decimal + * string) and port. + */ + +int tcp_connect_to_server(const char *name, unsigned short port) +{ + struct hostent *hent; + struct sockaddr_in server_addr; + int s; + int rc; + + hent = gethostbyname(name); + DIE(hent == NULL, "gethostbyname"); + + s = socket(PF_INET, SOCK_STREAM, 0); + DIE(s < 0, "socket"); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, + sizeof(server_addr.sin_addr.s_addr)); + + rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); + DIE(rc < 0, "connect"); + + return s; +} + +int tcp_close_connection(int sockfd) +{ + int rc; + + rc = shutdown(sockfd, SHUT_RDWR); + DIE(rc < 0, "shutdown"); + + return close(sockfd); +} + +/* + * Create a server socket. + */ + +int tcp_create_listener(unsigned short port, int backlog) +{ + struct sockaddr_in address; + int listenfd; + int sock_opt; + int rc; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + + sock_opt = 1; + rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + &sock_opt, sizeof(int)); + DIE(rc < 0, "setsockopt"); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + + rc = bind(listenfd, (SSA *) &address, sizeof(address)); + DIE(rc < 0, "bind"); + + rc = listen(listenfd, backlog); + DIE(rc < 0, "listen"); + + return listenfd; +} + +/* + * Use getpeername(2) to extract remote peer address. Fill buffer with + * address format IP_address:port (e.g. 192.168.0.1:22). + */ + +int get_peer_address(int sockfd, char *buf, size_t len) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) + return -1; + + snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return 0; +} diff --git a/chapters/app-interact/overview/guides/shared-mem/utils/sock/sock_util.h b/chapters/app-interact/overview/guides/shared-mem/utils/sock/sock_util.h new file mode 100644 index 0000000000..906976dc94 --- /dev/null +++ b/chapters/app-interact/overview/guides/shared-mem/utils/sock/sock_util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Useful socket macros and structures + */ + +#ifndef SOCK_UTIL_H_ +#define SOCK_UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* default backlog for listen(2) system call */ +#define DEFAULT_LISTEN_BACKLOG 5 + +/* "shortcut" for struct sockaddr structure */ +#define SSA struct sockaddr + + +int tcp_connect_to_server(const char *name, unsigned short port); +int tcp_close_connection(int s); +int tcp_create_listener(unsigned short port, int backlog); +int get_peer_address(int sockfd, char *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/chapters/app-interact/overview/guides/shared-mem/utils/utils.h b/chapters/app-interact/overview/guides/shared-mem/utils/utils.h new file mode 100644 index 0000000000..efdf6b59dd --- /dev/null +++ b/chapters/app-interact/overview/guides/shared-mem/utils/utils.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef UTILS_H_ +#define UTILS_H_ 1 + +#include +#include +#include +#include +#include "log/log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR(assertion, call_description) \ + do { \ + if (assertion) \ + log_error("%s: %s", \ + call_description, strerror(errno)); \ + } while (0) + +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + log_fatal("%s: %s", \ + call_description, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_H_ */ diff --git a/content/chapters/app-interact/lecture/demo/sync/.gitignore b/chapters/app-interact/overview/guides/sync/.gitignore similarity index 100% rename from content/chapters/app-interact/lecture/demo/sync/.gitignore rename to chapters/app-interact/overview/guides/sync/.gitignore diff --git a/chapters/app-interact/overview/guides/sync/Makefile b/chapters/app-interact/overview/guides/sync/Makefile new file mode 100644 index 0000000000..a2f295e200 --- /dev/null +++ b/chapters/app-interact/overview/guides/sync/Makefile @@ -0,0 +1,48 @@ +# List of executables to build +BINARIES = thread_sem thread_cond proc_sem_first proc_sem_second proc_sig_first proc_sig_second + +# Default library flags if not provided externally +LDLIBS ?= -lpthread + +CC = gcc +CFLAGS += -g -Wall -Wextra +LDFLAGS += -z lazy +CPPFLAGS += + +INCLUDES_DIR = utils +LOGGER_DIR = $(INCLUDES_DIR)/log +LOGGER_OBJ = $(LOGGER_DIR)/log.o + +all: $(BINARIES) + +# Compile log object +$(LOGGER_OBJ): $(LOGGER_DIR)/log.c $(LOGGER_DIR)/log.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Generic rule for .o files +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Link each executable with the logger object +thread_sem: thread_sem.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +thread_cond: thread_cond.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +proc_sem_first: proc_sem_first.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +proc_sem_second: proc_sem_second.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +proc_sig_first: proc_sig_first.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +proc_sig_second: proc_sig_second.o $(LOGGER_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +clean: + rm -f $(BINARIES) *.o $(LOGGER_OBJ) + +.PHONY: all clean diff --git a/content/chapters/app-interact/lecture/demo/sync/proc_sem_first.c b/chapters/app-interact/overview/guides/sync/proc_sem_first.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/sync/proc_sem_first.c rename to chapters/app-interact/overview/guides/sync/proc_sem_first.c diff --git a/content/chapters/app-interact/lecture/demo/sync/proc_sem_second.c b/chapters/app-interact/overview/guides/sync/proc_sem_second.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/sync/proc_sem_second.c rename to chapters/app-interact/overview/guides/sync/proc_sem_second.c diff --git a/content/chapters/app-interact/lecture/demo/sync/proc_sig_first.c b/chapters/app-interact/overview/guides/sync/proc_sig_first.c similarity index 99% rename from content/chapters/app-interact/lecture/demo/sync/proc_sig_first.c rename to chapters/app-interact/overview/guides/sync/proc_sig_first.c index 6ccd2c9736..2ccb722946 100644 --- a/content/chapters/app-interact/lecture/demo/sync/proc_sig_first.c +++ b/chapters/app-interact/overview/guides/sync/proc_sig_first.c @@ -62,6 +62,7 @@ static void wait_for_signal(int signal) while (1) { int ret_signal; + sigpending(&pending_set); if (sigismember(&pending_set, signal) == 0) { sigwait(&wait_set, &ret_signal); diff --git a/content/chapters/app-interact/lecture/demo/sync/proc_sig_second.c b/chapters/app-interact/overview/guides/sync/proc_sig_second.c similarity index 99% rename from content/chapters/app-interact/lecture/demo/sync/proc_sig_second.c rename to chapters/app-interact/overview/guides/sync/proc_sig_second.c index 0f76712684..ad59610856 100644 --- a/content/chapters/app-interact/lecture/demo/sync/proc_sig_second.c +++ b/chapters/app-interact/overview/guides/sync/proc_sig_second.c @@ -62,6 +62,7 @@ static void wait_for_signal(int signal) while (1) { int ret_signal; + sigpending(&pending_set); if (sigismember(&pending_set, signal) == 0) { sigwait(&wait_set, &ret_signal); diff --git a/content/chapters/app-interact/lecture/demo/sync/thread_cond.c b/chapters/app-interact/overview/guides/sync/thread_cond.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/sync/thread_cond.c rename to chapters/app-interact/overview/guides/sync/thread_cond.c diff --git a/content/chapters/app-interact/lecture/demo/sync/thread_sem.c b/chapters/app-interact/overview/guides/sync/thread_sem.c similarity index 100% rename from content/chapters/app-interact/lecture/demo/sync/thread_sem.c rename to chapters/app-interact/overview/guides/sync/thread_sem.c diff --git a/chapters/app-interact/overview/guides/sync/utils/log/CPPLINT.cfg b/chapters/app-interact/overview/guides/sync/utils/log/CPPLINT.cfg new file mode 100644 index 0000000000..5aa9cb376c --- /dev/null +++ b/chapters/app-interact/overview/guides/sync/utils/log/CPPLINT.cfg @@ -0,0 +1 @@ +exclude_files=log\.c diff --git a/chapters/app-interact/overview/guides/sync/utils/log/log.c b/chapters/app-interact/overview/guides/sync/utils/log/log.c new file mode 100644 index 0000000000..ac65f4ed33 --- /dev/null +++ b/chapters/app-interact/overview/guides/sync/utils/log/log.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Copyright (c) 2020 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct +{ + void *udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char * const level_strings[] = { "TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL" }; + +#ifdef LOG_USE_COLOR +static const char * const level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m" }; +#endif + +static void +stdout_callback(log_Event *ev) +{ + char buf[16]; + + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, + "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, + level_colors[ev->level], + level_strings[ev->level], + ev->file, + ev->line); +#else + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +file_callback(log_Event *ev) +{ + char buf[64]; + + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +lock(void) +{ + if (L.lock) + L.lock(true, L.udata); +} + +static void +unlock(void) +{ + if (L.lock) + L.lock(false, L.udata); +} + +const char* +log_level_string(int level) +{ + return level_strings[level]; +} + +void +log_set_lock(log_LockFn fn, void *udata) +{ + L.lock = fn; + L.udata = udata; +} + +void +log_set_level(int level) +{ + L.level = level; +} + +void +log_set_quiet(bool enable) +{ + L.quiet = enable; +} + +int +log_add_callback(log_LogFn fn, void *udata, int level) +{ + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + +int +log_add_fp(FILE *fp, int level) +{ + return log_add_callback(file_callback, fp, level); +} + +static void +init_event(log_Event *ev, void *udata) +{ + if (!ev->time) { + time_t t = time(NULL); + + ev->time = localtime(&t); + } + ev->udata = udata; +} + +void +log_log(int level, const char *file, int line, const char *fmt, ...) +{ + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} diff --git a/chapters/app-interact/overview/guides/sync/utils/log/log.h b/chapters/app-interact/overview/guides/sync/utils/log/log.h new file mode 100644 index 0000000000..7acb55aab6 --- /dev/null +++ b/chapters/app-interact/overview/guides/sync/utils/log/log.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * Copyright (c) 2020 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_H */ diff --git a/chapters/app-interact/overview/guides/sync/utils/sock/sock_util.c b/chapters/app-interact/overview/guides/sync/utils/sock/sock_util.c new file mode 100644 index 0000000000..b426f20c29 --- /dev/null +++ b/chapters/app-interact/overview/guides/sync/utils/sock/sock_util.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Useful socket functions + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../utils.h" +#include "../log/log.h" +#include "sock_util.h" + +/* + * Connect to a TCP server identified by name (DNS name or dotted decimal + * string) and port. + */ + +int tcp_connect_to_server(const char *name, unsigned short port) +{ + struct hostent *hent; + struct sockaddr_in server_addr; + int s; + int rc; + + hent = gethostbyname(name); + DIE(hent == NULL, "gethostbyname"); + + s = socket(PF_INET, SOCK_STREAM, 0); + DIE(s < 0, "socket"); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, + sizeof(server_addr.sin_addr.s_addr)); + + rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); + DIE(rc < 0, "connect"); + + return s; +} + +int tcp_close_connection(int sockfd) +{ + int rc; + + rc = shutdown(sockfd, SHUT_RDWR); + DIE(rc < 0, "shutdown"); + + return close(sockfd); +} + +/* + * Create a server socket. + */ + +int tcp_create_listener(unsigned short port, int backlog) +{ + struct sockaddr_in address; + int listenfd; + int sock_opt; + int rc; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + + sock_opt = 1; + rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + &sock_opt, sizeof(int)); + DIE(rc < 0, "setsockopt"); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + + rc = bind(listenfd, (SSA *) &address, sizeof(address)); + DIE(rc < 0, "bind"); + + rc = listen(listenfd, backlog); + DIE(rc < 0, "listen"); + + return listenfd; +} + +/* + * Use getpeername(2) to extract remote peer address. Fill buffer with + * address format IP_address:port (e.g. 192.168.0.1:22). + */ + +int get_peer_address(int sockfd, char *buf, size_t len) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) + return -1; + + snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return 0; +} diff --git a/chapters/app-interact/overview/guides/sync/utils/sock/sock_util.h b/chapters/app-interact/overview/guides/sync/utils/sock/sock_util.h new file mode 100644 index 0000000000..906976dc94 --- /dev/null +++ b/chapters/app-interact/overview/guides/sync/utils/sock/sock_util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Useful socket macros and structures + */ + +#ifndef SOCK_UTIL_H_ +#define SOCK_UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* default backlog for listen(2) system call */ +#define DEFAULT_LISTEN_BACKLOG 5 + +/* "shortcut" for struct sockaddr structure */ +#define SSA struct sockaddr + + +int tcp_connect_to_server(const char *name, unsigned short port); +int tcp_close_connection(int s); +int tcp_create_listener(unsigned short port, int backlog); +int get_peer_address(int sockfd, char *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/chapters/app-interact/overview/guides/sync/utils/utils.h b/chapters/app-interact/overview/guides/sync/utils/utils.h new file mode 100644 index 0000000000..efdf6b59dd --- /dev/null +++ b/chapters/app-interact/overview/guides/sync/utils/utils.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef UTILS_H_ +#define UTILS_H_ 1 + +#include +#include +#include +#include +#include "log/log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR(assertion, call_description) \ + do { \ + if (assertion) \ + log_error("%s: %s", \ + call_description, strerror(errno)); \ + } while (0) + +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + log_fatal("%s: %s", \ + call_description, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_H_ */ diff --git a/content/chapters/app-interact/lecture/media/app-components.svg b/chapters/app-interact/overview/media/app-components.svg similarity index 100% rename from content/chapters/app-interact/lecture/media/app-components.svg rename to chapters/app-interact/overview/media/app-components.svg diff --git a/content/chapters/app-interact/lecture/media/app-interaction-interface.svg b/chapters/app-interact/overview/media/app-interaction-interface.svg similarity index 100% rename from content/chapters/app-interact/lecture/media/app-interaction-interface.svg rename to chapters/app-interact/overview/media/app-interaction-interface.svg diff --git a/content/chapters/app-interact/lecture/media/communication-channel.svg b/chapters/app-interact/overview/media/communication-channel.svg similarity index 100% rename from content/chapters/app-interact/lecture/media/communication-channel.svg rename to chapters/app-interact/overview/media/communication-channel.svg diff --git a/content/chapters/app-interact/lecture/media/gitlab-architecture.png b/chapters/app-interact/overview/media/gitlab-architecture.png similarity index 100% rename from content/chapters/app-interact/lecture/media/gitlab-architecture.png rename to chapters/app-interact/overview/media/gitlab-architecture.png diff --git a/content/chapters/app-interact/lecture/media/interruption.drawio b/chapters/app-interact/overview/media/interruption.drawio similarity index 100% rename from content/chapters/app-interact/lecture/media/interruption.drawio rename to chapters/app-interact/overview/media/interruption.drawio diff --git a/content/chapters/app-interact/lecture/media/interruption/interruption-0.svg b/chapters/app-interact/overview/media/interruption/interruption-0.svg similarity index 99% rename from content/chapters/app-interact/lecture/media/interruption/interruption-0.svg rename to chapters/app-interact/overview/media/interruption/interruption-0.svg index 17f919cf12..13fe3f12af 100644 --- a/content/chapters/app-interact/lecture/media/interruption/interruption-0.svg +++ b/chapters/app-interact/overview/media/interruption/interruption-0.svg @@ -1,5 +1,5 @@ - - - - - - - - - ([source](https://docs.gitlab.com/ee/development/architecture.html)) + ([source](https://docs.gitlab.com/ee/development/architecture.html)) ---- @@ -103,4 +103,4 @@ ### Kubernetes -![Kubernetes Architecture](./media/kubernetes-architecture.png) ([source](https://medium.com/devops-mojo/kubernetes-architecture-overview-introduction-to-k8s-architecture-and-understanding-k8s-cluster-components-90e11eb34ccd)) +![Kubernetes Architecture](overview/media/kubernetes-architecture.png) ([source](https://medium.com/devops-mojo/kubernetes-architecture-overview-introduction-to-k8s-architecture-and-understanding-k8s-cluster-components-90e11eb34ccd)) diff --git a/content/chapters/app-interact/lecture/slides/defs.md b/chapters/app-interact/overview/slides/defs.md similarity index 92% rename from content/chapters/app-interact/lecture/slides/defs.md rename to chapters/app-interact/overview/slides/defs.md index 97604459c3..be8577c018 100644 --- a/content/chapters/app-interact/lecture/slides/defs.md +++ b/chapters/app-interact/overview/slides/defs.md @@ -36,9 +36,9 @@ int main(void) ### Exhibit 1 - Creating Interaction -- `demo/comm-channels/reader.c` -- `demo/comm-channels/writer.c` -- `demo/comm-channels/send_receive_pipe.c` +- `chapters/app-interact/overview/guides/comm-channels/reader.c` +- `chapters/app-interact/overview/guides/comm-channels/writer.c` +- `chapters/app-interact/overview/guides/comm-channels/send_receive_pipe.c` --- @@ -134,7 +134,7 @@ int main(void) ### Exhibit 4 - WhatsApp Application -![App1](./media/whatsApp.svg) +![App1](overview/media/whatsApp.svg) ---- diff --git a/content/chapters/app-interact/lecture/slides/os-roles.md b/chapters/app-interact/overview/slides/os-roles.md similarity index 91% rename from content/chapters/app-interact/lecture/slides/os-roles.md rename to chapters/app-interact/overview/slides/os-roles.md index e7ea455903..b9aa04c7c2 100644 --- a/content/chapters/app-interact/lecture/slides/os-roles.md +++ b/chapters/app-interact/overview/slides/os-roles.md @@ -41,4 +41,4 @@ ## OS - The Lawmaker -![Multiple Apps Interacting through the OS](./media/multiple-apps-interaction.svg) +![Multiple Apps Interacting through the OS](overview/media/multiple-apps-interaction.svg) diff --git a/content/chapters/app-interact/lecture/slides/why.md b/chapters/app-interact/overview/slides/why.md similarity index 100% rename from content/chapters/app-interact/lecture/slides/why.md rename to chapters/app-interact/overview/slides/why.md diff --git a/chapters/app-interact/password-cracker/drills/tasks/password-cracker/README.md b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/README.md new file mode 100644 index 0000000000..430561ffed --- /dev/null +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/README.md @@ -0,0 +1,14 @@ +# Password cracker + +Navigate to `chapters/app-interact/password-cracker/drills/tasks/password-cracker/support`. +Creating 26 processes is not very realistic, since it's unlikely that a usual machine has that many cores. + +Modify the program so that it only creates 4 workers. +Each worker will receive 2 characters instead of one, defining an interval to search. +For example, the first worker will receive `a` and `f`, meaning it will brute-force passwords starting with `a`, `b`, `c`, `d`, `e`, or `f`, the second `g` - `l`, and so on. + +Check that the `worker()` function is indeed called from different worker processes. +One simple way to do this is to print out the current process ID at the beginning of the function. +To get the current process ID, use the `getpid()` function from the `os` module. + +If you're having difficulties solving this exercise, go through [this](../../../reading/password-cracker.md) reading material. diff --git a/content/chapters/app-interact/lab/solution/password-cracker/Makefile b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/solution/Makefile similarity index 100% rename from content/chapters/app-interact/lab/solution/password-cracker/Makefile rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/solution/Makefile diff --git a/content/chapters/app-interact/lab/solution/password-cracker/password-cracker-multiprocess.c b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/solution/password-cracker-multiprocess.c similarity index 94% rename from content/chapters/app-interact/lab/solution/password-cracker/password-cracker-multiprocess.c rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/solution/password-cracker-multiprocess.c index 505abb913e..86dee3a88d 100644 --- a/content/chapters/app-interact/lab/solution/password-cracker/password-cracker-multiprocess.c +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/solution/password-cracker-multiprocess.c @@ -77,18 +77,17 @@ void worker(int idx, int request_pipe_fd, int result_pipe_fd) } } - if ((password[k] == 'z') || (k == PASSWORD_LEN)) { + if ((password[k] == 'z') || (k == PASSWORD_LEN)) k--; - } } } if (found) { - /* - * Found the password. Send the password length and the password - * through the pipe. - */ - v = PASSWORD_LEN; + /* + * Found the password. Send the password length and the password + * through the pipe. + */ + v = PASSWORD_LEN; ret = write(result_pipe_fd, &v, sizeof(v)); DIE(ret < 0, "write"); @@ -99,7 +98,7 @@ void worker(int idx, int request_pipe_fd, int result_pipe_fd) /* * Didn't find the password. Send the value 0 through the pipe. */ - v = 0; + v = 0; ret = write(result_pipe_fd, &v, sizeof(v)); DIE(ret < 0, "write"); @@ -183,7 +182,7 @@ int main(void) first_char_end = char_list[(i+1) * chunk_size - 1]; if (i == NUM_WORKERS - 1) - first_char_end = char_list[char_list_len - 1]; + first_char_end = char_list[char_list_len - 1]; ret = write(request_pipefd[i], &first_char_begin, sizeof(char)); DIE(ret < 0, "write"); diff --git a/content/chapters/app-interact/lab/solution/password-cracker/python/password-cracker-multiprocess-2.py b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/solution/python/password-cracker-multiprocess-2.py similarity index 100% rename from content/chapters/app-interact/lab/solution/password-cracker/python/password-cracker-multiprocess-2.py rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/solution/python/password-cracker-multiprocess-2.py diff --git a/content/chapters/app-interact/lab/support/password-cracker/Makefile b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/Makefile similarity index 100% rename from content/chapters/app-interact/lab/support/password-cracker/Makefile rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/Makefile diff --git a/content/chapters/app-interact/lab/support/password-cracker/password-cracker-multiprocess.c b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/password-cracker-multiprocess.c similarity index 98% rename from content/chapters/app-interact/lab/support/password-cracker/password-cracker-multiprocess.c rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/password-cracker-multiprocess.c index 0c6b11a223..827db5e9d7 100644 --- a/content/chapters/app-interact/lab/support/password-cracker/password-cracker-multiprocess.c +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/password-cracker-multiprocess.c @@ -76,9 +76,8 @@ void worker(int idx, int request_pipe_fd, int result_pipe_fd) } } - if ((password[k] == 'z') || (k == PASSWORD_LEN)) { + if ((password[k] == 'z') || (k == PASSWORD_LEN)) k--; - } } if (found) { diff --git a/content/chapters/app-interact/lab/support/password-cracker/password-cracker-multithread.c b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/password-cracker-multithread.c similarity index 97% rename from content/chapters/app-interact/lab/support/password-cracker/password-cracker-multithread.c rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/password-cracker-multithread.c index 9da5eac05c..99ecc7551c 100644 --- a/content/chapters/app-interact/lab/support/password-cracker/password-cracker-multithread.c +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/password-cracker-multithread.c @@ -69,9 +69,8 @@ void *worker(void *arg) } } - if ((password[k] == 'z') || (k == PASSWORD_LEN)) { + if ((password[k] == 'z') || (k == PASSWORD_LEN)) k--; - } } if (found) { diff --git a/content/chapters/app-interact/lab/support/password-cracker/python/password-cracker-multiprocess-1.py b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/python/password-cracker-multiprocess-1.py similarity index 100% rename from content/chapters/app-interact/lab/support/password-cracker/python/password-cracker-multiprocess-1.py rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/python/password-cracker-multiprocess-1.py diff --git a/content/chapters/app-interact/lab/support/password-cracker/python/password-cracker-multiprocess-2.py b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/python/password-cracker-multiprocess-2.py similarity index 100% rename from content/chapters/app-interact/lab/support/password-cracker/python/password-cracker-multiprocess-2.py rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/python/password-cracker-multiprocess-2.py diff --git a/content/chapters/app-interact/lab/support/password-cracker/python/password-cracker-multithread.py b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/python/password-cracker-multithread.py similarity index 100% rename from content/chapters/app-interact/lab/support/password-cracker/python/password-cracker-multithread.py rename to chapters/app-interact/password-cracker/drills/tasks/password-cracker/support/python/password-cracker-multithread.py diff --git a/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/CPPLINT.cfg b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/CPPLINT.cfg new file mode 100644 index 0000000000..5aa9cb376c --- /dev/null +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/CPPLINT.cfg @@ -0,0 +1 @@ +exclude_files=log\.c diff --git a/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/log.c b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/log.c new file mode 100644 index 0000000000..ac65f4ed33 --- /dev/null +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/log.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Copyright (c) 2020 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct +{ + void *udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char * const level_strings[] = { "TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL" }; + +#ifdef LOG_USE_COLOR +static const char * const level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m" }; +#endif + +static void +stdout_callback(log_Event *ev) +{ + char buf[16]; + + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, + "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, + level_colors[ev->level], + level_strings[ev->level], + ev->file, + ev->line); +#else + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +file_callback(log_Event *ev) +{ + char buf[64]; + + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +lock(void) +{ + if (L.lock) + L.lock(true, L.udata); +} + +static void +unlock(void) +{ + if (L.lock) + L.lock(false, L.udata); +} + +const char* +log_level_string(int level) +{ + return level_strings[level]; +} + +void +log_set_lock(log_LockFn fn, void *udata) +{ + L.lock = fn; + L.udata = udata; +} + +void +log_set_level(int level) +{ + L.level = level; +} + +void +log_set_quiet(bool enable) +{ + L.quiet = enable; +} + +int +log_add_callback(log_LogFn fn, void *udata, int level) +{ + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + +int +log_add_fp(FILE *fp, int level) +{ + return log_add_callback(file_callback, fp, level); +} + +static void +init_event(log_Event *ev, void *udata) +{ + if (!ev->time) { + time_t t = time(NULL); + + ev->time = localtime(&t); + } + ev->udata = udata; +} + +void +log_log(int level, const char *file, int line, const char *fmt, ...) +{ + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} diff --git a/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/log.h b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/log.h new file mode 100644 index 0000000000..7acb55aab6 --- /dev/null +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/log/log.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * Copyright (c) 2020 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_H */ diff --git a/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/utils.h b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/utils.h new file mode 100644 index 0000000000..efdf6b59dd --- /dev/null +++ b/chapters/app-interact/password-cracker/drills/tasks/password-cracker/utils/utils.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef UTILS_H_ +#define UTILS_H_ 1 + +#include +#include +#include +#include +#include "log/log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR(assertion, call_description) \ + do { \ + if (assertion) \ + log_error("%s: %s", \ + call_description, strerror(errno)); \ + } while (0) + +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + log_fatal("%s: %s", \ + call_description, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_H_ */ diff --git a/content/chapters/app-interact/lab/content/password-cracker.md b/chapters/app-interact/password-cracker/reading/password-cracker.md similarity index 75% rename from content/chapters/app-interact/lab/content/password-cracker.md rename to chapters/app-interact/password-cracker/reading/password-cracker.md index ab104117ee..2d9e3a2fff 100644 --- a/content/chapters/app-interact/lab/content/password-cracker.md +++ b/chapters/app-interact/password-cracker/reading/password-cracker.md @@ -10,7 +10,7 @@ Instead of one process checking all combinations, we'll split the work among mul ## Multiprocess Version -The code for this version is in `support/password-cracker/password-cracker-multiprocess.c`. +The code for this version is in `chapters/app-interact/password-cracker/support/password-cracker-multiprocess.c`. The idea is the following: we create 26 worker processes, where each process will consider passwords that start with one particular letter (the first process will brute-force passwords starting with `a`, the second with `b`, and so on). @@ -49,17 +49,9 @@ student@os:~/.../support/password-cracker$ ./password-cracker-multiprocess worker 7 found haxx ``` -### Practice - -Creating 26 processes is not very realistic, since it's unlikely that a usual machine has that many cores. - -Modify the program so that it only creates 4 workers. -Each worker will receive 2 characters instead of one, defining an interval to search. -For example, the first worker will receive `a` and `f`, meaning it will brute-force passwords starting with `a`, `b`, `c`, `d`, `e`, or `f`, the second `g` - `l`, and so on. - ## Multithreaded Version -Check out the code in `support/password-cracker/password-cracker-multithread.c`. +Check out the code in `chapters/app-interact/password-cracker/support/password-cracker-multithread.c`. The core idea of the program is the same, but now we're using threads instead of processes. @@ -67,13 +59,13 @@ This makes the communication easier: we'll use the thread function argument to s As for the result, each thread will return it as the return value of the thread function. ```console -student@os:~/.../support/password-cracker$ ./password-cracker-multithread +student@os:~/.../support$ ./password-cracker-multithread worker 7 found haxx ``` ## Multiprocess Version in Python (1) -Code in `support/password-cracker/python/password-cracker-multiprocess-1.py`. +Code in `chapters/app-interact/password-cracker/support/python/password-cracker-multiprocess-1.py`. This is the Python equivalent of the previous multiprocess version. The program structure is the same, but Python has a few nice features that make our life easier: @@ -86,13 +78,13 @@ So we don't need to create 2 pipes for each direction. * we don't have to write the code that generates all the password combinations, `itertools.product` will do it for us ```console -student@os:~/.../support/password-cracker$ python3 python/password-cracker-multiprocess-1.py +student@os:~/.../support$ python3 python/password-cracker-multiprocess-1.py worker 7 found haxx ``` ## Multiprocess Version in Python (2) -Code in `support/password-cracker/python/password-cracker-multiprocess-2.py`. +Code in `chapters/app-interact/password-cracker/support/python/password-cracker-multiprocess-2.py`. In this case, the code looks different than in the previous examples. Now we are taking advantage of some Python constructs, namely `process pools`, which are a collection of worker processes. @@ -104,24 +96,18 @@ At first glance, it might look like the usual `map` function, but with the key d In other words, the work is distributed to the worker processes from the pool, and all the communication that we had to handle in the previous examples is done behind the scenes, greatly simplifying the code. ```console -student@os:~/.../support/password-cracker$ python3 python/password-cracker-multiprocess-2.py +student@os:~/.../support$ python3 python/password-cracker-multiprocess-2.py worker 7 found haxx ``` -### Practice - -Check that the `worker` function is indeed called from different worker processes. -One simple way to do this is to print out the current process ID at the beginning of the function. -To get the current process ID, use the `getpid` function from the `os` module. - ## Multithreaded Version in Python -Code in `support/password-cracker/python/password-cracker-multithread.py`. +Code in `chapters/app-interact/password-cracker/support/python/password-cracker-multithread.py`. The Python equivalent of the previous multithreaded version. ```console -student@os:~/.../support/password-cracker$ python3 python/password-cracker-multithread.py +student@os:~/.../support$ python3 python/password-cracker-multithread.py worker 7 found haxx ``` diff --git a/content/chapters/app-interact/lecture/slides.mdpp b/chapters/app-interact/slides.mdpp similarity index 68% rename from content/chapters/app-interact/lecture/slides.mdpp rename to chapters/app-interact/slides.mdpp index 1ab4a4c5ea..6067db1c3e 100644 --- a/content/chapters/app-interact/lecture/slides.mdpp +++ b/chapters/app-interact/slides.mdpp @@ -16,14 +16,14 @@ revealOptions: 1. [Roles of the Operating System](./slides/os-roles.md) 1. [Programming Interface](./slides/api.md) -!INCLUDE "slides/why.md" +!INCLUDE "overview/slides/why.md" -!INCLUDE "slides/defs.md" +!INCLUDE "overview/slides/defs.md" -!INCLUDE "slides/classification.md" +!INCLUDE "overview/slides/classification.md" -!INCLUDE "slides/channels.md" +!INCLUDE "overview/slides/channels.md" -!INCLUDE "slides/os-roles.md" +!INCLUDE "overview/slides/os-roles.md" -!INCLUDE "slides/api.md" +!INCLUDE "overview/slides/api.md" diff --git a/content/chapters/app-interact/lab/quiz/time-server-interop.md b/chapters/app-interact/time-server/drills/questions/time-server-interop.md similarity index 100% rename from content/chapters/app-interact/lab/quiz/time-server-interop.md rename to chapters/app-interact/time-server/drills/questions/time-server-interop.md diff --git a/content/chapters/app-interact/lab/quiz/time-server.md b/chapters/app-interact/time-server/drills/questions/time-server.md similarity index 100% rename from content/chapters/app-interact/lab/quiz/time-server.md rename to chapters/app-interact/time-server/drills/questions/time-server.md diff --git a/chapters/app-interact/time-server/drills/tasks/time-server/README.md b/chapters/app-interact/time-server/drills/tasks/time-server/README.md new file mode 100644 index 0000000000..0acd8c2b08 --- /dev/null +++ b/chapters/app-interact/time-server/drills/tasks/time-server/README.md @@ -0,0 +1,17 @@ +# Time server + +Navigate to `chapters/app-interact/time-server/drills/tasks/time-server/support`. +Try to figure out the protocol used by the server and the client. +You can do this by reading the source code, corroborated with information obtained at runtime. + +Run the server again (the version in C), but instead of running the client, let's run `netcat` and pipe the output to `hexdump`: + +```console +nc -d 127.0.0.1 2000 | hexdump -C +``` + +[Quiz](../drills/questions/time-server.md) + +[Quiz](../drills/questions/time-server-interop.md) + +If you're having difficulties solving this exercise, go through [this](../../../reading/time-server.md) reading material. diff --git a/content/chapters/app-interact/lab/support/time-server/Makefile b/chapters/app-interact/time-server/drills/tasks/time-server/support/Makefile similarity index 100% rename from content/chapters/app-interact/lab/support/time-server/Makefile rename to chapters/app-interact/time-server/drills/tasks/time-server/support/Makefile diff --git a/content/chapters/app-interact/lab/support/time-server/client.c b/chapters/app-interact/time-server/drills/tasks/time-server/support/client.c similarity index 93% rename from content/chapters/app-interact/lab/support/time-server/client.c rename to chapters/app-interact/time-server/drills/tasks/time-server/support/client.c index 056796a9a4..8a75a0a079 100644 --- a/content/chapters/app-interact/lab/support/time-server/client.c +++ b/chapters/app-interact/time-server/drills/tasks/time-server/support/client.c @@ -91,11 +91,10 @@ int main(int argc, char *argv[]) DIE(ret < 0, "recv"); DIE(ret != size, "EOF"); - if (size == 4) { - current_time = ntohl(val); - } else if (size == 8) { - current_time = be64toh(val); - } + if (size == 4) + current_time = ntohl(val); + else if (size == 8) + current_time = be64toh(val); printf("The time is %s", ctime(¤t_time)); diff --git a/content/chapters/app-interact/lab/support/time-server/python/client.py b/chapters/app-interact/time-server/drills/tasks/time-server/support/python/client.py similarity index 100% rename from content/chapters/app-interact/lab/support/time-server/python/client.py rename to chapters/app-interact/time-server/drills/tasks/time-server/support/python/client.py diff --git a/content/chapters/app-interact/lab/support/time-server/python/server.py b/chapters/app-interact/time-server/drills/tasks/time-server/support/python/server.py similarity index 100% rename from content/chapters/app-interact/lab/support/time-server/python/server.py rename to chapters/app-interact/time-server/drills/tasks/time-server/support/python/server.py diff --git a/content/chapters/app-interact/lab/support/time-server/server.c b/chapters/app-interact/time-server/drills/tasks/time-server/support/server.c similarity index 100% rename from content/chapters/app-interact/lab/support/time-server/server.c rename to chapters/app-interact/time-server/drills/tasks/time-server/support/server.c diff --git a/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/CPPLINT.cfg b/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/CPPLINT.cfg new file mode 100644 index 0000000000..5aa9cb376c --- /dev/null +++ b/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/CPPLINT.cfg @@ -0,0 +1 @@ +exclude_files=log\.c diff --git a/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/log.c b/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/log.c new file mode 100644 index 0000000000..ac65f4ed33 --- /dev/null +++ b/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/log.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Copyright (c) 2020 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct +{ + void *udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char * const level_strings[] = { "TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL" }; + +#ifdef LOG_USE_COLOR +static const char * const level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m" }; +#endif + +static void +stdout_callback(log_Event *ev) +{ + char buf[16]; + + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, + "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, + level_colors[ev->level], + level_strings[ev->level], + ev->file, + ev->line); +#else + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +file_callback(log_Event *ev) +{ + char buf[64]; + + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf(ev->udata, + "%s %-5s %s:%d: ", + buf, + level_strings[ev->level], + ev->file, + ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void +lock(void) +{ + if (L.lock) + L.lock(true, L.udata); +} + +static void +unlock(void) +{ + if (L.lock) + L.lock(false, L.udata); +} + +const char* +log_level_string(int level) +{ + return level_strings[level]; +} + +void +log_set_lock(log_LockFn fn, void *udata) +{ + L.lock = fn; + L.udata = udata; +} + +void +log_set_level(int level) +{ + L.level = level; +} + +void +log_set_quiet(bool enable) +{ + L.quiet = enable; +} + +int +log_add_callback(log_LogFn fn, void *udata, int level) +{ + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + +int +log_add_fp(FILE *fp, int level) +{ + return log_add_callback(file_callback, fp, level); +} + +static void +init_event(log_Event *ev, void *udata) +{ + if (!ev->time) { + time_t t = time(NULL); + + ev->time = localtime(&t); + } + ev->udata = udata; +} + +void +log_log(int level, const char *file, int line, const char *fmt, ...) +{ + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} diff --git a/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/log.h b/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/log.h new file mode 100644 index 0000000000..7acb55aab6 --- /dev/null +++ b/chapters/app-interact/time-server/drills/tasks/time-server/utils/log/log.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * Copyright (c) 2020 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `log.c` for details. + */ + +/* Github link: https://github.com/rxi/log.c */ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_level(int level); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); + +void log_log(int level, const char *file, int line, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_H */ diff --git a/chapters/app-interact/time-server/drills/tasks/time-server/utils/utils.h b/chapters/app-interact/time-server/drills/tasks/time-server/utils/utils.h new file mode 100644 index 0000000000..efdf6b59dd --- /dev/null +++ b/chapters/app-interact/time-server/drills/tasks/time-server/utils/utils.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef UTILS_H_ +#define UTILS_H_ 1 + +#include +#include +#include +#include +#include "log/log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR(assertion, call_description) \ + do { \ + if (assertion) \ + log_error("%s: %s", \ + call_description, strerror(errno)); \ + } while (0) + +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + log_fatal("%s: %s", \ + call_description, strerror(errno)); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_H_ */ diff --git a/chapters/app-interact/time-server/reading/time-server.md b/chapters/app-interact/time-server/reading/time-server.md new file mode 100644 index 0000000000..f24e08f94b --- /dev/null +++ b/chapters/app-interact/time-server/reading/time-server.md @@ -0,0 +1,35 @@ +# Time Server + +Check out the code in `chapters/app-interact/time-server/support/server.c` and `chapters/app-interact/time-server/support/client.c`. + +This is a simple program consisting of a server and a client. +The server uses a tcp socket to wait for connections. +Once a client has connected, the server will send the current time to it. +The client will then print the received time to the console. + +Let's build and run this example: + +```console +student@os:~/.../support$ make +student@os:~/.../support$ ./server +``` + +Then, in another terminal: + +```console +student@os:~/.../support$ ./client 127.0.0.1 2000 +The time is Thu Sep 1 11:48:03 2022 +``` + +## Python Version + +In `chapters/app-interact/time-server/support/python` we have the equivalent python implementation for both the server and client: + +```console +student@os:~/.../support/python$ python3 server.py +``` + +```console +student@os:~/.../support/python$ python3 client.py 127.0.0.1 2000 +The time is Thu Sep 1 11:58:01 2022 +``` diff --git a/content/chapters/app-interact/lab/quiz/timer.md b/chapters/app-interact/x-window-system/drills/questions/timer.md similarity index 85% rename from content/chapters/app-interact/lab/quiz/timer.md rename to chapters/app-interact/x-window-system/drills/questions/timer.md index cddad57b25..b3ffed661e 100644 --- a/content/chapters/app-interact/lab/quiz/timer.md +++ b/chapters/app-interact/x-window-system/drills/questions/timer.md @@ -2,7 +2,7 @@ ## Question Text -What is the purpose of the timer used in the Oneko's implementantion +What is the purpose of the timer used in the Oneko's implementation ## Question Answers diff --git a/content/chapters/app-interact/lab/media/strace_xeyes.gif b/chapters/app-interact/x-window-system/media/strace_xeyes.gif similarity index 100% rename from content/chapters/app-interact/lab/media/strace_xeyes.gif rename to chapters/app-interact/x-window-system/media/strace_xeyes.gif diff --git a/content/chapters/app-interact/lab/media/strace_xeyes.mp4 b/chapters/app-interact/x-window-system/media/strace_xeyes.mp4 similarity index 100% rename from content/chapters/app-interact/lab/media/strace_xeyes.mp4 rename to chapters/app-interact/x-window-system/media/strace_xeyes.mp4 diff --git a/content/chapters/app-interact/lab/content/x-window-system.md b/chapters/app-interact/x-window-system/reading/x-window-system.md similarity index 71% rename from content/chapters/app-interact/lab/content/x-window-system.md rename to chapters/app-interact/x-window-system/reading/x-window-system.md index f134b8d4d3..6c7a70d02b 100644 --- a/content/chapters/app-interact/lab/content/x-window-system.md +++ b/chapters/app-interact/x-window-system/reading/x-window-system.md @@ -46,3 +46,29 @@ strace -e 'trace=!poll' -e trace='socket,connect,recvmsg' xeyes |& grep -v '\-1 ``` ![strace-xeyes](../media/strace_xeyes.gif) + +## Oneko + +An alternative to `xeyes` which allows us to observe Unix sockets is `oneko`. +Going through the same steps, we see that the application also create a Unix socket, then connects to the path `@"/tmp/.X11-unix/X0"`. + +```console +student@os:~$ strace -e trace=socket,connect oneko +socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 3 +connect(3, {sa_family=AF_UNIX, sun_path=@"/tmp/.X11-unix/X1"}, 20) = 0 +--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} --- +``` + +When running `oneko`, what differs from `xeyes` is the `SIGALRM` signal. +This means that `oneko` uses a timer, which is periodically set, and then it expires only to be reset again. +The purpose of this timer is to slow down the cat. + +Verifying the communication between the X server and `oneko` is easy. +We see that the cat follows our mouse cursor, behaving similarly to `xeyes`. +After running `oneko` under `strace`, we see the communication uses the UNIX socket created at the beginning: + +```console +strace -e 'trace=!poll' -e trace='socket,connect,recvmsg' oneko |& grep -v '\-1 EAGAIN' +``` + +[Quiz](../drills/questions/timer.md) diff --git a/config.yaml b/config.yaml index 2485fb096f..1d9cb04481 100644 --- a/config.yaml +++ b/config.yaml @@ -155,8 +155,23 @@ lab_structure: - guides/benchmarking-sendfile.md - guides/kernel-caching.md - guides/async.md - - + - title: Lab 12 - Application Interaction + filename: lab12.md + content: + - tasks/time-server.md + - tasks/password-cracker.md + - tasks/dbus.md + - reading/x-window-system.md + - reading/time-server.md + - reading/password-cracker.md + - guides/containers-vs-vms.md + - reading/os-cloud.md + - reading/dbus.md + - guides/dbus-dfeet.md + - guides/calling-dbus-methods.md + - guides/inspecting-low-level-communication.md + - guides/dbus-usage-python.md + - guides/firefox.md make_assets: plugin: command options: @@ -166,7 +181,7 @@ make_assets: - chapters/data - chapters/compute - chapters/io - - content/chapters/app-interact/lecture + - chapters/app-interact args: - all @@ -235,23 +250,23 @@ docusaurus: - Questions: path: questions subsections: - - Memory Access: memory-access.md - - Half page: half-page.md - - Malloc Brk: malloc-brk.md - - Malloc Mmap: malloc-mmap.md - - Memory granularity: memory-granularity.md - - Mmap file: mmap-file.md - - Page Allocation: page-allocation.md - - Operators: operators.md - - Memory Leaks: memory-leaks.md - - Valgrind Leaks: valgrind-leaks.md - - Bypass Canary: bypass-canary.md - - Memory Aslr: memory-aslr.md - - Memory Regions Vars: memory-regions-vars.md - - Memory Stack Protector: memory-stack-protector.md - - Stack Layout: stack-layout.md - - String buff over: string-buff-over.md - - String strcpy: string-strcpy.md + - Memory Access: memory-access.md + - Half page: half-page.md + - Malloc Brk: malloc-brk.md + - Malloc Mmap: malloc-mmap.md + - Memory granularity: memory-granularity.md + - Mmap file: mmap-file.md + - Page Allocation: page-allocation.md + - Operators: operators.md + - Memory Leaks: memory-leaks.md + - Valgrind Leaks: valgrind-leaks.md + - Bypass Canary: bypass-canary.md + - Memory Aslr: memory-aslr.md + - Memory Regions Vars: memory-regions-vars.md + - Memory Stack Protector: memory-stack-protector.md + - Stack Layout: stack-layout.md + - String buff over: string-buff-over.md + - String strcpy: string-strcpy.md - Lab 3 - Memory: lab3.md - Lab 4 - Investigate Memory: lab4.md - Lab 5 - Memory Security: lab5.md @@ -328,24 +343,23 @@ docusaurus: - Lab 9 - File Descriptors: lab9.md - Lab 10 - Inter-Process Communication: lab10.md - Lab 11 - IO Optimizations: lab11.md - - Lecture: - path: /build/embed_reveal + - Application Interaction: + path: /build/prepare_view/.view + extra: + - media subsections: - - IO: IO/IO.mdx - - Application Interaction: Application-Interaction/Application-Interaction.mdx - # - Lab: - # - Application Interaction: - # path: content/chapters/app-interact/lab/content - # extra: - # - ../media - # - ../quiz - # subsections: - # - Overview: overview.md - # - Time Server: time-server.md - # - Password Cracker: password-cracker.md - # - The X Window System: x-window-system.md - # - D-Bus: dbus.md - # - OS Cloud: os-cloud.md + - Slides: /build/embed_reveal/Application-Interaction/Application-Interaction.mdx + - Overview: /build/prepare_view/.view/app-interact-overview.md + - Questions: + path: questions + subsections: + - Time Server: time-server.md + - Time Server Interop: time-server-interop.md + - X Window System: timer.md + - Vm Creation: vm-creation.md + - Container versus VM: container-vs-vm.md + - Cgroups versus namespaces: cgroups-vs-namespaces.md + - Lab 12 - Application Interaction: lab12.md - Assignments: # These all have the same filename so we need to create separate # subdirectories for them, otherwise they will overwrite each other. @@ -400,7 +414,7 @@ docusaurus: - slides/Data: /build/make_assets/chapters/data/_site - slides/Software-Stack: /build/make_assets/chapters/software-stack/_site - slides/IO: /build/make_assets/chapters/io/_site - - slides/Application-Interaction: /build/make_assets/content/chapters/app-interact/lecture/_site + - slides/Application-Interaction: /build/make_assets/chapters/app-interact/_site config_meta: title: Operating Systems url: http://localhost/ diff --git a/content/chapters/app-interact/.gitignore b/content/chapters/app-interact/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/content/chapters/app-interact/lab/content/arena.md b/content/chapters/app-interact/lab/content/arena.md deleted file mode 100644 index 6e2509f891..0000000000 --- a/content/chapters/app-interact/lab/content/arena.md +++ /dev/null @@ -1,214 +0,0 @@ -# Arena - -## Oneko - -An alternative to `xeyes` which allows us to observe Unix sockets is `oneko`. -Going through the same steps, we see that the application also create a Unix socket, then connects to the path `@"/tmp/.X11-unix/X0"`. - -```console -student@os:~$ strace -e trace=socket,connect oneko -socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 3 -connect(3, {sa_family=AF_UNIX, sun_path=@"/tmp/.X11-unix/X1"}, 20) = 0 ---- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} --- -``` - -When running `oneko`, what differs from `xeyes` is the `SIGALRM` signal. -This means that `oneko` uses a timer, which is periodically set, and then it expires only to be reset again. -The purpose of this timer is to slow down the cat. - -Verifying the communication between the X server and `oneko` is easy. -We see that the cat follows our mouse cursor, behaving similarly to `xeyes`. -After running `oneko` under `strace`, we see the communication uses the UNIX socket created at the beginning: - -```console -strace -e 'trace=!poll' -e trace='socket,connect,recvmsg' oneko |& grep -v '\-1 EAGAIN' -``` - -[Quiz](../quiz/timer.md) - -## D-Bus - -Use the `dbus` python bindings to get the computer's battery level using a python script. -You can start from the documentation [here](https://dbus.freedesktop.org/doc/dbus-python/tutorial.html#). -You need to read the sections `Connecting to the Bus`, `Proxy objects`, and `Interfaces and methods`. - -There's also a skeleton you can use in `support/dbus/get_battery_level.py`. - -In summary, your script will start by connecting to the `System Bus`. -Then you'll use the `get_object` method to obtain a proxy object. -On this proxy object, you can actually do the method call as explained [here](https://dbus.freedesktop.org/doc/dbus-python/tutorial.html#interfaces-and-methods): - -```text -To call a method, call the method of the same name on the proxy object, passing in the interface name via the dbus_interface keyword argument -``` - -So, if you want to call the method `this.is.an.interface.method` with the arguments `A` and `B` you can do it like this: - -```python -result = proxy.method(A, B, dbus_interface = "this.is.an.interface") -``` - -## OS-Cloud: More Disk Customization - -You might have probably noticed that there are 2 types of disk customizations: - -- One type is for things that can be done without running the virtual machine. -If we only want to modify some files inside the disk filesystem, we can do so by mounting the disk. -This is done, for example, in the `disk-templates/ubuntu_22.04/setup_root_password.sh` script. -There we use `nbd_connect_qcow2` + `mount` to mount the disk, then we modify the `/etc/shadow` file to change the root password. - -- The second case is for operations that must be done with the virtual machine running. -These are handled in the `ubuntu_22_04_vm_prepare` function: the virtual machine is first started (`start_qemu_for_vm`), then `pexpect` is used to interact with the virtual machine via the `qemu` serial console. -Here we do things like running `ssh-keygen` - a binary that is part of the disk filesystem, which depends on other parts of the operating system from the disk to be running. -Note that in `ubuntu_22_04_vm_prepare`, for convenience, we also do some customizations that fall into the first category (like modifying `/etc/ssh/sshd_config`). - -### Copy Additional Files to the Newly Created Disk - -This is a customization from the first category. -In `disk-templates/ubuntu_22.04/files` there is a file called `99-os-cloud-welcome` (a script that prints a greeting message). -We want to copy this file to `/etc/update-motd.d` in our newly created disk, so that it will run whenever a user logs in. - -To do this, you will create a script called `copy_files.sh` in `disk-templates/ubuntu_22.04`. -This script will receive a path to a `qcow2` disk file as an argument, it will mount the disk, and then copy the file to the necessary location. -Then, in the `create_disk_from_template` function in `disk.py` you will call this script, similar with how the other scripts are called. - -You can use `disk-templates/ubuntu_22.04/setup_root_password.sh` as an example. - -### SSH Key Setup - -We want to be able to log into the virtual machine using an ssh key, instead of the password `123456`. -Notice that the `vm_create` API also accepts an `ssh_key` parameter. -Here, the user can provide an ssh public key, which the system will install in `/root/.ssh/authorized_keys` in the newly created virtual machine. - -Your task is to implement this feature, as a customization from the second category (that is, implemented in the `ubuntu_22_04_vm_prepare` function). -The key will be accessible to the function as the `ssh_pub_key` parameter. -Then it's only a matter of writing the key to the appropriate place, using a command like `echo key > /root/.ssh/authorized_keys`. -Note that the `/root/.ssh` directory might not exist, so you need to create it as well. - -After the feature is complete, you can test it using the keys in the `support/os-cloud/keys` directory. -This directory contains a pair of public-private keys. -The directory will also be mounted inside the `os-cloud` container in `/keys`. - -You will create another virtual machine, passing the public key to `vm_create`: - -```console -student@os:~/.../support/os-cloud$ curl -H "Content-Type: application/json" \ - -d '{ "name": "my_vm2", "image": "ubuntu_22.04", "network": "default", "mem_size": "2G", "disk_size": "10G", "ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8CDHgeE4NIIIih3wSz58GDkfPLUk2m9gmbZB1f6o8Lzawzb3HVFpslAUWK0f/Ymw9cloInpMo50gWMYFSyJ7ZrOWWak54BedpHDkFAxxy+JCE9b+pkKsrAT7wiir7gn2LHlhj55FLZkC9PpM9cBcrMfzlcP9Bf+2cnpDdINybSLmOUmrI23ANteM4lEVaa2yEbCaJk6dFB8+atz5zPjvVI0Hd+kJK7yJ0xV6Zc2ADle7TKW3dyiXOE9qFKe9933Rj7ocqNXCAO1cxUoJCVuVS7lh+1pSSPXLWLTOhVp/XiLGWVP6KRYmmn710MWKm9Kj1tPiGUphUraL20SJiRT6/ os-cloud-user"}' \ - localhost:5000/vm_create -{"id":2,"status":"ok"} -``` - -Obtain the IP address that was allocated to the new vm: - -```console -student@os:~/.../support/os-cloud$ curl -s -H "Content-Type: application/json" -d '{ "id": 2 }' localhost:5000/vm_info | jq . -{ - "disk_size": 10737418240, - "id": 2, - "ip": "192.168.0.3", - "mem_size": 2147483648, - "name": "my_vm2", - "network": "default", - "os": "ubuntu_22.04", - "state": "RUNNING" -} -``` - -Then go inside the `os-cloud` container and ssh to the vm using the private key in `/keys`. -It should work without prompting for the password: - -```console -student@os:~/.../support/os-cloud$ docker-compose exec os-cloud bash -root@ac93d3d6cab2:/app# ssh -i /keys/ssh_key root@192.168.0.3 -Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-56-generic x86_64) -[...] -Powered by OS Cloud -Last login: Mon Jan 2 19:34:53 2023 from 192.168.0.1 -root@ubuntu:~# -``` - - - -## OS-Cloud: Internet Access - - - -Notice that our virtual machines don't have internet access: - -```console -Powered by OS Cloud -Last login: Mon Jan 2 19:52:47 UTC 2023 on ttyS0 -root@ubuntu:~# curl google.com -curl: (6) Could not resolve host: google.com -``` - -In this task, we want to fix this problem. -To do this, we must first understand how the networking for the virtual machines is done. - -First, there is the concept of a `network`, which you saw in the previous section. -There is a network called `default`, with the address of `192.168.0.0/24`. -All virtual machines are part of this network, that's why they were allocated ip addresses like `192.168.0.2`. - -Let's go inside the `os-cloud` container and take a look at the network interfaces: - -```console -$ docker-compose exec os-cloud bash -root@8333e5cefb0d:/app# ip a -1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 - link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 - inet 127.0.0.1/8 scope host lo - valid_lft forever preferred_lft forever -2: br0: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 8a:68:b7:5b:6b:45 brd ff:ff:ff:ff:ff:ff - inet 192.168.0.1/16 scope global br0 - valid_lft forever preferred_lft forever -3: tap0: mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000 - link/ether 8a:68:b7:5b:6b:45 brd ff:ff:ff:ff:ff:ff -4: tap1: mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000 - link/ether fa:f8:7f:83:50:8f brd ff:ff:ff:ff:ff:ff -77: eth0@if78: mtu 1500 qdisc noqueue state UP group default - link/ether 02:42:ac:16:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 - inet 172.22.0.3/16 brd 172.22.255.255 scope global eth0 - valid_lft forever preferred_lft forever - -root@8333e5cefb0d:/app# ps -ef | grep qemu -root 19 8 29 09:15 ? 00:01:26 qemu-system-x86_64 -m 2048 -hda /vm-disks/1/disk.qcow2 -net nic,macaddr=52:54:00:12:34:00 -net tap,ifname=tap0,script=no -monitor telnet::10001,server,nowait -serial telnet::10002,server,nowait -nographic -enable-kvm -root 29 8 28 09:15 ? 00:01:24 qemu-system-x86_64 -m 2048 -hda /vm-disks/2/disk.qcow2 -net nic,macaddr=52:54:00:12:34:01 -net tap,ifname=tap1,script=no -monitor telnet::10003,server,nowait -serial telnet::10004,server,nowait -nographic -enable-kvm -``` - -Here we have 2 virtual machines running. -Each virtual machine uses a `tap` interface (the `-net tap,ifname=tap0,script=no` parameter for `qemu`). -This means that the `ens0` interface inside the virtual machine corresponds to the `tap0` interface outside the virtual machine. -All the tap interfaces are bridged together into the `br0` bridge, which has the ip address `192.168.0.1`. -Also, each virtual machine has the default gateway configured to be `192.168.0.1`. - -In summary, it looks something like this: - -![os-cloud](../media/os_cloud_networking.svg) - -All the traffic coming from the virtual machines passes through the `br0` interface. -So, in order to make the internet work, all we have to do is a simple `NAT`, with a command like: - -```console -root@8333e5cefb0d:/app# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j MASQUERADE -``` - -Now, the virtual machines should have internet access: - -```console -root@8333e5cefb0d:/app# ssh root@192.168.0.2 -[...] -root@ubuntu:~# curl google.com - -301 Moved -

301 Moved

-The document has moved -here. - -``` - -Now your task is to run the `iptables` command above automatically when the system starts, so that it's not necessary to run it manually like we did in the above example. - -A good place to do this is in the `create_one_network` function in `network.py`. -There you can add another `subprocess.run` call to run `iptables`. -The `192.168.0.0/24` value should not be hardcoded, but you can take it from the `ip_with_prefixlen` member of the `Net` object. diff --git a/content/chapters/app-interact/lab/content/dbus.md b/content/chapters/app-interact/lab/content/dbus.md deleted file mode 100644 index de5974fc68..0000000000 --- a/content/chapters/app-interact/lab/content/dbus.md +++ /dev/null @@ -1,242 +0,0 @@ -# D-Bus - -D-Bus is an Inter-Process Communication (IPC) mechanism that is commonly present on Linux. -It is particularly used by various components of the desktop environment (like GNOME) to communicate between one another, although the system itself is general-purpose and can be used in any other situations. - -As the name suggests, the communication model is that of a bus: processes connect to the bus, then exchange messages with other processes through the bus. -The bus itself is implemented by the dbus-daemon, and there are in fact multiple buses: one system bus, accessible system-wide, and one or more session buses, each one corresponding to one user login session. - -Every process that connects to D-Bus receives a unique connection name. -This name can be something human-readable, like `org.freedesktop.Notifications`, or some generated ID, like `:1.63`. -Once a process is connected, it can expose one or multiple `objects`. -An object has a path-like name, consisting of strings separated by a slash character (for example, `/org/freedesktop/Notifications`). -Each object contains one or more `interfaces`, which have the methods that can be called on that object. - -## D-Bus Inspection with D-Feet - -In order to better understand these concepts, we'll use a graphical tool (`D-Feet`) to inspect all the available D-Bus objects on our system. - -Run D-Feet and select `Session Bus` from the top button: - -![dfeet-session-bus](../media/dfeet_session_bus.png) - -On the left panel, we can see all the processes connected to D-Bus with their associated `connection names`. -Scroll down and find `org.freedesktop.Notifications`. -On the right side, expand `/org/freedesktop/Notifications` and then expand the `org.freedesktop.Notifications` interface. -The window should look like this: - -![dfeet-notifications](../media/dfeet_notifications.png) - -Some observations: - -* The bus communication happens over a Unix socket, with the path `/run/user/1000/bus`. - -* `org.freedesktop.Notifications` on the left panel is the `connection name`. - -* The process that has connected with this name is `/usr/bin/gjs /usr/share/gnome-shell/org.gnome.Shell.Notifications` and has the pid of `4373`. - -* This process exposes one object: `/org/freedesktop/Notifications`. -Note that the object name is the same as the connection name, where the dots have been replaced with slashes. -This is not a requirement, as the objects exposed by a process can have any name. - - -* The object has 4 interfaces: `org.freedesktop.DBus.Introspectable`, `org.freedesktop.DBus.Peer`, `org.freedesktop.DBus.Properties` and `org.freedesktop.Notifications`. -Note that the last one (`org.freedesktop.Notifications`) is the same as the connection name, but this again is just a coincidence, not a requirement. - - -* The interface `org.freedesktop.Notifications` has some methods that can be called, such as `Notify`. - -## Calling D-Bus Methods - -The application behind `org.freedesktop.Notifications` is responsible with desktop notifications (the small bubbles of text that appear at the top of the screen when some event happens). -When an application wants to send a notification it needs to connect to D-Bus and call the `Notify` method from the `org.freedesktop.Notifications` interface. - -In this example, we want to call the `Notify` method ourselves. -To do this, we must first understand the signature of this method: - -`Notify (String arg_0, UInt32 arg_1, String arg_2, String arg_3, String arg_4, Array of [String] arg_5, Dict of {String, Variant} arg_6, Int32 arg_7) ↦ (UInt32 arg_8)` - -This doesn't tell us much, but we can find more documentation [here](https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html#basic-design), since `freedesktop` is an open standard. - -We'll set the arguments to the following (for our simple case, most of them will be unused): - -* `app_name`: `""` - -* `replaces_id`: `0` - -* `app_icon`: `""` - -* `summary`: `"This is the title"` - -* `body`: `"This is the content"` - -* `actions`: `[]` - -* `hints`: `{}` - -* `expire_timeout`: `-1` - -Now the question is how to actually call the method. -Normally, we would have to write an application that connects to D-Bus and executes the call. -But for demonstrative purposes there are easier ways. - -One way is directly from d-feet. -If we double-click on the `Notify` method in the right-side pane of d-feet, a window will open that allows us to call the method with any arguments that we want: - -![dfeet-execute-dialog](../media/dfeet_execute.png) - -Then we click the `Execute` button and the notification will appear: - -![dfeet-execute-](../media/dfeet_execute.gif) - -Another way is from the command-line. There's the `gdbus` tool that can do this: - -```console -student@os:~$ gdbus call \ - --session \ - --dest org.freedesktop.Notifications \ - --object-path /org/freedesktop/Notifications \ - --method org.freedesktop.Notifications.Notify \ - -- \ - '""' \ - 0 \ - '""' \ - "This is the title" \ - "This is the content" \ - [] \ - {} \ - -1 -``` - -Let's see how it works: - -![gdbus-notify](../media/gdbus_notify.gif) - -You can also find this `gdbus` call in the `support/dbus/send_notification.sh` script. - -## Inspecting the Low-level Communication - -Let's run `gdbus` under `strace` to see what's happening behind the scenes. -Run the script in `support/dbus/send_notification_strace.sh`: - -```console -strace: Process 61888 attached -[pid 61887] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 5 -[pid 61887] connect(5, {sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, 110) = 0 -[pid 61887] sendmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0", iov_len=1}], msg_iovlen=1, -msg_control=[{cmsg_len=28, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, cmsg_data={pid=61887, -uid=1000, gid=1000}}], -msg_controllen=32, msg_flags=0}, MSG_NOSIGNAL) = 1 -strace: Process 61889 attached - -[...] - -[pid 61889] sendmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\1\0\1T\0\0\0\3\0\0\0\237\0\0\0\1 -\1o\0\36\0\0\0/org/freedesktop/Notifications\0\0\2\1s\0\35\0\0\0org.freedesktop.Notifications\0\0\0\6\1s\0\35 -\0\0\0org.freedesktop.Notifications\0\0\0\10\1g\0\rsusssasa{sv}i\0\0\0\0\0\0\3\1s\0\6\0\0\0Notify\0\0\0\0\0\0 -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21\0\0\0This is the title\0\0\0\23\0\0\0This is the content\0\0\0\0\0\0\0\0\0 -\0\0\0\0\377\377\377\377", iov_len=260}], msg_iovlen=1, msg_controllen=0, - msg_flags=0}, MSG_NOSIGNAL) = 260 -[pid 61889] recvmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\2\1\1\4\0\0\0\312\0\0\0.\0\0\0", iov_len=16}], -msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 16 -[pid 61889] recvmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\6\1s\0\6\0\0\0:1.497\0\0\10\1g\0\1u\0\0\5\1u\0 -\3\0\0\0\7\1s\0\5\0\0\0:1.49\0\0\0\36\0\0\0", iov_len=52}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 52 -(uint32 30,) -[pid 61889] +++ exited with 0 +++ -[pid 61888] +++ exited with 0 +++ -+++ exited with 0 +++ -``` - -We see a Unix socket being created and a connection made to `/run/user/1000/bus`, as expected. -Then a series of messages are exchanged on the socket, which are part of the D-Bus protocol. -On a closer look, we can even identify some strings from our notification, like `This is the title` or `This is the content`: - -```console -[pid 61889] sendmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\1\0\1T\0\0\0\3\0\0\0\237\0\0\0\1 -\1o\0\36\0\0\0/org/freedesktop/Notifications\0\0\2\1s\0\35\0\0\0org.freedesktop.Notifications\0\0\0\6\1s\0\35 -\0\0\0org.freedesktop.Notifications\0\0\0\10\1g\0\rsusssasa{sv}i\0\0\0\0\0\0\3\1s\0\6\0\0\0Notify\0\0\0\0\0\0 -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21\0\0\0This is the title\0\0\0\23\0\0\0This is the content\0\0\0\0\0\0\0\0\0 -\0\0\0\0\377\377\377\377", iov_len=260}], msg_iovlen=1, msg_controllen=0, -``` - -### Practice - -Use D-Bus to find out the computer's battery level. -There is the `org.freedesktop.UPower` interface on the system bus that can provide this information. - -The method you need to call is `org.freedesktop.DBus.Properties.Get` from the `/org/freedesktop/UPower/devices/DisplayDevice` object. - - -This method needs 2 arguments: an interface name and a property name. - -Those should be `org.freedesktop.UPower.Device` and `Percentage` respectively. - - -Then input all of the above into a `gdbus` call, which, if everything is correct, should output the battery percentage level as a number between 0 and 100. - -Note: if you are running on a desktop computer or inside a virtual machine, you will get the value `0.0`, because those systems don't have a battery. - -This task can also be solved in a python script. -Check out the details in the [arena section](./arena.md#d-bus). - -## Firefox - -Let's do the following experiment: - -- Open the Firefox browser - -- From a terminal run `firefox www.google.com` - -![firefox-url-open](../media/firefox_url_open.gif) - -Notice that the URL we passed in the command-line was opened in the existing Firefox window as a new tab. -Even though we started a separate Firefox process, which should have created a separate new window, this didn't actually happen. -Instead, the process that we started from the command-line exited immediately and the site was opened in the already running Firefox instance. - -Without any precise knowledge about Firefox internals, we can guess that something like this happened: - -- The newly started Firefox process detected that another instance of Firefox is already running - -- The newly started Firefox process sent a message to the existing running process, requesting it to open a URL in a new tab - -Since we're talking about message passing between 2 processes, there's a chance that maybe D-Bus was involved. -Let's check: we'll use a tool called `dbus-monitor` that will print all messages passed through D-Bus. - -```console -student@os:~$ dbus-monitor -``` - -Then, in another terminal, we'll run `firefox www.google.com` again. - -Going back to the `dbus-monitor` output, we find the following: - -```console -... -method call time=1655809062.813923 sender=:1.757 -> destination=org.mozilla.firefox.ZGVmYXVsdC1yZWxlYXNl serial=2 path=/org/mozilla/firefox/Remote; interface=org.mozilla.firefox; member=OpenURL - array of bytes [ - 02 00 00 00 1a 00 00 00 2f 00 00 00 2f 68 6f 6d 65 2f 61 64 72 69 61 6e - 73 00 2f 6f 70 74 2f 66 69 72 65 66 6f 78 2f 66 69 72 65 66 6f 78 00 77 - 77 77 2e 67 6f 6f 67 6c 65 2e 63 6f 6d 00 - ] -``` - -There was a D-Bus call to `org.mozilla.firefox.ZGVmYXVsdC1yZWxlYXNl`, on the object `/org/mozilla/firefox/Remote`, method `OpenURL` from the `org.mozilla.firefox` interface. -Indeed, we see that this object exists in d-feet as well: - -![dfeet-firefox](../media/dfeet_firefox.png) - -We can try to call the `OpenURL` method ourselves, directly from d-feet. -The method has only one argument of the type `Array of [Byte]`. -Although there's no documentation for it, we can use the same byte array that we saw in `dbus-monitor`: - -```console - array of bytes [ - 02 00 00 00 1a 00 00 00 2f 00 00 00 2f 68 6f 6d 65 2f 61 64 72 69 61 6e - 73 00 2f 6f 70 74 2f 66 69 72 65 66 6f 78 2f 66 69 72 65 66 6f 78 00 77 - 77 77 2e 67 6f 6f 67 6c 65 2e 63 6f 6d 00 - ] -``` - -(Note that `77 77 77 2e 67 6f 6f 67 6c 65 2e 63 6f 6d` at the end is the string `www.google.com`, so that's another confirmation that we're on the right track). - -![dfeet-url-open](../media/dfeet_url_open.gif) diff --git a/content/chapters/app-interact/lab/content/time-server.md b/content/chapters/app-interact/lab/content/time-server.md deleted file mode 100644 index 6c7d988eed..0000000000 --- a/content/chapters/app-interact/lab/content/time-server.md +++ /dev/null @@ -1,52 +0,0 @@ -# Time Server - -Check out the code in `support/time-server/server.c` and `support/time-server/client.c`. - -This is a simple program consisting of a server and a client. -The server uses a tcp socket to wait for connections. -Once a client has connected, the server will send the current time to it. -The client will then print the received time to the console. - -Let's build and run this example: - -```console -student@os:~/.../support/time-server$ make -gcc -Wall -o server server.c -gcc -Wall -o client client.c -student@os:~/.../support/time-server$ ./server -``` - -Then, in another terminal: - -```console -student@os:~/.../support/time-server$ ./client 127.0.0.1 2000 -The time is Thu Sep 1 11:48:03 2022 -``` - -## Python Version - -In `support/time-server/python` we have the equivalent python implementation for both the server and client: - -```console -student@os:~/.../support/time-server/python$ python3 server.py -``` - -```console -student@os:~/.../support/time-server/python$ python3 client.py 127.0.0.1 2000 -The time is Thu Sep 1 11:58:01 2022 -``` - -### Practice - -Try to figure out the protocol used by the server and the client. -You can do this by reading the source code, corroborated with information obtained at runtime. - -Run the server again (the version in C), but instead of running the client, let's run `netcat` and pipe the output to `hexdump`: - -```console -nc -d 127.0.0.1 2000 | hexdump -C -``` - -[Quiz](../quiz/time-server.md) - -[Quiz](../quiz/time-server-interop.md) diff --git a/content/chapters/app-interact/lab/solution/password-cracker/.gitignore b/content/chapters/app-interact/lab/solution/password-cracker/.gitignore deleted file mode 100644 index cfdab0fc1e..0000000000 --- a/content/chapters/app-interact/lab/solution/password-cracker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/password-cracker-multiprocess diff --git a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/utils.py b/content/chapters/app-interact/lab/support/os-cloud/os-cloud/utils.py deleted file mode 100644 index 6479524bd2..0000000000 --- a/content/chapters/app-interact/lab/support/os-cloud/os-cloud/utils.py +++ /dev/null @@ -1 +0,0 @@ -DISK_TMP_PASSWORD = "123456" diff --git a/content/chapters/app-interact/lab/support/password-cracker/.gitignore b/content/chapters/app-interact/lab/support/password-cracker/.gitignore deleted file mode 100644 index 95471c387b..0000000000 --- a/content/chapters/app-interact/lab/support/password-cracker/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/password-cracker-multiprocess -/password-cracker-multithread \ No newline at end of file diff --git a/content/chapters/app-interact/lab/support/time-server/.gitignore b/content/chapters/app-interact/lab/support/time-server/.gitignore deleted file mode 100644 index acc58d7f7c..0000000000 --- a/content/chapters/app-interact/lab/support/time-server/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/server -/client diff --git a/content/chapters/app-interact/lecture/Makefile b/content/chapters/app-interact/lecture/Makefile deleted file mode 100644 index f932b5c21b..0000000000 --- a/content/chapters/app-interact/lecture/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -TARGETS = synchronization interruption - -include ../../../common/makefile/slides.mk diff --git a/content/chapters/app-interact/lecture/demo/comm-channels/Makefile b/content/chapters/app-interact/lecture/demo/comm-channels/Makefile deleted file mode 100644 index d8093731b0..0000000000 --- a/content/chapters/app-interact/lecture/demo/comm-channels/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -BINARIES = send_receive_pipe reader writer \ - send_fifo receive_fifo \ - send_unix_socket receive_unix_socket \ - send_net_dgram_socket receive_net_dgram_socket \ - send_net_stream_socket receive_net_stream_socket - -include ../../../../../common/makefile/multiple.mk - -../../../../../common/utils/sock/sock_util.o: ../../../../../common/utils/sock/sock_util.c - -send_net_stream_socket: ../../../../../common/utils/sock/sock_util.o - -receive_net_stream_socket: ../../../../../common/utils/sock/sock_util.o - -clean:: - -rm -f socket_channel - -rm -f fifo_channel diff --git a/content/chapters/app-interact/lecture/demo/fibonacci-server/Makefile b/content/chapters/app-interact/lecture/demo/fibonacci-server/Makefile deleted file mode 100644 index 46dc308d6d..0000000000 --- a/content/chapters/app-interact/lecture/demo/fibonacci-server/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -BINARIES = server mt_server mp_server mt_pool_server mp_pool_server mp_pool_server_works - -include ../../../../../common/makefile/multiple.mk - -server: server.o connection.o ../../../../../common/utils/sock/sock_util.o - -mt_server: mt_server.o connection.o ../../../../../common/utils/sock/sock_util.o - $(CC) -o $@ $^ -lpthread - -mp_server: mp_server.o connection.o ../../../../../common/utils/sock/sock_util.o - -mt_pool_server: mt_pool_server.o task.o connection.o ../../../../../common/utils/sock/sock_util.o - $(CC) -o $@ $^ -lpthread - -mp_pool_server: mp_pool_server.o task.o connection.o ../../../../../common/utils/sock/sock_util.o - $(CC) -o $@ $^ -lpthread - -mp_pool_server_works: mp_pool_server_works.o connection.o ../../../../../common/utils/sock/sock_util.o - -server.o: connection.h - -mt_server.o: connection.h - -mp_server.o: connection.h - -mt_pool_server.o: task.h connection.h - -mp_pool_server.o: task.h connection.h - -mp_pool_server_works.o: connection.h - -connection.o: connection.h - -task.o: task.h - -../../../../../common/utils/sock/sock_util.o: ../../../../../common/utils/sock/sock_util.c ../../../../../common/utils/sock/sock_util.h - -clean:: - -rm -f ../../../../../common/utils/sock/sock_util.o diff --git a/content/chapters/app-interact/lecture/demo/interrupt/Makefile b/content/chapters/app-interact/lecture/demo/interrupt/Makefile deleted file mode 100644 index dad0fc87db..0000000000 --- a/content/chapters/app-interact/lecture/demo/interrupt/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BINARIES = signal_printer rt_signal_printer signal_sender signal_sender_sleep rt_signal_sender - -include ../../../../../common/makefile/multiple.mk diff --git a/content/chapters/app-interact/lecture/demo/lock/Makefile b/content/chapters/app-interact/lecture/demo/lock/Makefile deleted file mode 100644 index e205ae8b43..0000000000 --- a/content/chapters/app-interact/lecture/demo/lock/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -BINARIES = thread_mutex thread_sem proc_sem proc_flock -LDLIBS ?= -lpthread - -include ../../../../../common/makefile/multiple.mk diff --git a/content/chapters/app-interact/lecture/demo/shared-mem/Makefile b/content/chapters/app-interact/lecture/demo/shared-mem/Makefile deleted file mode 100644 index 06ee2a43d0..0000000000 --- a/content/chapters/app-interact/lecture/demo/shared-mem/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -BINARIES = shmem_threads shmem_file_reader shmem_file_writer shmem_shm_reader shmem_shm_writer -LDLIBS ?= -lpthread -lrt - -include ../../../../../common/makefile/multiple.mk - -shmem_file_reader.o: shmem_reader.c ../../../../../common/utils/log/log.h ../../../../../common/utils/utils.h - $(CC) $(CPPFLAGS) -DSHMEM_FILE $(CFLAGS) -c -o $@ $< - -shmem_file_writer.o: shmem_writer.c ../../../../../common/utils/log/log.h ../../../../../common/utils/utils.h - $(CC) $(CPPFLAGS) -DSHMEM_FILE $(CFLAGS) -c -o $@ $< - -shmem_shm_reader.o: shmem_reader.c ../../../../../common/utils/log/log.h ../../../../../common/utils/utils.h - $(CC) $(CPPFLAGS) -DSHMEM_SHM $(CFLAGS) -c -o $@ $< - -shmem_shm_writer.o: shmem_writer.c ../../../../../common/utils/log/log.h ../../../../../common/utils/utils.h - $(CC) $(CPPFLAGS) -DSHMEM_SHM $(CFLAGS) -c -o $@ $< - -clean:: - -rm -f shmem_file_writer.o shmem_file_reader.o - -rm -f shmem_shm_writer.o shmem_shm_reader.o diff --git a/content/chapters/app-interact/lecture/demo/sync/Makefile b/content/chapters/app-interact/lecture/demo/sync/Makefile deleted file mode 100644 index ed731e0d18..0000000000 --- a/content/chapters/app-interact/lecture/demo/sync/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -BINARIES = thread_sem thread_cond proc_sem_first proc_sem_second \ - proc_sig_first proc_sig_second -LDLIBS ?= -lpthread - -include ../../../../../common/makefile/multiple.mk diff --git a/gen-view.py b/gen-view.py index 1134d94bf2..3f3fc9b174 100644 --- a/gen-view.py +++ b/gen-view.py @@ -6,7 +6,7 @@ from typing import List import yaml -CHAPTERS = ["Software Stack", "Data", "Compute", "IO"] +CHAPTERS = ["Software Stack", "Data", "Compute", "IO", "App Interact"] CHAPTERS_PATH = "chapters/" viewDir = ".view"