aboutsummaryrefslogtreecommitdiffstats
path: root/src/launcherutil.c
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2023-12-25 06:05:40 -0600
committerLibravatar bigfoot547 <[email protected]>2023-12-25 06:05:40 -0600
commit6d1d4d0a5506dce90c833ef8dd141058fea3c33a (patch)
tree12a95579dbf04c4310e5b42ad8cae399d81f1189 /src/launcherutil.c
parentinitial commit (diff)
[WIP] Add instances
still need to do the following: - check if the folder exists - try and find some way to canonicalize the path name
Diffstat (limited to 'src/launcherutil.c')
-rw-r--r--src/launcherutil.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/launcherutil.c b/src/launcherutil.c
new file mode 100644
index 0000000..8df4a71
--- /dev/null
+++ b/src/launcherutil.c
@@ -0,0 +1,157 @@
+#include "macros.h"
+#include "l2su.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+/* handcoded string functions
+ *
+ * NOTE: I am aware that this is inefficient but since these are used only a handful of times
+ * during initialization, I don't think performance is really a huge deal here.
+ *
+ * remember that this is a Minecraft launcher, so the PC has to meet the minimum specs of that,
+ * which are well above the minimum specs of this launcher */
+
+char *l2_launcher_strapp(char *buf, const char *src)
+{
+ size_t buflen = strlen(buf);
+ size_t srclen = strlen(src);
+
+ char *ret = realloc(buf, buflen + srclen + 1);
+ if (!ret) return NULL;
+
+ memcpy(ret + buflen, src, srclen);
+ ret[buflen + srclen] = '\0'; /* realloc does not initialize like calloc does */
+
+ return ret;
+}
+
+char *l2_launcher_find_config_path(void)
+{
+ /* check for $L2SU_CONFIG */
+ char *config = getenv(PROJECT_NAME_UPPER "_CONFIG");
+ if (config) {
+ return strdup(config);
+ }
+
+ /* check for $XDG_CONFIG_HOME */
+ config = getenv("XDG_CONFIG_HOME");
+ if (config) {
+ /* want to append '"/" PROJECT_NAME' to our string */
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/" PROJECT_NAME);
+ }
+
+ /* check for $HOME/.config */
+ config = getenv("HOME");
+ if (config) {
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/.config/" PROJECT_NAME);
+ }
+
+ /* fail (do NOT attempt to find home directory from passwd */
+ return NULL;
+}
+
+char *l2_launcher_find_data_path(void)
+{
+ /* check for $L2SU_DATA */
+ char *config = getenv(PROJECT_NAME_UPPER "_DATA");
+ if (config) {
+ return strdup(config);
+ }
+
+ /* check for $XDG_DATA_HOME */
+ config = getenv("XDG_DATA_HOME");
+ if (config) {
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/" PROJECT_NAME);
+ }
+
+ /* check for $HOME/.local/share */
+ config = getenv("HOME");
+ if (config) {
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/.local/share/" PROJECT_NAME);
+ }
+
+ return NULL;
+}
+
+int l2_launcher_open_config(const char *path, int flags, mode_t mode)
+{
+ int conffd = open(l2_state.paths.config, O_RDONLY | O_DIRECTORY);
+ if (conffd < 0) return INSTANCE_ERRNO;
+
+ int instfd = openat(conffd, path, flags, mode);
+ int en = errno; /* back up errno because close can fail */
+
+ close(conffd);
+
+ errno = en;
+ return instfd;
+}
+
+/* NOTE: There's no portable (or otherwise - see open(2) BUGS) way to do this without race conditions. */
+int l2_launcher_mkdir_parents(const char *path)
+{
+ if (*path != '/') return -1;
+
+ int reserrno = 0;
+
+ char *pathbuf = strdup(path);
+ char *pcurelem = pathbuf;
+ if (!pathbuf) return -1;
+
+ struct stat stbuf = { 0 };
+
+ do { /* strtok is off-limits because it smells bad */
+ *pcurelem = '/';
+ pcurelem = strchr(pcurelem + 1, '/');
+
+ if (pcurelem) {
+ *pcurelem = '\0';
+ }
+
+ /* now pathbuf contains our truncated path name which may or may not exist */
+ if (mkdir(pathbuf, 0755) < 0) {
+ if (errno == EEXIST) {
+ /* racy: stat the file and continue if it is a directory */
+ if (stat(pathbuf, &stbuf) < 0) {
+ reserrno = errno;
+ goto mdcleanup;
+ }
+
+ if (!S_ISDIR(stbuf.st_mode)) {
+ reserrno = ENOTDIR;
+ goto mdcleanup;
+ }
+ } else {
+ reserrno = errno;
+ goto mdcleanup;
+ }
+ }
+ } while (pcurelem);
+
+mdcleanup:
+
+ free(pathbuf);
+ if (reserrno != 0) {
+ errno = reserrno;
+ return -1;
+ }
+
+ return 0;
+}