2024-06-20 00:34:32 +00:00
|
|
|
#include "../include/util.h"
|
2024-06-22 04:03:17 +00:00
|
|
|
#include "../include/error.h"
|
2024-06-22 22:55:01 +00:00
|
|
|
#include "../include/types.h"
|
2024-06-26 19:33:20 +00:00
|
|
|
|
|
|
|
#include <archive.h>
|
2024-06-28 17:51:56 +00:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <errno.h>
|
2024-06-26 19:33:20 +00:00
|
|
|
#include <linux/limits.h>
|
2024-07-11 04:31:36 +00:00
|
|
|
#include <openssl/evp.h>
|
2024-06-20 00:34:32 +00:00
|
|
|
#include <stdarg.h>
|
2024-06-20 22:36:56 +00:00
|
|
|
#include <stdio.h>
|
2024-06-20 00:34:32 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2024-06-28 17:51:56 +00:00
|
|
|
void pdebug(const char *func, const char *fmt, ...) {
|
|
|
|
if (LM_DEBUG != 1)
|
2024-06-20 00:34:32 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
2024-06-28 17:51:56 +00:00
|
|
|
printf("[libmp debug] %s: ", func);
|
2024-06-20 00:34:32 +00:00
|
|
|
vprintf(fmt, args);
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool eq(char *s1, char *s2) {
|
|
|
|
if (NULL == s1 || NULL == s2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (strlen(s1) != strlen(s2))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return strcmp(s1, s2) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_letter(char c) {
|
|
|
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_digit(char c) {
|
|
|
|
return c >= '0' && c <= '9';
|
|
|
|
}
|
|
|
|
|
|
|
|
bool contains(char *str, char s) {
|
|
|
|
for (char *c = str; *c != 0; c++)
|
|
|
|
if (*c == s)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2024-06-22 04:03:17 +00:00
|
|
|
|
2024-06-22 22:55:01 +00:00
|
|
|
bool parse_host(char *addr, char *host, uint16_t *port) {
|
2024-06-22 04:03:17 +00:00
|
|
|
char *save = NULL, *portc = NULL;
|
2024-06-22 22:55:01 +00:00
|
|
|
int portint = 0;
|
2024-06-22 04:03:17 +00:00
|
|
|
|
2024-06-22 22:55:01 +00:00
|
|
|
if ((host = strtok_r(addr, ":", &save)) == NULL) {
|
2024-06-22 04:03:17 +00:00
|
|
|
lm_error_set(LM_ERR_BadHost);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-06-22 22:55:01 +00:00
|
|
|
if ((portc = strtok_r(NULL, ":", &save)) == NULL) {
|
2024-06-22 04:03:17 +00:00
|
|
|
*port = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
portint = atoi(portc);
|
2024-06-22 22:55:01 +00:00
|
|
|
if (portint <= 0 || portint > UINT16_MAX) {
|
2024-06-22 04:03:17 +00:00
|
|
|
lm_error_set(LM_ERR_BadPort);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*port = portint;
|
|
|
|
return true;
|
|
|
|
}
|
2024-06-22 22:55:01 +00:00
|
|
|
|
|
|
|
bool copy_to_buffer(void *buffer, void *src, size_t size, ssize_t *total, ssize_t *used) {
|
|
|
|
if (*used + size > *total)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (*used == 0)
|
|
|
|
bzero(buffer, *total);
|
|
|
|
|
|
|
|
memcpy(buffer + *used, src, size);
|
|
|
|
*used += size;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool copy_from_buffer(void *dst, void *buffer, size_t size, ssize_t *total, ssize_t *used) {
|
|
|
|
if (*used + size > *total)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (*used == 0)
|
|
|
|
bzero(dst, size);
|
|
|
|
|
|
|
|
memcpy(dst, buffer + *used, size);
|
|
|
|
*used += size;
|
|
|
|
return true;
|
|
|
|
}
|
2024-06-26 19:33:20 +00:00
|
|
|
|
|
|
|
bool copy_blocks(struct archive *w, struct archive *r) {
|
|
|
|
int64_t offset = 0;
|
|
|
|
const void *buffer;
|
|
|
|
size_t size = 0;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
while ((rc = archive_read_data_block(r, &buffer, &size, &offset)) == ARCHIVE_OK) {
|
|
|
|
rc = archive_write_data_block(w, buffer, size, offset);
|
|
|
|
if (rc != ARCHIVE_OK) {
|
|
|
|
lm_error_set(LM_ERR_ArcWBlockFail);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc != ARCHIVE_EOF) {
|
|
|
|
lm_error_set(LM_ERR_ArcRBlockFail);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool extract_archive(char *dst, char *src) {
|
|
|
|
struct archive *reader = NULL, *writer = NULL;
|
|
|
|
struct archive_entry *entry = NULL;
|
|
|
|
int flags = 0, rc = 0;
|
|
|
|
char *oldpwd = NULL;
|
|
|
|
bool ret = false;
|
2024-06-28 18:48:04 +00:00
|
|
|
char srcfull[PATH_MAX + 1];
|
|
|
|
|
|
|
|
if (NULL == realpath(src, srcfull)) {
|
|
|
|
lm_error_set(LM_ERR_ArcRealpathFail);
|
|
|
|
goto end;
|
|
|
|
}
|
2024-06-26 19:33:20 +00:00
|
|
|
|
|
|
|
oldpwd = getcwd(NULL, 0);
|
|
|
|
if (NULL == oldpwd) {
|
|
|
|
lm_error_set(LM_ERR_GetCwdFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
chdir(dst);
|
|
|
|
|
|
|
|
flags = ARCHIVE_EXTRACT_PERM;
|
|
|
|
flags |= ARCHIVE_EXTRACT_UNLINK;
|
|
|
|
|
|
|
|
reader = archive_read_new();
|
2024-06-28 18:48:04 +00:00
|
|
|
writer = archive_write_disk_new();
|
|
|
|
|
|
|
|
if (NULL == reader || NULL == writer) {
|
|
|
|
lm_error_set(LM_ERR_ArcNewFail);
|
|
|
|
goto end;
|
|
|
|
}
|
2024-06-26 19:33:20 +00:00
|
|
|
|
|
|
|
archive_write_disk_set_options(writer, flags);
|
|
|
|
archive_write_disk_set_standard_lookup(writer);
|
|
|
|
|
|
|
|
archive_read_support_format_tar(reader);
|
|
|
|
archive_read_support_filter_gzip(reader);
|
|
|
|
|
2024-06-28 18:48:04 +00:00
|
|
|
if (archive_read_open_filename(reader, srcfull, 1024 * 10) != ARCHIVE_OK) {
|
2024-06-26 19:33:20 +00:00
|
|
|
lm_error_set(LM_ERR_ArcOpenFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((rc = archive_read_next_header(reader, &entry)) == ARCHIVE_OK) {
|
|
|
|
rc = archive_write_header(writer, entry);
|
|
|
|
if (rc != ARCHIVE_OK) {
|
|
|
|
lm_error_set(LM_ERR_ArcWHeaderFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!copy_blocks(writer, reader))
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
rc = archive_write_finish_entry(writer);
|
|
|
|
if (rc != ARCHIVE_OK) {
|
|
|
|
lm_error_set(LM_ERR_ArcWEntryFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-28 18:48:04 +00:00
|
|
|
if (rc != ARCHIVE_EOF) {
|
|
|
|
lm_error_set(LM_ERR_ArcNextHeaderFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2024-06-26 19:33:20 +00:00
|
|
|
ret = true;
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (NULL != reader) {
|
|
|
|
archive_read_close(reader);
|
|
|
|
archive_read_free(reader);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NULL != writer) {
|
2024-06-28 18:48:04 +00:00
|
|
|
archive_write_close(writer);
|
|
|
|
archive_write_free(writer);
|
2024-06-26 19:33:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (NULL != oldpwd) {
|
|
|
|
chdir(oldpwd);
|
|
|
|
free(oldpwd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2024-06-27 20:05:39 +00:00
|
|
|
|
|
|
|
bool exists(char *path) {
|
|
|
|
struct stat st;
|
|
|
|
return stat(path, &st) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_file(char *path) {
|
|
|
|
struct stat st;
|
|
|
|
if (stat(path, &st) < 0)
|
|
|
|
return false;
|
|
|
|
return S_ISREG(st.st_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_dir(char *path) {
|
|
|
|
struct stat st;
|
|
|
|
if (stat(path, &st) < 0)
|
|
|
|
return false;
|
|
|
|
return S_ISDIR(st.st_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool can_read(char *path) {
|
|
|
|
return access(path, R_OK) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool can_write(char *path) {
|
|
|
|
return access(path, W_OK) == 0;
|
|
|
|
}
|
2024-06-28 17:51:56 +00:00
|
|
|
|
|
|
|
bool mkdir_ifnot(char *path) {
|
|
|
|
return !(mkdir(path, 0700) < 0 && errno != EEXIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sockaddr_to_str(struct sockaddr *addr, char *str) {
|
|
|
|
struct sockaddr_in *ipv4;
|
|
|
|
struct sockaddr_in6 *ipv6;
|
|
|
|
|
|
|
|
switch (addr->sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
ipv4 = (struct sockaddr_in *)addr;
|
|
|
|
inet_ntop(AF_INET, &ipv4->sin_addr, str, INET_ADDRSTRLEN);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
ipv6 = (struct sockaddr_in6 *)addr;
|
|
|
|
inet_ntop(AF_INET6, &ipv6->sin6_addr, str, INET6_ADDRSTRLEN);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-07-01 03:43:20 +00:00
|
|
|
|
|
|
|
bool package_name_valid(char *name) {
|
|
|
|
for (char *c = name; *c != 0; c++) {
|
|
|
|
if (!is_digit(*c) && !is_letter(*c) && *c != '-' && *c != '.')
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool package_version_valid(char *version) {
|
|
|
|
for (char *c = version; *c != 0; c++) {
|
|
|
|
if (!is_digit(*c) && !is_letter(*c) && *c != '-' && *c != '+' && *c != '.')
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool package_parse(char *package, char *name, char *version) {
|
|
|
|
ssize_t ni = 0, vi = -1;
|
|
|
|
|
|
|
|
for (char *c = package; *c != 0; c++) {
|
|
|
|
if (vi < 0 && *c == '_') {
|
|
|
|
vi = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi < 0)
|
|
|
|
name[ni++] = *c;
|
|
|
|
else
|
|
|
|
version[vi++] = *c;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ni > 0 && vi > 0) {
|
|
|
|
name[ni] = 0;
|
|
|
|
version[vi] = 0;
|
|
|
|
return package_name_valid(name) && package_version_valid(version);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int join(char *res, const char *base, const char *pth) {
|
|
|
|
int blen = strlen(base);
|
|
|
|
|
|
|
|
if ((base[blen - 1] == '/' && pth[0] != '/') || (base[blen - 1] != '/' && pth[0] == '/')) {
|
|
|
|
return sprintf(res, "%s%s", base, pth);
|
|
|
|
} else if (base[blen - 1] != '/' && pth[0] != '/') {
|
|
|
|
return sprintf(res, "%s/%s", base, pth);
|
|
|
|
} else if (base[blen - 1] == '/' && pth[0] == '/') {
|
|
|
|
char *basedup = strdup(base);
|
|
|
|
basedup[blen - 1] = '\0';
|
|
|
|
|
|
|
|
return sprintf(res, "%s%s", basedup, pth);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int join_multiple(char *res, const char *base, const char *pth, const char *pth2) {
|
|
|
|
char firstp[strlen(base) + strlen(pth) + 5];
|
|
|
|
if (join(firstp, base, pth) < 0)
|
|
|
|
return -1;
|
|
|
|
return join(res, firstp, pth2);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *join_alloc(const char *base, const char *pth) {
|
|
|
|
int pthlen = strlen(base) + strlen(pth);
|
|
|
|
char *path = malloc(pthlen + 5);
|
|
|
|
|
|
|
|
join(path, base, pth);
|
|
|
|
return path;
|
|
|
|
}
|
2024-07-04 00:12:33 +00:00
|
|
|
|
|
|
|
bool pkglist_contains(lm_pkg_t *list, lm_pkg_t *pkg) {
|
|
|
|
lm_pkg_t *cur = list;
|
|
|
|
while (cur) {
|
|
|
|
if (eq(pkg->name, cur->name))
|
|
|
|
return true;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
lm_pkg_t *pkglist_del(lm_pkg_t *list, lm_pkg_t *pkg) {
|
2024-07-10 13:39:05 +00:00
|
|
|
if (NULL == pkg) {
|
|
|
|
lm_error_set(LM_ERR_ArgNULL);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2024-07-04 00:12:33 +00:00
|
|
|
if (NULL == list)
|
|
|
|
return list;
|
|
|
|
|
2024-07-10 13:39:05 +00:00
|
|
|
if (eq(list->name, pkg->name)) {
|
|
|
|
list = NULL;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
lm_pkg_t *cur = list;
|
|
|
|
lm_pkg_t *found = NULL;
|
2024-07-04 00:12:33 +00:00
|
|
|
|
2024-07-10 13:39:05 +00:00
|
|
|
while (NULL != cur->next) {
|
|
|
|
if (eq(cur->next->name, pkg->name)) {
|
|
|
|
found = cur->next;
|
|
|
|
cur->next = cur->next->next;
|
2024-07-04 00:12:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
2024-07-10 13:39:05 +00:00
|
|
|
free(found);
|
2024-07-04 00:12:33 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2024-07-10 13:39:05 +00:00
|
|
|
lm_pkg_t *pkglist_add_top(lm_pkg_t *list, lm_pkg_t *pkg) {
|
2024-07-04 00:12:33 +00:00
|
|
|
lm_pkg_t *new = malloc(sizeof(lm_pkg_t));
|
|
|
|
memcpy(new, pkg, sizeof(lm_pkg_t));
|
|
|
|
new->next = list;
|
|
|
|
list = new;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2024-07-10 13:39:05 +00:00
|
|
|
lm_pkg_t *pkglist_add_end(lm_pkg_t *list, lm_pkg_t *pkg) {
|
|
|
|
lm_pkg_t *new = malloc(sizeof(lm_pkg_t)), *cur = list;
|
|
|
|
memcpy(new, pkg, sizeof(lm_pkg_t));
|
|
|
|
|
|
|
|
new->next = NULL;
|
|
|
|
|
|
|
|
if (NULL == cur) {
|
|
|
|
list = new;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (cur->next != NULL)
|
|
|
|
cur = cur->next;
|
|
|
|
cur->next = new;
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2024-07-04 00:12:33 +00:00
|
|
|
void pkglist_free(lm_pkg_t *list) {
|
2024-07-10 13:39:05 +00:00
|
|
|
lm_pkg_t *cur = list, *old = NULL;
|
|
|
|
while (cur != NULL) {
|
|
|
|
old = cur;
|
|
|
|
cur = cur->next;
|
2024-07-04 00:12:33 +00:00
|
|
|
free(old);
|
|
|
|
}
|
|
|
|
}
|
2024-07-04 22:44:42 +00:00
|
|
|
|
|
|
|
bool copy_file(char *dst, char *src) {
|
|
|
|
FILE *dstp = NULL, *srcp = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if ((dstp = fopen(dst, "w")) == NULL) {
|
|
|
|
lm_error_set(LM_ERR_DstOpenFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((srcp = fopen(src, "r")) == NULL) {
|
|
|
|
lm_error_set(LM_ERR_SrcOpenFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[255];
|
|
|
|
size_t bufsize = sizeof(buf), read = 0;
|
|
|
|
|
|
|
|
while ((read = fread(buf, 1, bufsize, srcp)) > 0) {
|
|
|
|
if (fwrite(buf, 1, read, dstp) <= 0) {
|
|
|
|
lm_error_set(LM_ERR_DstWriteFail);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
end:
|
|
|
|
if (NULL != dstp)
|
|
|
|
fclose(dstp);
|
|
|
|
|
|
|
|
if (NULL != srcp)
|
|
|
|
fclose(srcp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2024-07-11 04:31:36 +00:00
|
|
|
|
|
|
|
char *get_md5(char *path) {
|
|
|
|
const EVP_MD *alg = NULL;
|
|
|
|
EVP_MD_CTX *ctx = NULL;
|
|
|
|
FILE *file = NULL;
|
|
|
|
char *sum = NULL, buffer[255];
|
|
|
|
unsigned char digest[16];
|
|
|
|
unsigned int digest_len;
|
|
|
|
size_t read = 0;
|
|
|
|
|
|
|
|
alg = EVP_md5();
|
|
|
|
bzero(buffer, sizeof(buffer));
|
|
|
|
bzero(digest, sizeof(digest));
|
|
|
|
|
|
|
|
if ((file = fopen(path, "r")) == NULL) {
|
|
|
|
lm_error_set(LM_ERR_HashOpenFail);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EVP_DigestInit_ex(ctx, alg, NULL) <= 0) {
|
|
|
|
lm_error_set(LM_ERR_HashDigestFail);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((read = fread(buffer, sizeof(buffer), 1, file)) > 0)
|
|
|
|
EVP_DigestUpdate(ctx, buffer, read);
|
|
|
|
|
|
|
|
EVP_DigestFinal(ctx, digest, &digest_len);
|
|
|
|
EVP_MD_CTX_free(ctx);
|
|
|
|
|
|
|
|
sum = malloc((digest_len * 2) + 1);
|
|
|
|
|
|
|
|
for (int i = 0; i < sizeof(digest); i++)
|
|
|
|
sprintf(&sum[i * 2], "%02x", (unsigned int)digest[i]);
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|