mirror of
https://github.com/javalsai/lidm.git
synced 2026-02-27 03:50:44 +01:00
fixes: improve login environment handling (#114)
* chore(organization): allow nested header and c files * feat: add shell login "middleware" & etc: * lidm now calls `bash` (or other shells, depends on PACKAGE cfg) in login mode as a session wrapper to source most env (can be disabled) * this fixes a lot of env problems with all `/etc/profile` and more Extra: * implemented a musl compatible version of `execvpe` and now lidm should search for PATH everywhere it needs to * `search_path` now also checks if the found binary is properly executable * lidm now uses `confstr` for a decent PATH default if none is found * logs are unbuffered for cases where debug logs appear empty (exit without handlers moment) * chore: one-time evaluate certain makefile vars --------- Co-authored-by: grialion <48643945+grialion@users.noreply.github.com>
This commit is contained in:
64
src/util/path.c
Normal file
64
src/util/path.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util/path.h"
|
||||
|
||||
// returns NULL on any error
|
||||
// otherwise it returns the absolute path of the program that MUST BE FREED
|
||||
//
|
||||
// Should be almost completely posix compliant, except it won't resolve empty
|
||||
// PATH entries relative to the cwd
|
||||
char* NULLABLE search_path(const char* NNULLABLE for_binary) {
|
||||
if (strchr(for_binary, '/') != NULL) {
|
||||
// skip absolute paths
|
||||
return strdup(for_binary);
|
||||
}
|
||||
char* path_env = getenv("PATH");
|
||||
if (!path_env) return NULL;
|
||||
char* path = strdup(path_env);
|
||||
if (!path) return NULL;
|
||||
|
||||
char* tok = strtok(path, ":");
|
||||
while (tok) {
|
||||
char* bin_path;
|
||||
asprintf(&bin_path, "%s/%s", tok, for_binary);
|
||||
if (!bin_path) {
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct stat stat_buf;
|
||||
if (stat(bin_path, &stat_buf) == 0 && access(bin_path, X_OK) == 0) {
|
||||
free(path);
|
||||
return bin_path;
|
||||
}
|
||||
|
||||
free(bin_path);
|
||||
tok = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This is present in glibc ONLY with GNU extensions, this aims to provide a
|
||||
// musl compatible variant.
|
||||
//
|
||||
// Respects errno of exec functions family.
|
||||
int execvpe(const char* NNULLABLE file, char* NULLABLE const argv[NNULLABLE],
|
||||
char* NULLABLE const envp[NNULLABLE]) {
|
||||
char* path = search_path(file);
|
||||
if (!path) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
int ret = execve(path, argv, envp);
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
62
src/util/utf8.c
Normal file
62
src/util/utf8.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "util/utf8.h"
|
||||
|
||||
#define UTF8_CONT_MSK 0b11000000
|
||||
#define UTF8_CONT_VAL 0b10000000
|
||||
bool utf8_iscont(char byte) {
|
||||
return (byte & UTF8_CONT_MSK) == UTF8_CONT_VAL;
|
||||
}
|
||||
|
||||
size_t utf8len(const char* str) {
|
||||
size_t len = 0;
|
||||
while (*str != '\0') {
|
||||
if (!utf8_iscont(*(str++))) len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t utf8len_until(const char* str, const char* until) {
|
||||
size_t len = 0;
|
||||
while (str < until) {
|
||||
if (!utf8_iscont(*(str++))) len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t utf8trunc(char* str, size_t n) {
|
||||
size_t bytes = 0;
|
||||
while (true) {
|
||||
if (str[bytes] == '\0') break;
|
||||
if (utf8_iscont(str[bytes])) {
|
||||
bytes++;
|
||||
continue;
|
||||
}
|
||||
if (n == 0) {
|
||||
str[bytes] = '\0';
|
||||
break;
|
||||
}
|
||||
bytes++;
|
||||
n--;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const char* utf8back(const char* str) {
|
||||
while (utf8_iscont(*(--str))) {
|
||||
}
|
||||
return str;
|
||||
}
|
||||
const char* utf8seek(const char* str) {
|
||||
while (utf8_iscont(*(++str))) {
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
const char* utf8seekn(const char* str, size_t n) {
|
||||
while (n > 0 && *str != '\0') {
|
||||
str = utf8seek(str);
|
||||
n--;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
96
src/util/vec.c
Normal file
96
src/util/vec.c
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util/vec.h"
|
||||
|
||||
const struct Vector VEC_NEW = {
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
.pages = NULL,
|
||||
};
|
||||
|
||||
struct Vector vec_from_raw(void** raw) {
|
||||
size_t len = 0;
|
||||
while (raw[len])
|
||||
len++;
|
||||
|
||||
return (struct Vector){
|
||||
.length = len,
|
||||
.capacity = len,
|
||||
.pages = raw,
|
||||
};
|
||||
}
|
||||
|
||||
void** vec_as_raw(struct Vector self) {
|
||||
if (vec_push(&self, NULL) != 0) return NULL;
|
||||
return self.pages;
|
||||
}
|
||||
|
||||
int vec_resize(struct Vector* self, size_t size) {
|
||||
void** new_location =
|
||||
(void**)realloc((void*)self->pages, size * sizeof(void*));
|
||||
if (new_location != NULL) {
|
||||
if (self->length > size) self->length = size;
|
||||
self->capacity = size;
|
||||
self->pages = new_location;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vec_reserve(struct Vector* self, size_t size) {
|
||||
uint32_t new_capacity = self->capacity;
|
||||
while (self->length + size > new_capacity) {
|
||||
new_capacity = new_capacity + (new_capacity >> 1) +
|
||||
1; // cap * 1.5 + 1; 0 1 2 4 7 11...
|
||||
}
|
||||
return vec_resize(self, new_capacity);
|
||||
}
|
||||
|
||||
int vec_reserve_exact(struct Vector* self, size_t size) {
|
||||
uint32_t needed_capacity = self->length + size;
|
||||
if (self->capacity < needed_capacity) {
|
||||
return vec_resize(self, needed_capacity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vec_push(struct Vector* self, void* item) {
|
||||
int res_ret = vec_reserve(self, 1);
|
||||
if (res_ret != 0) return res_ret;
|
||||
|
||||
self->pages[self->length++] = item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vec_free(struct Vector* self) {
|
||||
while (self->length > 0)
|
||||
free(self->pages[--self->length]);
|
||||
|
||||
vec_clear(self);
|
||||
}
|
||||
|
||||
void vec_clear(struct Vector* self) {
|
||||
free((void*)self->pages);
|
||||
vec_reset(self);
|
||||
}
|
||||
|
||||
void vec_reset(struct Vector* self) {
|
||||
*self = (struct Vector){
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
.pages = NULL,
|
||||
};
|
||||
}
|
||||
|
||||
void* vec_pop(struct Vector* self) {
|
||||
if (self->length == 0) return NULL;
|
||||
|
||||
return self->pages[--self->length];
|
||||
}
|
||||
|
||||
void* vec_get(struct Vector* self, size_t index) {
|
||||
if (index >= self->length) return NULL;
|
||||
|
||||
return self->pages[index];
|
||||
}
|
||||
Reference in New Issue
Block a user