Compare commits

...

10 commits

9 changed files with 720 additions and 25 deletions

View file

@ -1,33 +1,21 @@
#SOURCE= vlc
#CFLAGS=$(shell pkg-config --libs vlc)
#
#all: compilationvlc
#
#compilationvlc:
# $(CC) $(SOURCE).c -o $(SOURCE) $(CFLAGS)
# Directory to store compiled binaries.
BINDIR ?= /tmp/bin/
CC=clang
CFLAGS=-c -Wall -g
LDFLAGS=
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
#SOURCES=$(wildcard *.c)
TESTS=$(addsuffix .test, $(EXEC))
CC ?= clang
CFLAGS ?= -c -Wall -g
LDFLAGS ?=
all: $(SOURCES) $(EXEC)
CFILES=$(wildcard *.c)
EXEC=$(patsubst %.c,$(BINDIR)%,$(CFILES))
TESTS=$(addsuffix .test, $(patsubst %.c,%,$(CFILES)))
$(EXEC): $(CFILES)
$(CC) $(LDFLAGS) $@.c -o $@
all: $(BINDIR) $(EXEC)
.c.o:
$(CC) $(CFLAGS) $< -o $@
clean:
@-rm $(EXEC)
$(BINDIR):; -mkdir -p $(BINDIR)
$(EXEC): $(CFILES); $(CC) $(LDFLAGS) `basename $@`.c -o $@
clean:; @-rm $(EXEC)
# to test a binary "prog" : make prog.test
$(TESTS):
valgrind --leak-check=full -v --track-origins=yes ./$(basename $@)
$(TESTS):; valgrind --leak-check=full -v --track-origins=yes $(BINDIR)$(basename $@)
test: all $(TESTS)

43
c/howamiused.c Normal file
View file

@ -0,0 +1,43 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define TMPDIR "/tmp/"
// When invoked, this application writes its input, parameters and
// environment variables in differents files: last-(input|parameters|env) in TMPDIR.
//
// Useful for debugging purposes.
int main(int argc, char **argv, char **env) {
int fd = open(TMPDIR "last-input", O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) { return -1; }
size_t nb = 0;
char buffer[BUFSIZ];
while((nb = read(0, buffer, BUFSIZ-1))) {
dprintf(fd, "%*s", (int)nb, buffer);
}
close(fd);
fd = open(TMPDIR "last-parameters", O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) { return -1; }
for (size_t i = 0 ; i < argc ; i++) {
dprintf(fd, "%s\n", argv[i]);
}
close(fd);
fd = open(TMPDIR "last-env", O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) { return -1; }
while (env[0] != NULL) {
dprintf(fd, "%s\n", env[0]);
printf("env: %s\n", env[0]);
env++;
}
close(fd);
return 0;
}

340
c/paintest.c Normal file
View file

