Skip to content

Instantly share code, notes, and snippets.

@lucaswerkmeister
Last active March 22, 2018 22:47
Show Gist options
  • Save lucaswerkmeister/b30822702afb73da8008a0b5b6ec6e22 to your computer and use it in GitHub Desktop.
Save lucaswerkmeister/b30822702afb73da8008a0b5b6ec6e22 to your computer and use it in GitHub Desktop.
Running the LilyPond development version inside a container

Containerized lilypond-git

I’ve lately taken up LilyPond transcription as a hobby, and recently I encountered a score that needed a feature from the LilyPond development version. I wanted to keep the stable version of LilyPond installed on my main system, so I created a container (machinectl clone Arch-Base Arch-lilypond-git) and built the lilypond-git package inside it. In order to build the score in that container, I then use the below Makefile and small wrapper program: lilypond-git invokes lilypond inside the Arch-lilypond-git container, with the current working directory bind-mounted into it, and afterwards adjusts the ownership of the generated PDF file (because lilypond was running as root inside the container). This would be easier to write as a shell script, of course, but Linux ignores the setuid bit on shell scripts, and I need this to be a setuid binary if I want to invoke it from Emacs’ compilation mode without entering my password for sudo all the time (which is extremely cumbersome anyways, since you have to use C-u M-x compile instead of just M-x compile, which doesn’t match the F12 keybinding).

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s FILE.ly FILE.pdf\n", argv[0]);
return EXIT_FAILURE;
}
char *cwd = get_current_dir_name();
int child = fork();
if (child < 0) {
perror("fork");
return EXIT_FAILURE;
}
if (child == 0) {
return execlp("systemd-nspawn",
"systemd-nspawn",
"--quiet",
"-M",
"Arch-lilypond-git",
"--ephemeral",
"--read-only",
"--private-network",
"--bind",
cwd,
"--chdir",
cwd,
"lilypond",
argv[1],
(char *)NULL);
} else {
free(cwd);
int wstatus, exitstatus = -1;
do {
pid_t w = waitpid(child, &wstatus, 0);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(wstatus)) {
exitstatus = WEXITSTATUS(wstatus);
}
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
(void)chown(argv[2], getuid(), getgid());
return exitstatus >= 0 ? exitstatus : EXIT_FAILURE;
}
}
.PHONY: all
CFLAGS := -Wall -Wextra -Wpedantic -Werror
all: the-score.pdf
the-score.pdf: the-score.ly lilypond-git
./lilypond-git $< $@
# based on Make’s implicit rule, search for %: in make -p
lilypond-git: lilypond-git.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
sudo sh -c 'chown root $@ && chmod u+s $@'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment