feat|perf: generic&efficient desktop&config parser

This commit is contained in:
javalsai 2025-06-10 23:44:09 +02:00
parent d13ebfff4e
commit 22c3f7c896
Signed by: javalsai
SSH Key Fingerprint: SHA256:3G83yKhBUWVABVX/vPWH88xnK4+ptMtHkZGCRXD4Mk8
10 changed files with 178 additions and 88 deletions

View File

@ -12,10 +12,10 @@ ALLFLAGS=$(CFLAGS) -I$(IDIR)
LIBS=-lpam LIBS=-lpam
_DEPS = util.h ui.h config.h auth.h efield.h keys.h users.h sessions.h chvt.h _DEPS = util.h ui.h config.h desktop.h auth.h efield.h keys.h users.h sessions.h chvt.h macros.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS)) DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = main.o util.o ui.o config.o auth.o efield.o users.o sessions.o chvt.o _OBJ = main.o util.o ui.o config.o desktop.o auth.o efield.o users.o sessions.o chvt.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: $(CDIR)/%.c $(DEPS) $(ODIR)/%.o: $(CDIR)/%.c $(DEPS)

17
include/desktop.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef DESKTOPH_
#define DESKTOPH_
#include <stdbool.h>
#include <stdio.h>
#include "macros.h"
struct status {
bool finish;
int ret;
};
int read_desktop(FILE* fd, void* ctx, struct status (*cb)(void* ctx, char* NULLABLE table,
char* key, char* value));
#endif

12
include/macros.h Normal file
View File

@ -0,0 +1,12 @@
// Do we just replace the compiler with clang??
#if defined(__clang__)
#define NULLABLE _Nullable
#else
#define NULLABLE
#endif
#if defined(__clang__)
#define NNULLABLE _Nonnull
#else
#define NNULLABLE
#endif

View File

@ -3,6 +3,7 @@
#include <sys/types.h> #include <sys/types.h>
#include "macros.h"
#include "util.h" #include "util.h"
enum session_type { enum session_type {
@ -12,9 +13,9 @@ enum session_type {
}; };
struct session { struct session {
char* name; char* NNULLABLE name;
char* exec; char* NNULLABLE exec;
char* tryexec; char* NULLABLE tryexec;
enum session_type type; enum session_type type;
}; };

View File

@ -132,7 +132,8 @@ void moarEnv(char* user,
if (newbuf == NULL) continue; // can't bother if (newbuf == NULL) continue; // can't bother
strlcpy(newbuf, pw->pw_dir, newbuf_len); strlcpy(newbuf, pw->pw_dir, newbuf_len);
newbuf[home_len] = '/'; // assume pw_dir doesn't start with '/' :P newbuf[home_len] = '/'; // assume pw_dir doesn't start with '/' :P
strlcpy(&newbuf[home_len + 1], file2sourcepath, newbuf_len - home_len - 1); strlcpy(&newbuf[home_len + 1], file2sourcepath,
newbuf_len - home_len - 1);
/* printf("DEBUG(user_source)!!!! %d %s\n", i, newbuf); */ /* printf("DEBUG(user_source)!!!! %d %s\n", i, newbuf); */
sourceFileTry(newbuf); sourceFileTry(newbuf);
@ -250,8 +251,7 @@ bool launch(char* user,
pam_close_session(pamh, 0); pam_close_session(pamh, 0);
pam_end(pamh, PAM_SUCCESS); pam_end(pamh, PAM_SUCCESS);
if (*reach_session == false) if (*reach_session == false) return false;
return false;
exit(0); exit(0);
} }

View File

@ -41,6 +41,7 @@ int chvt(int n) {
close(fd); close(fd);
} }
(void)fputs("Couldn't get a file descriptor referring to the console.\n", stderr); (void)fputs("Couldn't get a file descriptor referring to the console.\n",
stderr);
return -1; return -1;
} }

74
src/desktop.c Normal file
View File