@ -0,0 +1,340 @@
#include <stdio.h>
#include <fcntl.h> // open
#include <unistd.h> // read write
#include <stdlib.h>
#include <netdb.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#define BUFFER_SIZE 1000
/* The purpose of this application is to test AppArmor profiles.
Thus, this application can perform a few (limited) operations regarding files and network access.
*/
void read_file(char *filename) {
printf("read_file: %s\n", filename);
int fd = open(filename, O_RDONLY, NULL);
if (fd > 0) {
char buffer[BUFFER_SIZE];
size_t bytes = read(fd, buffer, BUFFER_SIZE);
printf("read %zu bytes\n", bytes);
close(fd);
}
else {
printf("impossible to read %s\n", filename);
}
}
void write_file(char *filename) {
printf("write_file: %s\n", filename);
int fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
if (fd > 0) {
char buffer[] = "hello that's meeeeee";
size_t bytes = write(fd, buffer, sizeof buffer);
printf("wrote %zu bytes\n", bytes);
close(fd);
}
else {
printf("impossible to write %s\n", filename);
}
}
void unixsock_server(char *address) {
printf("unixsock_server: %s\n", address);
int ret;
int connection_socket;
int data_socket;
ssize_t r, w;
struct sockaddr_un name;
char buffer[BUFFER_SIZE];
/* Create local socket. */
connection_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (connection_socket == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&name, 0, sizeof(name));
/* Bind socket to socket name. */
name.sun_family = AF_UNIX;
strncpy(name.sun_path, address, sizeof(name.sun_path) - 1);
ret = bind(connection_socket, (const struct sockaddr *) &name, sizeof(name));
if (ret == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
ret = listen(connection_socket, 20);
if (ret == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
/* Wait for incoming connection. */
data_socket = accept(connection_socket, NULL, NULL);
if (data_socket == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
/* Wait for a data packet. */
r = read(data_socket, buffer, sizeof(buffer));
if (r == -1) {
perror("read");
exit(EXIT_FAILURE);
}
/* Ensure buffer is 0-terminated. */
buffer[sizeof(buffer) - 1] = 0;
printf("received: %s\n", buffer);
/* Send result. */
sprintf(buffer, "hello back");
printf("sending: %s\n", buffer);
w = write(data_socket, buffer, sizeof(buffer));
if (w == -1) {
perror("write");
exit(EXIT_FAILURE);
}
/* Close socket. */
printf("closing\n");
close(data_socket);
close(connection_socket);
/* Unlink the socket. */
printf("unlink: %s\n", address);
unlink(address);
}
void unixsock_client(char *address) {
printf("unixsock_client: %s\n", address);
int ret;
int data_socket;
ssize_t r, w;
struct sockaddr_un addr;
char buffer[BUFFER_SIZE];
/* Create local socket. */
data_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (data_socket == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&addr, 0, sizeof(addr));
/* Connect socket to socket address. */
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, address, sizeof(addr.sun_path) - 1);
printf("address is: %s\n", addr.sun_path);
ret = connect(data_socket, (const struct sockaddr *) &addr, sizeof(addr));
if (ret == -1) {
fprintf(stderr, "server is down\n");
exit(EXIT_FAILURE);
}
/* Send data. */
w = write(data_socket, "hello", 6);
if (w == -1) {
perror("write");
exit(EXIT_FAILURE);
}
/* Receive data. */
r = read(data_socket, buffer, sizeof(buffer));
if (r == -1) {
perror("read");
exit(EXIT_FAILURE);
}
/* Ensure buffer is 0-terminated. */
buffer[sizeof(buffer) - 1] = 0;
printf("received: %s\n", buffer);
/* Close socket. */
printf("closing\n");
close(data_socket);
}
void network_client(char *address, char *port) {
printf("network_client: @%s port %s\n", address, port);
int sfd, s;
char buffer[BUFFER_SIZE];
ssize_t nread;
struct addrinfo hints;
struct addrinfo *result, *rp;
/* Obtain address(es) matching host/port. */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(address, port, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1) continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) break;
close(sfd);
}
freeaddrinfo(result); /* No longer needed */
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
snprintf(buffer, 6, "hello");
if (write(sfd, buffer, 6) != 6) {
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(sfd, buffer, BUFFER_SIZE);
if (nread == -1) {
perror("read");
exit(EXIT_FAILURE);
}
printf("received %zd bytes: %s\n", nread, buffer);
}
void network_server(char *port) {
printf("network_server: %s\n", port);
int sfd, s;
char buffer[BUFFER_SIZE];
ssize_t nread;
socklen_t peer_addrlen;
struct addrinfo hints;
struct addrinfo *result, *rp;
struct sockaddr_storage peer_addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, port, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1) continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break;
close(sfd);
}
freeaddrinfo(result); /* No longer needed */
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
exit(EXIT_FAILURE);
}
/* Read a single datagram and echo it back to sender. */
char host[NI_MAXHOST], service[NI_MAXSERV];
peer_addrlen = sizeof(peer_addr);
nread = recvfrom(sfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *) &peer_addr, &peer_addrlen);
if (nread == -1) {
fprintf(stderr, "nread == -1\n");
exit(EXIT_FAILURE);
}
s = getnameinfo((struct sockaddr *) &peer_addr, peer_addrlen, host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICSERV);
if (s == 0) printf("Received %zd bytes from %s:%s\n", nread, host, service);
else fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));
printf("sending it back to sender\n");
if (sendto(sfd, buffer, nread, 0, (struct sockaddr *) &peer_addr, peer_addrlen) != nread) {
fprintf(stderr, "Error sending response\n");
}
}
void execute(char *filename) {
printf("execute: %s\n", filename);
pid_t cpuid = 0;
cpuid = fork();
if (cpuid == -1) {
fprintf(stderr, "fork failed\n");
return;
}
if (cpuid == 0) {
printf("I'm the child\n");
int ret = execl(filename, "hello", NULL);
if (ret == -1) {
printf("failed to exec %s\n", filename);
exit(EXIT_FAILURE);
}
printf("wait, what? probably failed to exec %s\n", filename);
exit(EXIT_FAILURE);
}
else {
printf("I'm the parent\n");
int status;
wait(&status);
printf("child exited with %d\n", status);
}
}
void usage(void) {
printf("usage: paintest r /path/to/file w /path/to/file n example.com:8080 u /unix/socket/path\n");
}
int main(int argc, char **argv)
{
int i = 1;
if(argc < 2) {
usage();
exit (EXIT_SUCCESS);
}
while (i < argc) {
if (memcmp(argv[i], "r", 1) == 0) { read_file(argv[i+1]); }
else if (memcmp(argv[i], "w", 1) == 0) { write_file(argv[i+1]); }
else if (memcmp(argv[i], "n", 1) == 0) { network_client(argv[i+1], argv[i+2]); i++; }
else if (memcmp(argv[i], "N", 1) == 0) { network_server(argv[i+1]); }
else if (memcmp(argv[i], "u", 1) == 0) { unixsock_client(argv[i+1]); }
else if (memcmp(argv[i], "U", 1) == 0) { unixsock_server(argv[i+1]); }
else if (memcmp(argv[i], "x", 1) == 0) { execute(argv[i+1]); }
else if (memcmp(argv[i], "h", 1) == 0) { usage(); }
i += 2;
}
return 0;
}

