2022-05-28 16:07:59 +02:00
|
|
|
#include <stdio.h>
|
2022-05-22 09:55:04 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2022-05-28 16:07:59 +02:00
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/stat.h>
|
2022-05-22 09:55:04 +02:00
|
|
|
|
|
|
|
#include "error.h"
|
|
|
|
#include "utils.h"
|
|
|
|
|
2022-05-28 16:07:59 +02:00
|
|
|
char *program = NULL;
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-24 02:46:34 +02:00
|
|
|
int spawn_redirect(const void *arg)
|
|
|
|
{
|
2022-05-25 23:57:50 +02:00
|
|
|
int *fds = (int *)arg;
|
2022-05-24 02:46:34 +02:00
|
|
|
|
2022-05-25 23:57:50 +02:00
|
|
|
ERRCHK_RET(close(fds[0]) == -1, FUNCFAILED("close"), ERRNOS);
|
|
|
|
ERRCHK_RET(dup2(fds[1], fds[2]) == -1, FUNCFAILED("dup2"), ERRNOS);
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int spawn_wait(pid_t pid, int *exitcode)
|
|
|
|
{
|
|
|
|
int stat;
|
|
|
|
ERRCHK_RET(waitpid(pid, &stat, 0) == -1, FUNCFAILED("waitpid"), ERRNOS);
|
|
|
|
|
|
|
|
if (exitcode && WIFEXITED(stat))
|
|
|
|
*exitcode = WEXITSTATUS(stat);
|
2022-05-24 02:46:34 +02:00
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2022-05-22 09:55:04 +02:00
|
|
|
/*
|
|
|
|
* Call command
|
|
|
|
*
|
|
|
|
* If cpid is NULL, wait for the command to finish executing;
|
|
|
|
* otherwise store pid in cpid
|
2022-05-23 03:32:09 +02:00
|
|
|
*
|
2022-05-24 02:46:34 +02:00
|
|
|
* cfunc is a function to call when child process is created
|
2022-05-22 09:55:04 +02:00
|
|
|
*/
|
2022-05-24 02:46:34 +02:00
|
|
|
int spawn(char *args[], pid_t *cpid, int *exitcode, int (*cfunc)(const void *),
|
|
|
|
const void *carg)
|
2022-05-22 09:55:04 +02:00
|
|
|
{
|
|
|
|
if (exitcode)
|
|
|
|
*exitcode = -1;
|
|
|
|
|
|
|
|
pid_t pid = fork();
|
2022-05-24 02:27:07 +02:00
|
|
|
ERRCHK_RET(pid == -1, FUNCFAILED("fork"), ERRNOS);
|
2022-05-22 09:55:04 +02:00
|
|
|
|
|
|
|
/* Child process */
|
|
|
|
if (pid == 0) {
|
2022-05-24 02:46:34 +02:00
|
|
|
if (cfunc && (cfunc(carg) != OK))
|
|
|
|
exit(EXIT_FAILURE);
|
2022-05-23 03:32:09 +02:00
|
|
|
|
2022-05-22 09:55:04 +02:00
|
|
|
execvp(args[0], args);
|
2022-05-25 23:57:50 +02:00
|
|
|
if (errno == ENOENT)
|
|
|
|
exit(NOTEXIST_EC);
|
|
|
|
|
2022-05-24 02:27:07 +02:00
|
|
|
PRINTINTERR(FUNCFAILED("exec"), ERRNOS);
|
2022-05-22 09:55:04 +02:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2022-05-25 23:57:50 +02:00
|
|
|
if (cpid)
|
2022-05-22 09:55:04 +02:00
|
|
|
*cpid = pid;
|
|
|
|
|
2022-05-25 23:57:50 +02:00
|
|
|
if (exitcode)
|
|
|
|
ERRCHK_RET_OK(spawn_wait(pid, exitcode));
|
2022-05-22 09:55:04 +02:00
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2022-05-23 20:45:35 +02:00
|
|
|
int strcmpnull(char const *s1, char const *s2)
|
|
|
|
{
|
|
|
|
if (!s1 && !s2)
|
|
|
|
return 0;
|
|
|
|
else if (s1 && !s2)
|
|
|
|
return 1;
|
|
|
|
else if (!s1 && s2)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return strcmp(s1, s2);
|
|
|
|
}
|
|
|
|
|
2022-05-28 16:07:59 +02:00
|
|
|
int get_cache_dir(char *buf, size_t len, char *name)
|
|
|
|
{
|
|
|
|
char *home, *cache_d, cache_d_buf[FILENAME_MAX];
|
|
|
|
|
|
|
|
if (!(cache_d = getenv("XDG_CACHE_HOME"))) {
|
|
|
|
home = getenv("HOME");
|
|
|
|
ERRCHK_RET(!home, "HOME env var does not exist");
|
|
|
|
|
|
|
|
snprintf(cache_d_buf, LEN(cache_d_buf)-1, "%s/.cache", home);
|
|
|
|
cache_d = cache_d_buf;
|
|
|
|
}
|
|
|
|
|
2022-05-31 20:08:01 +02:00
|
|
|
snprintf(buf, len - 1, "%s/%s", cache_d, name);
|
2022-05-28 16:07:59 +02:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mkpath(char* file_path, mode_t mode)
|
|
|
|
{
|
|
|
|
for (char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) {
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
if (mkdir(file_path, mode) == -1) {
|
|
|
|
if (errno != EEXIST) {
|
|
|
|
*p = '/';
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*p = '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-05-22 09:55:04 +02:00
|
|
|
CharVec char_v_new(size_t cap)
|
|
|
|
{
|
|
|
|
CharVec v;
|
|
|
|
v.buf = NULL;
|
|
|
|
v.len = 0;
|
|
|
|
v.cap = cap;
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
void char_v_free(CharVec *v)
|
|
|
|
{
|
|
|
|
if (v->buf) {
|
|
|
|
free(v->buf);
|
|
|
|
v->buf = NULL;
|
|
|
|
v->len = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-28 19:31:09 +02:00
|
|
|
static void char_v_create(CharVec *v)
|
2022-05-22 09:55:04 +02:00
|
|
|
{
|
2022-05-28 19:31:09 +02:00
|
|
|
if (v->buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!(v->buf = malloc(v->cap * sizeof(*v->buf)))) {
|
|
|
|
PRINTINTERR(FUNCFAILED("malloc"), ERRNOS);
|
|
|
|
abort();
|
2022-05-22 09:55:04 +02:00
|
|
|
}
|
|
|
|
|
2022-05-28 19:31:09 +02:00
|
|
|
v->buf[0] = '\0';
|
|
|
|
v->len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void char_v_check_cap(CharVec *v, size_t len_inc)
|
|
|
|
{
|
|
|
|
void *new_buf;
|
|
|
|
size_t new_len = v->len + len_inc;
|
|
|
|
|
|
|
|
if (new_len < v->cap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (new_len >= v->cap)
|
2022-05-22 09:55:04 +02:00
|
|
|
v->cap *= 2;
|
2022-05-28 19:31:09 +02:00
|
|
|
|
|
|
|
if (!(new_buf = realloc(v->buf, v->cap * sizeof(*v->buf)))) {
|
|
|
|
free(v->buf);
|
|
|
|
PRINTINTERR(FUNCFAILED("realloc"), ERRNOS);
|
|
|
|
abort();
|
2022-05-22 09:55:04 +02:00
|
|
|
}
|
|
|
|
|
2022-05-28 19:31:09 +02:00
|
|
|
v->buf = new_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void char_v_append(CharVec *v, char c)
|
|
|
|
{
|
|
|
|
char_v_create(v);
|
|
|
|
char_v_check_cap(v, 1);
|
|
|
|
|
2022-05-22 09:55:04 +02:00
|
|
|
v->buf[v->len - 1] = c;
|
|
|
|
v->buf[v->len] = '\0';
|
|
|
|
v->len++;
|
|
|
|
}
|
2022-05-28 19:31:09 +02:00
|
|
|
|
|
|
|
void char_v_append_str(CharVec *v, char *s)
|
|
|
|
{
|
|
|
|
size_t len = strlen(s);
|
|
|
|
|
|
|
|
char_v_create(v);
|
|
|
|
char_v_check_cap(v, len);
|
|
|
|
|
|
|
|
memcpy(v->buf + v->len * sizeof(*v->buf), s, len + 1);
|
|
|
|
v->len += len;
|
|
|
|
}
|