@ -0,0 +1,74 @@
// NOLINTBEGIN(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,readability-function-cognitive-complexity)
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "desktop.h"
#include "macros.h"
#define NOK \
{ \
ret = -1; \
break; \
}
#define NOKFKEY \
{ \
free(key); \
NOK \
}
int read_desktop(FILE* fd, void* ctx,
struct status (*cb)(void* ctx, char* NULLABLE table, char* key,
char* value)) {
char* table_name = NULL;
bool ret = -1;
char* buf = NULL;
size_t alloc_size = 0;
size_t read_size;
while ((read_size = getline(&buf, &alloc_size, fd)) > 0) {
ret = 0;
if (read_size <= 1) continue;
if (buf[0] == '[' && buf[read_size - 2] == ']') {
if (table_name != NULL) free(table_name);
table_name = realloc(buf, read_size);
table_name[read_size - 1] = '\0'; // newline
buf = NULL;
alloc_size = 0;
} else {
// Find '='
size_t eq_idx = 0;
while (buf[eq_idx] != '\0') {
if (buf[eq_idx] == '=') break;
eq_idx++;
}
// impossible with a min len of 1 (empty line)
if (eq_idx == 0) continue;
// Check its not end
if (buf[eq_idx] != '=') NOK;
// Key & Value
char* key = buf;
buf[eq_idx] = '\0'; // the equal
char* value = &buf[eq_idx+1];
buf[read_size-1] = '\0'; // the newline
// Callback
struct status cb_ret = cb(ctx, table_name, key, value);
if (cb_ret.finish) {
ret = cb_ret.ret;
break;
}
}
}
free(table_name);
if (buf != NULL) free(buf);
return ret;
}
#undef NOK
#undef NOKFKEY
// NOLINTEND(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,readability-function-cognitive-complexity)

View File

@ -50,8 +50,8 @@ void field_update(struct editable_field* self, char* update) {
} }
if (self->pos < self->length) { if (self->pos < self->length) {
// move with immediate buffer // move with immediate buffer
memmove(&self->content[self->pos + insert_len], memmove(&self->content[self->pos + insert_len], &self->content[self->pos],
&self->content[self->pos], self->length - self->pos); self->length - self->pos);
} }
memcpy(&self->content[self->pos], update, insert_len); memcpy(&self->content[self->pos], update, insert_len);

View File