119
c/poll-timing.c Normal file
View file

@ -0,0 +1,119 @@
#include <stdio.h>
//#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
// For poll-related stuff.
#include <fcntl.h>
#include <poll.h>
#include <sys/types.h>
#include <unistd.h>
#define err(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define BILLION 1000000000L
#define MILLION 1000000L
#define THOUSAND 1000L
void get_time_ts(struct timespec *t0) {
if (clock_gettime(CLOCK_REALTIME, t0) == -1) {
perror("clock_gettime");
exit(1);
}
}
long long duration_ns(struct timespec t0, struct timespec t1) {
return ((t1.tv_sec - t0.tv_sec)*BILLION) + (t1.tv_nsec - t0.tv_nsec);
}
void print_time_ns(long long time) {
printf("%llds %lldms %lldµ %lldns\n"
, time/BILLION
, (time/MILLION)%THOUSAND
, (time/THOUSAND)%THOUSAND
, time%THOUSAND
);
}
int main(int argc, char *argv[])
{
// Time-related structures.
struct timespec t0, t1;
int ready;
char buf[10];
nfds_t num_open_fds, nfds;
ssize_t s;
struct pollfd *pfds;
if (argc < 2) {
fprintf(stderr, "Usage: %s file...\n", argv[0]);
exit(EXIT_FAILURE);
}
num_open_fds = nfds = argc - 1;
pfds = calloc(nfds, sizeof(struct pollfd));
if (pfds == NULL)
err("malloc");
/* Open each file on command line, and add it to 'pfds' array. */
for (nfds_t j = 0; j < nfds; j++) {
pfds[j].fd = open(argv[j + 1], O_RDONLY);
if (pfds[j].fd == -1)
err("open");
printf("Opened \"%s\" on fd %d\n", argv[j + 1], pfds[j].fd);
pfds[j].events = POLLIN;
}
/* Keep calling poll() as long as at least one file descriptor is
open. */
while (num_open_fds > 0) {
printf("About to poll()\n");
get_time_ts(&t0);
ready = poll(pfds, nfds, -1);
get_time_ts(&t1);
if (ready == -1)
err("poll");
printf("polling duration: ");
print_time_ns(duration_ns(t0, t1));
printf("Ready: %d\n", ready);
/* Deal with array returned by poll(). */
for (nfds_t j = 0; j < nfds; j++) {
if (pfds[j].revents != 0) {
printf(" fd=%d; events: %s%s%s\n", pfds[j].fd,
(pfds[j].
revents & POLLIN) ? "POLLIN " : "",
(pfds[j].
revents & POLLHUP) ? "POLLHUP " : "",
(pfds[j].
revents & POLLERR) ? "POLLERR " : "");
if (pfds[j].revents & POLLIN) {
s = read(pfds[j].fd, buf, sizeof(buf));
if (s == -1)
err("read");
printf(" read %zd bytes: %.*s\n",
s, (int)s, buf);
} else { /* POLLERR | POLLHUP */
printf(" closing fd %d\n",
pfds[j].fd);
if (close(pfds[j].fd) == -1)
err("close");
num_open_fds--;
}
}
}
}
printf("All file descriptors closed; bye\n");
exit(EXIT_SUCCESS);
}

