-
Notifications
You must be signed in to change notification settings - Fork 881
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add bladerf fpga images to snap (#799)
fix #798
- Loading branch information
Showing
3 changed files
with
331 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
// Source: https://github.com/snapcore/snapcraft-preloads/blob/master/semaphores/preload-semaphores.c | ||
|
||
#ifndef _GNU_SOURCE | ||
#define _GNU_SOURCE | ||
#endif | ||
|
||
/* | ||
* $ gcc -Wall -fPIC -shared -o mylib.so ./lib.c -ldl | ||
* $ LD_PRELOAD=./mylib.so ... | ||
*/ | ||
|
||
#include <dlfcn.h> | ||
|
||
#include <sys/types.h> | ||
#include <stdio.h> | ||
#include <semaphore.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <errno.h> | ||
#include <sys/stat.h> | ||
#include <unistd.h> | ||
#include <fcntl.h> | ||
#include <stdarg.h> | ||
#include <limits.h> | ||
|
||
static sem_t *(*original_sem_open) (const char *, int, ...); | ||
static int (*original_sem_unlink) (const char *); | ||
|
||
// Format is: 'sem.snap.SNAP_NAME.<something>'. So: 'sem.snap.' + '.' = 10 | ||
#define MAX_NAME_SIZE NAME_MAX - 10 | ||
#define SHM_DIR "/dev/shm" | ||
|
||
void debug(char *s, ...) | ||
{ | ||
if (secure_getenv("SEMWRAP_DEBUG")) { | ||
va_list va; | ||
va_start(va, s); | ||
fprintf(stderr, "SEMWRAP: "); | ||
vfprintf(stderr, s, va); | ||
va_end(va); | ||
fprintf(stderr, "\n"); | ||
} | ||
} | ||
|
||
const char *get_snap_name(void) | ||
{ | ||
const char *snapname = getenv("SNAP_INSTANCE_NAME"); | ||
if (!snapname) { | ||
snapname = getenv("SNAP_NAME"); | ||
} | ||
if (!snapname) { | ||
debug("SNAP_NAME and SNAP_INSTANCE_NAME not set"); | ||
} | ||
return snapname; | ||
} | ||
|
||
int rewrite(const char *snapname, const char *name, char *rewritten, | ||
size_t rmax) | ||
{ | ||
if (strlen(snapname) + strlen(name) > MAX_NAME_SIZE) { | ||
errno = ENAMETOOLONG; | ||
return -1; | ||
} | ||
|
||
const char *tmp = name; | ||
if (tmp[0] == '/') { | ||
// If specified with leading '/', just strip it to avoid | ||
// having to mkdir(), etc | ||
tmp = &name[1]; | ||
} | ||
|
||
int n = snprintf(rewritten, rmax, "snap.%s.%s", snapname, tmp); | ||
if (n < 0 || n >= rmax) { | ||
fprintf(stderr, "snprintf truncated\n"); | ||
return -1; | ||
} | ||
rewritten[rmax-1] = '\0'; | ||
|
||
return 0; | ||
} | ||
|
||
sem_t *sem_open(const char *name, int oflag, ...) | ||
{ | ||
mode_t mode; | ||
unsigned int value; | ||
|
||
debug("sem_open()"); | ||
debug("requested name: %s", name); | ||
|
||
// lookup the libc's sem_open() if we haven't already | ||
if (!original_sem_open) { | ||
dlerror(); | ||
original_sem_open = dlsym(RTLD_NEXT, "sem_open"); | ||
if (!original_sem_open) { | ||
debug("could not find sem_open in libc"); | ||
return SEM_FAILED; | ||
} | ||
dlerror(); | ||
} | ||
|
||
// mode and value must be set with O_CREAT | ||
va_list argp; | ||
va_start(argp, oflag); | ||
if (oflag & O_CREAT) { | ||
mode = va_arg(argp, mode_t); | ||
value = va_arg(argp, unsigned int); | ||
if (value > SEM_VALUE_MAX) { | ||
errno = EINVAL; | ||
return SEM_FAILED; | ||
} | ||
} | ||
va_end(argp); | ||
|
||
const char *snapname = get_snap_name(); | ||
|
||
// just call libc's sem_open() if snapname not set | ||
if (!snapname) { | ||
if (oflag & O_CREAT) { | ||
return original_sem_open(name, oflag, mode, value); | ||
} | ||
return original_sem_open(name, oflag); | ||
} | ||
|
||
// Format the rewritten name | ||
char rewritten[MAX_NAME_SIZE+1]; | ||
if (rewrite(snapname, name, rewritten, MAX_NAME_SIZE + 1) != 0) { | ||
return SEM_FAILED; | ||
} | ||
debug("rewritten name: %s", rewritten); | ||
|
||
if (oflag & O_CREAT) { | ||
// glibc's sem_open with O_CREAT will create a file in /dev/shm | ||
// by creating a tempfile, initializing it, hardlinking it and | ||
// unlinking the tempfile. We: | ||
// 1. create a temporary file in /dev/shm with rewritten path | ||
// as the template and the specified mode | ||
// 2. initializing a sem_t with sem_init | ||
// 3. writing the initialized sem_t to the temporary file using | ||
// sem_open()s declared value. We used '1' for pshared since | ||
// that is how glibc sets up a named semaphore | ||
// 4. close the temporary file | ||
// 5. hard link the temporary file to the rewritten path. If | ||
// O_EXCL is not specified, ignore EEXIST and just cleanup | ||
// as per documented behavior in 'man sem_open'. If O_EXCL | ||
// is specified and file exists, exit with error. If link is | ||
// successful, cleanup. | ||
// 6. call glibc's sem_open() without O_CREAT|O_EXCL | ||
// | ||
// See glibc's fbtl/sem_open.c for more details | ||
|
||
// First, calculate the requested path | ||
char path[PATH_MAX] = { 0 }; | ||
// /sem. + '/0' = 14 | ||
int max_path_size = strlen(SHM_DIR) + strlen(rewritten) + 6; | ||
if (max_path_size >= PATH_MAX) { | ||
// Should never happen since PATH_MAX should be much | ||
// larger than NAME_MAX, but be defensive. | ||
errno = ENAMETOOLONG; | ||
return SEM_FAILED; | ||
} | ||
int n = snprintf(path, max_path_size, "%s/sem.%s", SHM_DIR, | ||
rewritten); | ||
if (n < 0 || n >= max_path_size) { | ||
errno = ENAMETOOLONG; | ||
return SEM_FAILED; | ||
} | ||
path[max_path_size-1] = '\0'; | ||
|
||
// Then calculate the template path | ||
char tmp[PATH_MAX] = { 0 }; | ||
n = snprintf(tmp, PATH_MAX, "%s/%s.XXXXXX", SHM_DIR, | ||
rewritten); | ||
if (n < 0 || n >= PATH_MAX) { | ||
errno = ENAMETOOLONG; | ||
return SEM_FAILED; | ||
} | ||
tmp[PATH_MAX-1] = '\0'; | ||
|
||
// Next, create a temporary file | ||
int fd = mkstemp(tmp); | ||
if (fd < 0) { | ||
return SEM_FAILED; | ||
} | ||
debug("tmp name: %s", tmp); | ||
|
||
// Update the temporary file to have the requested mode | ||
if (fchmod(fd, mode) < 0) { | ||
close(fd); | ||
unlink(tmp); | ||
return SEM_FAILED; | ||
} | ||
|
||
// Then write out an empty semaphore and set the initial value. | ||
// We use '1' for pshared since that is how glibc sets up the | ||
// semaphore (see glibc's fbtl/sem_open.c) | ||
sem_t initsem; | ||
sem_init(&initsem, 1, value); | ||
if (write(fd, &initsem, sizeof(sem_t)) < 0) { | ||
close(fd); | ||
unlink(tmp); | ||
return SEM_FAILED; | ||
} | ||
close(fd); | ||
|
||
// Then link the file into place. If the target exists and | ||
// O_EXCL was not specified, just cleanup and proceed to open | ||
// the existing file as per documented behavior in 'man | ||
// sem_open'. | ||
int existed = 0; | ||
if (link(tmp, path) < 0) { | ||
// Note: snapd initially didn't allow 'l' in its | ||
// policy so we first try with link() since it is | ||
// race-free but fallback to rename() if necessary. | ||
if (errno == EACCES || errno == EPERM) { | ||
fprintf(stderr, "sem_open() wrapper: hard linking tempfile denied. Falling back to rename()\n"); | ||
if (rename(tmp, path) < 0) { | ||
unlink(tmp); | ||
return SEM_FAILED; | ||
} | ||
} else if (oflag & O_EXCL || errno != EEXIST) { | ||
unlink(tmp); | ||
return SEM_FAILED; | ||
} | ||
existed = 1; | ||
} | ||
unlink(tmp); | ||
|
||
// Then call sem_open() on the created file, stripping out the | ||
// O_CREAT|O_EXCL since we just created it | ||
sem_t *sem = original_sem_open(rewritten, | ||
oflag & ~(O_CREAT | O_EXCL)); | ||
if (sem == SEM_FAILED) { | ||
if (!existed) { | ||
unlink(path); | ||
} | ||
return SEM_FAILED; | ||
} | ||
|
||
return sem; | ||
} else { | ||
// without O_CREAT, just call sem_open with rewritten | ||
return original_sem_open(rewritten, oflag); | ||
} | ||
|
||
return SEM_FAILED; | ||
} | ||
|
||
// sem_unlink | ||
int sem_unlink(const char *name) | ||
{ | ||
debug("sem_unlink()"); | ||
debug("requested name: %s", name); | ||
|
||
// lookup the libc's sem_unlink() if we haven't already | ||
if (!original_sem_unlink) { | ||
dlerror(); | ||
original_sem_unlink = dlsym(RTLD_NEXT, "sem_unlink"); | ||
if (!original_sem_unlink) { | ||
debug("could not find sem_unlink in libc"); | ||
return -1; | ||
} | ||
dlerror(); | ||
} | ||
|
||
const char *snapname = get_snap_name(); | ||
|
||
// just call libc's sem_unlink() if snapname not set | ||
if (!snapname) { | ||
return original_sem_unlink(name); | ||
} | ||
|
||
// Format the rewritten name | ||
char rewritten[MAX_NAME_SIZE+1]; | ||
if (rewrite(snapname, name, rewritten, MAX_NAME_SIZE + 1) != 0) { | ||
return -1; | ||
} | ||
debug("rewritten name: %s", rewritten); | ||
|
||
return original_sem_unlink(rewritten); | ||
} |
Oops, something went wrong.