Skip to content

Commit 6ac786a

Browse files
committed
Add FreeBSD AppImage builds.
1 parent 0c94222 commit 6ac786a

File tree

6 files changed

+416
-49
lines changed

6 files changed

+416
-49
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: "Continuous build (FreeBSD)"
2+
3+
on:
4+
push:
5+
branches:
6+
- '*'
7+
tags-ignore:
8+
- 'continuous*'
9+
10+
jobs:
11+
build:
12+
strategy:
13+
matrix:
14+
include:
15+
- os: ubuntu-latest
16+
arch: x86_64
17+
dependencies: automake bash cmake gcc git gmake libtool meson nasm perl5 pkgconf python sudo wget wine yasm zip
18+
19+
runs-on: ${{ matrix.os }}
20+
21+
steps:
22+
- name: Start VM
23+
id: vm
24+
uses: vmactions/freebsd-vm@v1
25+
with:
26+
sync: sshfs
27+
28+
- name: Enable Linux support
29+
shell: freebsd {0}
30+
run: |
31+
sysrc linux_enable="YES"
32+
service linux start
33+
34+
- name: Install dependencies
35+
shell: freebsd {0}
36+
run: |
37+
pkg update
38+
pkg install -y ${{ matrix.dependencies }}
39+
pkg install -y gnome-icon-theme gtk3
40+
41+
- name: Checkout repository
42+
uses: actions/checkout@v4
43+
44+
- name: Checkout smooth
45+
uses: actions/checkout@v4
46+
with:
47+
repository: enzo1982/smooth
48+
path: smooth
49+
50+
- name: Checkout BoCA
51+
uses: actions/checkout@v4
52+
with:
53+
repository: enzo1982/BoCA
54+
path: boca
55+
56+
- name: Build AppImage
57+
shell: freebsd {0}
58+
env:
59+
AppImageArch: ${{ matrix.arch }}
60+
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
61+
run: |
62+
cd $GITHUB_WORKSPACE
63+
pw user add -n vmuser -m -g wheel
64+
echo "vmuser ALL=(ALL) NOPASSWD: ALL" >> /usr/local/etc/sudoers
65+
su vmuser -c .github/workflows/tools/build-appimage
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
diff -Naur type2-runtime-main/src/runtime/Makefile type2-runtime-freebsd/src/runtime/Makefile
2+
--- type2-runtime-main/src/runtime/Makefile 2025-05-30 13:05:28.000000000 +0200
3+
+++ type2-runtime-freebsd/src/runtime/Makefile 2025-06-11 14:29:55.000000000 +0200
4+
@@ -1,12 +1,12 @@
5+
GIT_COMMIT := $(shell cat version)
6+
-CC = clang
7+
-CFLAGS = -std=gnu99 -Os -D_FILE_OFFSET_BITS=64 -DGIT_COMMIT=\"$(GIT_COMMIT)\" -T data_sections.ld -ffunction-sections -fdata-sections -Wl,--gc-sections -static -Wall -Werror -static-pie
8+
-LIBS = -lsquashfuse -lsquashfuse_ll -lzstd -lz -lfuse3 -lmimalloc
9+
+CC = gcc
10+
+CFLAGS = -std=gnu99 -Os -D_FILE_OFFSET_BITS=64 -DGIT_COMMIT=\"$(GIT_COMMIT)\" -T data_sections.ld -ffunction-sections -fdata-sections -Wl,--gc-sections -static -Wall
11+
+LIBS = -lsquashfuse -lsquashfuse_ll -lzstd -llzma -lz -llz4 -llzo2 -lfuse3 -lmd -ldl -lpthread
12+
13+
all: runtime
14+
15+
runtime: runtime.c
16+
- $(CC) -I/usr/local/include/squashfuse -I/usr/include/fuse3 $(CFLAGS) $^ $(LIBS) -o $@
17+
+ $(CC) -I/usr/local/include -I/usr/local/include/fuse3 $(CFLAGS) $^ $(LIBS) -o $@
18+
19+
clean:
20+
rm -f runtime
21+
diff -Naur type2-runtime-main/src/runtime/runtime.c type2-runtime-freebsd/src/runtime/runtime.c
22+
--- type2-runtime-main/src/runtime/runtime.c 2025-05-30 13:05:28.000000000 +0200
23+
+++ type2-runtime-freebsd/src/runtime/runtime.c 2025-06-11 17:53:16.423734200 +0200
24+
@@ -64,8 +64,7 @@
25+
#include <libgen.h>
26+
#include <dirent.h>
27+
#include <ctype.h>
28+
-
29+
-const char* fusermountPath = NULL;
30+
+#include <sys/sysctl.h>
31+
32+
typedef struct {
33+
uint32_t lo;
34+
@@ -414,106 +413,6 @@
35+
return 0;
36+
}
37+
38+
-char* find_fusermount(bool verbose) {
39+
- char* fusermount_base = "fusermount";
40+
-
41+
- char* fusermount_path = getenv("PATH");
42+
- if (fusermount_path == NULL) {
43+
- return NULL;
44+
- }
45+
-
46+
- char* path_copy = strdup(fusermount_path);
47+
- char* dir = strtok(path_copy, ":");
48+
-
49+
- while (dir != NULL) {
50+
- DIR* dir_ptr = opendir(dir);
51+
- if (dir_ptr == NULL) {
52+
- dir = strtok(NULL, ":");
53+
- continue;
54+
- }
55+
-
56+
- struct dirent* entry;
57+
- while ((entry = readdir(dir_ptr)) != NULL) {
58+
- // Check if the entry starts with "fusermount"
59+
- if (strncmp(entry->d_name, fusermount_base, 10) == 0) {
60+
- // Check if the rest of the entry is a digit
61+
- char* suffix = entry->d_name + 10;
62+
- int j = 0;
63+
- while (suffix[j] != '\0' && isdigit(suffix[j])) {
64+
- j++;
65+
- }
66+
-
67+
- if (suffix[j] == '\0') {
68+
- // Construct the full path of the entry
69+
- char* fusermount_full_path = malloc(strlen(dir) + strlen(entry->d_name) + 2);
70+
- sprintf(fusermount_full_path, "%s/%s", dir, entry->d_name);
71+
-
72+
- // Check if the binary is setuid root
73+
- struct stat sb;
74+
- if (stat(fusermount_full_path, &sb) == -1) {
75+
- perror("stat");
76+
- free(fusermount_full_path);
77+
- continue;
78+
- }
79+
-
80+
- if (sb.st_uid != 0 || (sb.st_mode & S_ISUID) == 0) {
81+
- if (verbose) {
82+
- printf("Not setuid root, skipping...\n");
83+
- }
84+
- free(fusermount_full_path);
85+
- continue;
86+
- }
87+
-
88+
- if (verbose) {
89+
- printf("Found setuid root executable: %s\n", fusermount_full_path);
90+
- }
91+
-
92+
- pid_t pid = fork();
93+
- if (pid == -1) {
94+
- perror("fork");
95+
- free(fusermount_full_path);
96+
- continue;
97+
- }
98+
-
99+
- if (pid == 0) {
100+
- // Child process
101+
-
102+
- // close stdout and stderr if not in verbose mode
103+
- if (!verbose) {
104+
- close(1);
105+
- close(2);
106+
- }
107+
-
108+
- char* args[] = {fusermount_full_path, "--version", NULL};
109+
- execvp(fusermount_full_path, args);
110+
- // If execvp returns, it means the executable was not found
111+
- exit(1);
112+
- } else {
113+
- // Parent process
114+
- int status;
115+
- waitpid(pid, &status, 0);
116+
-
117+
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
118+
- // The executable was found and executed successfully
119+
- closedir(dir_ptr);
120+
- free(path_copy);
121+
- return fusermount_full_path;
122+
- }
123+
-
124+
- free(fusermount_full_path);
125+
- }
126+
- }
127+
- }
128+
- }
129+
-
130+
- closedir(dir_ptr);
131+
- dir = strtok(NULL, ":");
132+
- }
133+
-
134+
- free(path_copy);
135+
- return NULL;
136+
-}
137+
-
138+
/* Exit status to use when launching an AppImage fails.
139+
* For applications that assign meanings to exit status codes (e.g. rsync),
140+
* we avoid "cluttering" pre-defined exit status codes by using 127 which
141+
@@ -722,16 +621,8 @@
142+
143+
if (arg && strcmp(arg, option) == 0) {
144+
char portable_dir[PATH_MAX];
145+
- char fullpath[PATH_MAX];
146+
-
147+
- ssize_t length = readlink(appimage_path, fullpath, sizeof(fullpath));
148+
- if (length < 0) {
149+
- fprintf(stderr, "Error getting realpath for %s\n", appimage_path);
150+
- exit(EXIT_FAILURE);
151+
- }
152+
- fullpath[length] = '\0';
153+
154+
- sprintf(portable_dir, "%s.%s", fullpath, name);
155+
+ sprintf(portable_dir, "%s.%s", appimage_path, name);
156+
if (!mkdir(portable_dir, S_IRWXU))
157+
fprintf(stderr, "Portable %s directory created at %s\n", name, portable_dir);
158+
else
159+
@@ -1481,7 +1372,14 @@
160+
* functionality specifically for builds used by appimaged.
161+
*/
162+
if (getenv("TARGET_APPIMAGE") == NULL) {
163+
- strcpy(appimage_path, "/proc/self/exe");
164+
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
165+
+ size_t len = PATH_MAX;
166+
+
167+
+ if (sysctl(mib, 4, appimage_path, &len, 0, 0) != 0) {
168+
+ perror("Failed to obtain absolute path");
169+
+ exit(EXIT_EXECERROR);
170+
+ }
171+
+
172+
strcpy(argv0_path, argv[0]);
173+
} else {
174+
strcpy(appimage_path, getenv("TARGET_APPIMAGE"));
175+
@@ -1510,16 +1408,7 @@
176+
177+
/* Print the help and then exit */
178+
if (arg && strcmp(arg, "appimage-help") == 0) {
179+
- char fullpath[PATH_MAX];
180+
-
181+
- ssize_t length = readlink(appimage_path, fullpath, sizeof(fullpath));
182+
- if (length < 0) {
183+
- fprintf(stderr, "Error getting realpath for %s\n", appimage_path);
184+
- exit(EXIT_EXECERROR);
185+
- }
186+
- fullpath[length] = '\0';
187+
-
188+
- print_help(fullpath);
189+
+ print_help(appimage_path);
190+
exit(0);
191+
}
192+
193+
@@ -1562,12 +1451,7 @@
194+
195+
if (getenv("TARGET_APPIMAGE") == NULL) {
196+
// If we are operating on this file itself
197+
- ssize_t len = readlink(appimage_path, fullpath, sizeof(fullpath));
198+
- if (len < 0) {
199+
- perror("Failed to obtain absolute path");
200+
- exit(EXIT_EXECERROR);
201+
- }
202+
- fullpath[len] = '\0';
203+
+ strcpy(fullpath, appimage_path);
204+
} else {
205+
char* abspath = realpath(appimage_path, NULL);
206+
if (abspath == NULL) {
207+
@@ -1737,21 +1621,6 @@
208+
209+
if (pid == 0) {
210+
/* in child */
211+
-
212+
- fusermountPath = getenv("FUSERMOUNT_PROG");
213+
- if (fusermountPath == NULL) {
214+
- char* new_prog = find_fusermount(verbose);
215+
- if (new_prog != NULL) {
216+
- setenv("FUSERMOUNT_PROG", new_prog, 1);
217+
- if (verbose) {
218+
- fprintf(stderr, "FUSERMOUNT_PROG set to %s\n", new_prog);
219+
- }
220+
- free(new_prog);
221+
- } else {
222+
- printf("Error: No suitable fusermount binary found on the $PATH\n");
223+
- }
224+
- }
225+
-
226+
char* child_argv[5];
227+
228+
/* close read pipe */
229+
@@ -1847,6 +1716,16 @@
230+
strcpy(filename, mount_dir);
231+
strcat(filename, "/AppRun");
232+
233+
+ /* Wait for mounted image to become available (up to 1s) */
234+
+ for (int i = 0; i < 100; i++) {
235+
+ struct stat s;
236+
+ if (stat(filename, &s) == 0)
237+
+ break;
238+
+
239+
+ /* Wait 10ms */
240+
+ usleep(10000);
241+
+ }
242+
+
243+
/* TODO: Find a way to get the exit status and/or output of this */
244+
execv(filename, real_argv);
245+
/* Error if we continue here */

0 commit comments

Comments
 (0)