blend/overlayfs-tools/sh.c

99 lines
3 KiB
C
Raw Permalink Normal View History

2023-04-25 06:14:01 -05:00
#define _GNU_SOURCE
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include "sh.h"
char * vars[NUM_VARS];
const char * var_names[NUM_VARS] = {
"LOWERDIR",
"UPPERDIR",
"MOUNTDIR",
"LOWERNEW",
"UPPERNEW",
};
int quote(const char *filename, FILE *output);
FILE* create_shell_script(char *tmp_path_buffer) {
int tmp_file = mkstemps(tmp_path_buffer, 3); // the 3 is for suffix length (".sh")
if (tmp_file < 0) { return NULL; }
fchmod(tmp_file, S_IRWXU); // chmod to 0700
FILE* f = fdopen(tmp_file, "w");
if (f == NULL) { return NULL; }
fprintf(f, "#!/usr/bin/env bash\n");
fprintf(f, "set -x\n");
time_t rawtime;
time (&rawtime);
fprintf(f, "# This shell script is generated by overlayfs-tools on %s\n", ctime (&rawtime));
for (int i=0; i < NUM_VARS; i++) {
if (vars[i]) {
fprintf(f, "%s=", var_names[i]);
if (quote(vars[i], f) < 0) { return NULL; }
if (fputc('\n', f) == EOF) { return NULL; }
}
}
// Non-empty *NEW vars make a backup copy and override *DIR vars
if (vars[LOWERNEW]) {
fprintf(f, "rm -rf \"$LOWERNEW\"\n");
fprintf(f, "cp -a \"$LOWERDIR\" \"$LOWERNEW\"\n");
fprintf(f, "LOWERDIR=");
if (quote(vars[LOWERNEW], f) < 0) { return NULL; }
if (fputc('\n', f) == EOF) { return NULL; }
}
if (vars[UPPERNEW]) {
fprintf(f, "rm -rf \"$UPPERNEW\"\n");
fprintf(f, "cp -a \"$UPPERDIR\" \"$UPPERNEW\"\n");
fprintf(f, "UPPERDIR=");
if (quote(vars[UPPERNEW], f) < 0) { return NULL; }
if (fputc('\n', f) == EOF) { return NULL; }
}
return f;
}
int quote(const char *filename, FILE *output) {
if (fputc('\'', output) == EOF) { return -1; }
for (const char *s = filename; *s != '\0'; s++) {
if (*s == '\'') {
if (fprintf(output, "'\"'\"'") < 0) { return -1; }
} else {
if (fputc(*s, output) == EOF) { return -1; }
}
}
if (fputc('\'', output) == EOF) { return -1; }
return 0;
}
int substitue(char what, const char *filename, FILE *output) {
int i;
for (i=0; i < NUM_VARS; i++)
if (vars[i] && var_names[i][0] == what)
break;
if (i == NUM_VARS) { return -1; }
// filename prefix must match the var value
int prefix = strlen(vars[i]);
if (strncmp(filename, vars[i], prefix)) { return -1; }
filename += prefix;
fprintf(output, "\"$%s\"", var_names[i]);
return quote(filename, output);
}
int command(FILE *output, const char *command_format, ...) {
va_list arg;
va_start(arg, command_format);
for (size_t i = 0; command_format[i] != '\0'; i++) {
if (command_format[i] == '%') {
const char *s = va_arg(arg, char *);
if (substitue(command_format[++i], s, output) < 0) { return -1; }
} else {
if (fputc(command_format[i], output) == EOF) { return -1; }
}
}
va_end(arg);
if (fputc('\n', output) == EOF) { return -1; }
return 0;
}