@ -7,6 +7,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include "desktop.h"
#include "sessions.h" #include "sessions.h"
#include "util.h" #include "util.h"
@ -19,105 +20,89 @@ static const struct source_dir sources[] = {
{WAYLAND, "/usr/share/wayland-sessions"}, {WAYLAND, "/usr/share/wayland-sessions"},
}; };
static struct session new_session(enum session_type type, // static struct session new_session(enum session_type type, char* name,
char* name, // const char* exec, const char* tryexec) {
const char* exec, // struct session session;
const char* tryexec) { // session.type = type;
struct session session; // strcln(&session.name, name);
session.type = type; // strcln(&session.exec, exec);
strcln(&session.name, name); // strcln(&session.tryexec, tryexec);
strcln(&session.exec, exec);
strcln(&session.tryexec, tryexec);
return session; // return session;
} // }
static struct Vector* cb_sessions = NULL; static struct Vector* cb_sessions = NULL;
// NOTE: commented printf's here would be nice to have debug logs if I ever // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
// implement it struct status cb(void* _ctx, char* NULLABLE table, char* key, char* value) {
#define LN_NAME 0b0001 struct session* ctx = (struct session*)_ctx;
#define LN_EXEC 0b0010 struct status ret;
#define LN_TEXEC 0b0100 ret.finish = false;
#define LN_ALL (LN_NAME | LN_EXEC | LN_TEXEC)
if (table == NULL) return ret;
if (strcmp(table, "[Desktop Entry]") != 0) return ret;
char** NULLABLE copy_at = NULL;
if (strcmp(key, "Name") == 0) {
if (ctx->name == NULL) copy_at = &ctx->name;
} else if (strcmp(key, "Exec") == 0) {
if (ctx->exec == NULL) copy_at = &ctx->exec;
} else if (strcmp(key, "TryExec") == 0) {
if (ctx->tryexec == NULL) copy_at = &ctx->tryexec;
}
if (copy_at != NULL) {
*copy_at = malloc((strlen(value) + 1) * sizeof(char));
if (*copy_at == NULL) {
ret.finish = true;
ret.ret = -1; // malloc error
}
strcpy(*copy_at, value);
}
if (ctx->name != NULL && ctx->exec != NULL && ctx->tryexec != NULL) {
ret.finish = true;
ret.ret = 0;
}
return ret;
}
static enum session_type session_type; static enum session_type session_type;
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
static int fn(const char* fpath, const struct stat* sb, int typeflag) { static int fn(const char* fpath, const struct stat* sb, int typeflag) {
if (!S_ISREG(sb->st_mode)) return 0; if (!S_ISREG(sb->st_mode)) return 0;
// printf("gonna open %s\n", fpath); struct session* ctx = malloc(sizeof(struct session));
if (ctx == NULL) return 0;
ctx->name = NULL;
ctx->exec = NULL;
ctx->tryexec = NULL;
FILE* fd = fopen(fpath, "r"); FILE* fd = fopen(fpath, "r");
if (fd == NULL) { if (fd == NULL) {
free(ctx);
perror("fopen"); perror("fopen");
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) // NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
(void)fprintf(stderr, "error opening file (r) '%s'\n", fpath); (void)fprintf(stderr, "error opening file (r) '%s'\n", fpath);
return 0; return 0;
} }
u_char found = 0; int ret = read_desktop(fd, ctx, &cb);
if (ret < 0) { // any error
char* name_buf = NULL; free(ctx);
char* exec_buf = NULL; return 0;
char* tryexec_buf = NULL;
// This should be made a specific function
// Emm, if anything goes wrong just free the inner loop and `break;` fd and
// the rest is handled after
char* buf = NULL;
size_t alloc_size = 0;
size_t read_size;
while ((read_size = getline(&buf, &alloc_size, fd)) != -1) {
char* key = malloc(read_size + sizeof(char));
if (key == NULL) {
free(buf);
break;
}
char* value = malloc(read_size + sizeof(char));
if (value == NULL) {
free(buf);
free(key);
break;
}
value[0] = '\0'; // I'm not sure if sscanf would null this string out
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
if (sscanf(buf, "%[^=]=%[^\n]\n", key, value) == 2) {
if (strcmp(key, "Name") == 0) {
found &= LN_EXEC;
if(name_buf != NULL) free(name_buf);
name_buf = realloc(value, strlen(value) + sizeof(char));
} else if (strcmp(key, "Exec") == 0) {
found &= LN_EXEC;
if(exec_buf != NULL) free(exec_buf);
exec_buf = realloc(value, strlen(value) + sizeof(char));
} else if (strcmp(key, "TryExec") == 0) {
found &= LN_TEXEC;
if(tryexec_buf != NULL) free(tryexec_buf);
tryexec_buf = realloc(value, strlen(value) + sizeof(char));
} else {
free(value);
}
} else {
free(value);
}
free(key);
// if (found == LN_ALL) break;
} }
if(buf != NULL) free(buf);
(void)fclose(fd); (void)fclose(fd);
// printf("\nend parsing...\n");
// just add this to the list // just add this to the list
if (name_buf != NULL && exec_buf != NULL) { if (ctx->name != NULL && ctx->exec != NULL) {
struct session* session_i = malloc(sizeof(struct session)); ctx->type = session_type;
*session_i = new_session(session_type, name_buf, exec_buf, vec_push(cb_sessions, ctx);
tryexec_buf == NULL ? "" : tryexec_buf);
vec_push(cb_sessions, session_i);
} }
if (name_buf != NULL) free(name_buf);
if (exec_buf != NULL) free(exec_buf);
if (tryexec_buf != NULL) free(tryexec_buf);
return 0; return 0;
} }