/* Remove Pulseaudio library reference
*
* Copyright (C) 2016 kspflo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
// Build using: gcc -std=gnu99 -O2 -o pulsenomore pulsenomore.c -ldl
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LIBPULSE_SIMPLE "libpulse-simple.so.0"
#ifdef __NR_memfd_create
static inline int memfd_create(const char *name, unsigned int flags) {
return syscall(__NR_memfd_create, name, flags);
}
#else
#error "memfd_create syscall missing!"
#endif
static int check_pulseaudio_running(void) {
void *h;
pid_t pid;
int (*pa_pid_file_check_running)(pid_t *, const char *), running;
if(!(h = dlopen(LIBPULSE_SIMPLE, RTLD_LAZY))) {
warnx("Failed to resolve " LIBPULSE_SIMPLE);
return 0;
}
if(!(pa_pid_file_check_running = dlsym(h, "pa_pid_file_check_running")))
errx(1, "Failed to resolve symbol pa_pid_file_check_running");
running = (pa_pid_file_check_running(&pid, "pulseaudio") < 0) ? 0 : 1;
dlclose(h);
return running;
}
int main(int argc, char **argv) {
int fd, mfd;
char **args, *mem, *p;
ssize_t s;
struct stat stbuf;
if(argc < 2)
errx(1, "Usage: %s [ ... ]", argv[0]);
args = malloc(sizeof(char *) * argc);
if(!args)
err(1, "Failed to allocate argument vector");
for(int i = 1; i < argc; ++i)
args[i - 1] = strdup(argv[i]);
args[argc - 1] = NULL;
if(check_pulseaudio_running()) {
warnx("Pulseaudio is running");
execv(argv[1], args);
err(1, "Failed to exec '%s'", argv[1]);
}
else {
warnx("Pulseaudio is NOT running");
if((fd = open(argv[1], O_RDONLY | O_CLOEXEC)) < 0)
err(1, "Failed to open executable '%s'", argv[1]);
if(fstat(fd, &stbuf) < 0)
err(1, "Failed to stat executable");
if((mfd = memfd_create(argv[1], MFD_CLOEXEC)) < 0)
err(1, "Failed to create memfd");
if(ftruncate(mfd, stbuf.st_size) < 0)
err(1, "Failed to truncate memfd");
if((p = mem = mmap(NULL, stbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0)) == MAP_FAILED)
err(1, "Failed to mmap memfd");
while((s = read(fd, p, 64 * 1024 * 1024)) > 0)
p += s;
if(s < 0)
err(1, "Failed to load executable into memory");
if((p = memmem(mem, stbuf.st_size, LIBPULSE_SIMPLE, strlen(LIBPULSE_SIMPLE))) != NULL) {
strcpy(p, "/dev/null");
p += strlen("/dev/null") + 1;
while(*p)
*p++ = '\0';
warnx(LIBPULSE_SIMPLE " reference replaced");
}
else
warnx(LIBPULSE_SIMPLE " reference not found");
munmap(mem, stbuf.st_size);
fexecve(mfd, args, environ);
err(1, "Failed to exec '%s'", argv[1]);
}
}