57
c/time-measuring.c Normal file
View file

@ -0,0 +1,57 @@
#include <stdio.h>
//#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#define BILLION 1000000000L
#define MILLION 1000000L
#define THOUSAND 1000L
void get_time_ts(struct timespec *t0) {
if (clock_gettime(CLOCK_REALTIME, t0) == -1) {
perror("clock_gettime");
exit(1);
}
}
long long duration_ns(struct timespec t0, struct timespec t1) {
return ((t1.tv_sec - t0.tv_sec)*BILLION) + (t1.tv_nsec - t0.tv_nsec);
}
void print_time_ns(long long time) {
printf("%llds %lldms %lldµ %lldns\n"
, time/BILLION
, (time/MILLION)%THOUSAND
, (time/THOUSAND)%THOUSAND
, time%THOUSAND
);
}
int main (int argc, char** argv) {
struct timespec t0, t1;
get_time_ts(&t0);
int i = 0;
while (i < 10000) { i++; }
get_time_ts(&t1);
long long time = duration_ns(t0, t1);
print_time_ns(time);
return 0;
}
/* // For limited precision: timeval structure + gettimeofday function.
struct timeval t0, t1;
gettimeofday (&t0, NULL);
int i = 0;
while (i < 10000) { i++; }
gettimeofday (&t1, NULL);
printf("%ld ms\n", (t1.tv_sec - t0.tv_sec)*BILLION + (t1.tv_usec - t0.tv_usec));
*/

24
mk/audio.mk Normal file
View file

@ -0,0 +1,24 @@
# -prf "asendcmd=0.0 afftdn sn start,asendcmd=2 afftdn sn stop,afftdn=nr=10:nf=-40" \
SRC ?= tmp.opus
record-audio:
record-audio.sh $(SRC)
record-video:
record-video.sh $(SRC)
OUTPUT ?= tmp.opus
extract-audio:
ffmpeg -i $(SRC) $(OUTPUT)
normalize:
@# f: force overriding previous files
@# koa: keep original audio
@# pr: progress
@# -nt {ebu,rms,peak}: normalization type (default is "ebu", which is what we want)
@# -t TARGET_LEVEL: target db/LUFS level (default is "-23")
@# (for EBU) -lrt LOUDNESS_RANGE_TARGET: max audio range (default is "7")
@#
@# ffmpeg options
@# -c:a AUDIO_CODEC
ffmpeg-normalize -f -koa -pr -c:a libopus $(SRC)

View file

@ -0,0 +1,72 @@
ZRAMDIR ?= /tmp/zram
# Currently not working with alpine linux.
zram: zram-mkdir zram-module zram-create zram-format zram-mount
unzram: zram-umount zram-free
btrzram: zram-mkdir zram-module zram-create btrzram-format zram-mount
zram-mkdir:; -mkdir $(ZRAMDIR) 2>/dev/null
zram-module:; modprobe zram
zram-create:; zramctl --find --size 50000M -a zstd
# -b 2048 block size, cannot be used (mkfs.ext4 wants 4k blocks minimum)
# -N xxx nb of inodes
# -i xxx higher inode ratio
zram-format:; mkfs.ext4 -N 50000000 /dev/zram0
zram-mount:; mount /dev/zram0 $(ZRAMDIR)
zram-umount:; -umount $(ZRAMDIR)
zram-free:; -zramctl -r /dev/zram0
### BTRFS
BTRFS_DIR ?= /tmp/btrfs
BTRFS_IMG ?= /tmp/btrfs.img
BTRFS_SIZ ?= 5000
BTRFS_SECTOR_SIZE ?= 4096
BTRFS_NODE_SIZE ?= 4096 # Minimal accepted value.
BTRFS_LOOP ?= /dev/loop100
BTRFS_COMP ?= zstd:8
# apt install btrfs-progs
btrfs: btrfs-mkdir btrfs-create btrfs-loop btrfs-format btrfs-mount btrfs-chown
btrfs-mkdir:; [ ! -d $(BTRFS_DIR) ] && mkdir $(BTRFS_DIR) 2>/dev/null || :
btrfs-create:
[ ! -f $(BTRFS_IMG) ] && su karchnu -c "dd if=/dev/zero of=$(BTRFS_IMG) bs=1M count=$(BTRFS_SIZ)" || :
btrfs-loop:; losetup --sector-size $(BTRFS_SECTOR_SIZE) $(BTRFS_LOOP) $(BTRFS_IMG)
btrfs-format:; mkfs.btrfs -s $(BTRFS_SECTOR_SIZE) -n $(BTRFS_NODE_SIZE) -L BTRDATA $(BTRFS_LOOP)
btrfs-mount:; mount -o compress=$(BTRFS_COMP) $(BTRFS_LOOP) $(BTRFS_DIR)
btrfs-chown:; chown karchnu $(BTRFS_DIR)
unbtrfs: btrfs-umount btrfs-unloop btrfs-rm
btrfs-unloop:; [ -b $(BTRFS_LOOP) ] && losetup -d $(BTRFS_LOOP) || :
btrfs-umount:; umount $(BTRFS_DIR)
btrfs-rm:; rm $(BTRFS_IMG)
### EXT4
EXT4_DIR ?= /tmp/ext4
EXT4_IMG ?= /tmp/ext4.img
EXT4_SIZ ?= 5000
EXT4_SECTOR_SIZE ?= 1024
EXT4_INODE_NUMBER ?= 10000000
#EXT4_SECTOR_SIZE ?= 4096
#EXT4_INODE_NUMBER ?= 1500000
EXT4_INODE_SIZE ?= 256
EXT4_LOOP ?= /dev/loop1000
ext4: ext4-mkdir ext4-create ext4-loop ext4-format ext4-mount ext4-chown
ext4-mkdir:; [ ! -d $(EXT4_DIR) ] && mkdir $(EXT4_DIR) 2>/dev/null || :
ext4-create:
[ ! -f $(EXT4_IMG) ] && su karchnu -c "dd if=/dev/zero of=$(EXT4_IMG) bs=1M count=$(EXT4_SIZ)" || :
ext4-loop:; losetup --sector-size $(EXT4_SECTOR_SIZE) $(EXT4_LOOP) $(EXT4_IMG)
ext4-format:; mkfs.ext4 -b $(EXT4_SECTOR_SIZE) -I $(EXT4_INODE_SIZE) -N $(EXT4_INODE_NUMBER) -L EXT4DATA $(EXT4_LOOP)
ext4-mount:; mount $(EXT4_LOOP) $(EXT4_DIR)
ext4-chown:; chown karchnu $(EXT4_DIR)
unext4: ext4-umount ext4-unloop ext4-rm
ext4-unloop:; [ -b $(EXT4_LOOP) ] && losetup -d $(EXT4_LOOP) || :
ext4-umount:; umount $(EXT4_DIR) || :
ext4-rm:; rm $(EXT4_IMG) || :

8
mk/random.mk Normal file
View file

@ -0,0 +1,8 @@
APP ?= my-app
strace-pid:
@# strace an already running application
sudo strace -p $$(pidof $(APP))
strace:
@# --decode-fds = get file names
sudo strace --decode-fds -e desc,network $(APP)

44
mk/zram.mk Normal file
View file

@ -0,0 +1,44 @@
PDNSDIR ?= /tmp/zram
# Currently not working with alpine linux.
zram: mkdir zram-module zram-create zram-format zram-mount
unzram: zram-umount zram-free
btrzram: mkdir zram-module zram-create btrzram-format zram-mount
mkdir:; -mkdir $(PDNSDIR) 2>/dev/null
zram-module:; modprobe zram
zram-create:; zramctl --find --size 50000M -a zstd
# -b 2048 block size, cannot be used (mkfs.ext4 wants 4k blocks minimum)
# -N xxx nb of inodes
# -i xxx higher inode ratio
zram-format:; mkfs.ext4 -N 50000000 /dev/zram0
zram-mount:; mount /dev/zram0 $(PDNSDIR)
zram-umount:; -umount $(PDNSDIR)
zram-free:; -zramctl -r /dev/zram0
BTRFS_DIR ?= /tmp/btrfs
BTRFS_IMG ?= /tmp/btrfs.img
BTRFS_SIZ ?= 5000
BTRFS_SECTOR_SIZE ?= 4096
BTRFS_NODE_SIZE ?= 4096 # Minimal accepted value.
BTRFS_LOOP ?= /dev/loop100
BTRFS_COMP ?= zstd:8
# apt install btrfs-progs
btrfs: btrfs-mkdir btrfs-create btrfs-loop btrfs-format btrfs-mount btrfs-chown
btrfs-mkdir:; [ ! -d $(BTRFS_DIR) ] && mkdir $(BTRFS_DIR) 2>/dev/null || :
btrfs-create:
[ ! -f $(BTRFS_IMG) ] && su karchnu -c "dd if=/dev/zero of=$(BTRFS_IMG) bs=1M count=$(BTRFS_SIZ)" || :
btrfs-loop:; losetup --sector-size $(BTRFS_SECTOR_SIZE) $(BTRFS_LOOP) $(BTRFS_IMG)
btrfs-format:; mkfs.btrfs -s $(BTRFS_SECTOR_SIZE) -n $(BTRFS_NODE_SIZE) -L BTRDATA $(BTRFS_LOOP)
btrfs-mount:; mount -o compress=$(BTRFS_COMP) $(BTRFS_LOOP) $(BTRFS_DIR)
btrfs-chown:; chown karchnu $(BTRFS_DIR)
unbtrfs: btrfs-umount btrfs-unloop btrfs-rm
btrfs-unloop:; [ -b $(BTRFS_LOOP) ] && losetup -d $(BTRFS_LOOP) || :
btrfs-umount:; umount $(BTRFS_DIR)
btrfs-rm:; rm $(BTRFS_IMG)