diff options
| author | Benjamin Linskey | 2026-06-08 04:05:03 -0400 |
|---|---|---|
| committer | Benjamin Linskey | 2026-06-08 17:01:22 -0400 |
| commit | f9a393c59f95f387b7a0c6c774b970b3b1d49e20 (patch) | |
| tree | b4981b0af79391db11359c07d348ba5b32f91030 | |
| parent | 197ecfff9e99d57fe9539685316d3acf23f6cdfc (diff) | |
| download | rogue-f9a393c59f95f387b7a0c6c774b970b3b1d49e20.tar.gz | |
Store score file in home directory
BSD games are traditionally designed for multiuser systems and thus write their data to /var/games, using setgid to prevent tampering. Switch to a single-user design, writing the score file to the user’s home directory. $XDGDATAHOME/rogue will will be used if $XDGDATAHOME is defined. Otherwise, data will be written to a $HOME/.rogue directory.
This also improves the makefile by making header files a dependency of objects.
| -rw-r--r-- | Makefile | 9 | ||||
| -rw-r--r-- | machdep.c | 34 | ||||
| -rw-r--r-- | pathnames.c | 142 | ||||
| -rw-r--r-- | pathnames.h | 10 | ||||
| -rw-r--r-- | rogue.h | 1 | ||||
| -rw-r--r-- | score.c | 14 |
6 files changed, 163 insertions, 47 deletions
@@ -7,10 +7,13 @@ BIN_DIR:=$(PREFIX)/bin CPPFLAGS+=-DUNIX -DUNIX_SYSV SRCS= hit.c init.c inventory.c level.c machdep.c main.c \ message.c monster.c move.c object.c pack.c play.c random.c ring.c \ - room.c save.c score.c spec_hit.c throw.c trap.c use.c zap.c + room.c save.c score.c spec_hit.c throw.c trap.c use.c zap.c \ + pathnames.c OBJS= hit.o init.o inventory.o level.o machdep.o main.o \ message.o monster.o move.o object.o pack.o play.o random.o ring.o \ - room.o save.o score.o spec_hit.o throw.o trap.o use.o zap.o + room.o save.o score.o spec_hit.o throw.o trap.o use.o zap.o \ + pathnames.o +HEADERS=rogue.h pathnames.h DPADD= ${LIBCURSES} ${LIBTERMINFO} LDADD= -lcurses -lterminfo HIDEGAME=hidegame @@ -24,6 +27,8 @@ COPTS.score.c+= ${CC_WNO_FORMAT_TRUNCATION} $(PROG): $(OBJS) cc -o $@ -lcurses $(OBJS) +$(OBJS): $(HEADERS) + .PHONY: install install: $(PROG) chmod 755 $(PROG) @@ -424,40 +424,6 @@ md_exit(int status) exit(status); } -/* md_lock(): - * - * This function is intended to give the user exclusive access to the score - * file. It does so by flock'ing the score file. The full path name of the - * score file should be defined for any particular site in rogue.h. The - * constants _PATH_SCOREFILE defines this file name. - * - * When the parameter 'l' is non-zero (true), a lock is requested. Otherwise - * the lock is released. - */ - -void -md_lock(boolean l) -{ - static int fd = -1; - short tries; - - if (l) { - setegid(egid); - if ((fd = open(_PATH_SCOREFILE, O_RDONLY)) < 1) { - setegid(gid); - messagef(0, "cannot lock score file"); - return; - } - setegid(gid); - for (tries = 0; tries < 5; tries++) - if (!flock(fd, LOCK_EX|LOCK_NB)) - return; - } else { - (void)flock(fd, LOCK_UN|LOCK_NB); - (void)close(fd); - } -} - /* md_shell(): * * This function spawns a shell for the user to use. When this shell is diff --git a/pathnames.c b/pathnames.c new file mode 100644 index 0000000..e6d9117 --- /dev/null +++ b/pathnames.c @@ -0,0 +1,142 @@ +#include <stdlib.h> +#include <pwd.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdio.h> +#include "pathnames.h" +#include "rogue.h" + +#define XDG_DIR "rogue" +#define DOTFILE_DIR ".rogue" +#define SCORE_FILE "scores" + +static char *get_prog_dir_path(void); +static char *get_score_path(void); +static int ensure_prog_dir(void); + +/* + * Opens the score file for reading and writing and returns a file pointer. + * Returns NULL on error. + */ +FILE * +open_score_file(void) { + if (ensure_prog_dir() == -1) { + printf("Failed to ensure directory\n"); + return NULL; + } + + char *path = get_score_path(); + FILE *fp = fopen(path, "r+"); + if (!fp && errno == ENOENT) { + fp = fopen(path, "w+"); + } + free(path); + + if (!fp) { + printf("Failed to open file %s\n", path); + } + return fp; +} + +/* + * Returns the path to the program data directory. The caller is responsible + * for freeing the returned memory. + */ +static +char * +get_prog_dir_path(void) { + /* + * Use $XDG_DATA_HOME if defined, or the user's home directory + * otherwise. + */ + char *data_dir = getenv("XDG_DATA_HOME"); + char *dir; + if (data_dir) { + dir = XDG_DIR; + } else { + dir = DOTFILE_DIR; + data_dir = getenv("HOME"); + if (!data_dir) { + data_dir = getpwuid(getuid())->pw_dir; + } + } + + size_t len = strlen(data_dir) + strlen(dir) + 1; + bool add_slash = false; + if (data_dir[strlen(data_dir) - 1] != '/') { + len += 1; + add_slash = true; + } + + char *buf = malloc(len); + strlcpy(buf, data_dir, len); + if (add_slash) { + strlcat(buf, "/", len); + } + strlcat(buf, dir, len); + + return buf; +} + +/* + * Returns the path to the score file. The caller is repsonsible for freeing + * the returned memory. + */ +static +char * +get_score_path(void) +{ + char *dir = get_prog_dir_path(); + + // Account for slash after directory and trailing NULL. + size_t len = strlen(dir) + strlen(SCORE_FILE) + 2; + + char *buf = malloc(len); + strlcpy(buf, dir, len); + strlcat(buf, "/", len); + strlcat(buf, SCORE_FILE, len); + + free(dir); + + return buf; +} + +/* + * Ensures that the program data directory exists. Returns 0 on success or -1 + * if an error occurs. + */ +static +int +ensure_prog_dir(void) { + int ret; + char *path = get_prog_dir_path(); + struct stat s = {0}; + int err = stat(path, &s); + + // If file does not exist, create the directory. + if (err && errno == ENOENT) { + ret = mkdir(path, 0755); + goto cleanup; + } + + // If file does exist and stat() returned an error, bail out. + if (err) { + ret = err; + goto cleanup; + } + + // If file is a directory, we don't need to do anything. + if (s.st_mode & S_IFDIR) { + ret = 0; + goto cleanup; + } + + // File exists and isn't a directory, so return an error. + ret = -1; + goto cleanup; + +cleanup: + free(path); + return ret; +} diff --git a/pathnames.h b/pathnames.h index d6e91a5..f24ba08 100644 --- a/pathnames.h +++ b/pathnames.h @@ -31,5 +31,13 @@ * @(#)pathnames.h 8.1 (Berkeley) 5/31/93 */ -#define _PATH_SCOREFILE "/var/games/rogue.scores" +#ifndef _PATHNAMES_H +#define _PATHNAMES_H + +#include <stdio.h> + #define _PATH_SCREENDUMP "rogue.screen" + +FILE *open_score_file(void); + +#endif // _PATHNAMES_H @@ -542,7 +542,6 @@ int md_gseed(void); void md_heed_signals(void); void md_ignore_signals(void); int md_link_count(const char *); -void md_lock(boolean); void md_shell(const char *); void md_sleep(int); void md_slurp(void); @@ -32,6 +32,7 @@ * SUCH DAMAGE. */ +#include <stdlib.h> #include <sys/cdefs.h> #ifndef lint #if 0 @@ -341,16 +342,12 @@ put_scores(const object *monster, short other) FILE *fp; boolean dopause = score_only; - md_lock(1); - - setegid(egid); - if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL && - (fp = fopen(_PATH_SCOREFILE, "w+")) == NULL) { - setegid(gid); + fp = open_score_file(); + if (fp== NULL) { messagef(0, "cannot read/write/create score file"); sf_error(); } - setegid(gid); + rewind(fp); (void)xxx(1); @@ -418,7 +415,7 @@ put_scores(const object *monster, short other) write_score_entry(&scores[i], i, fp); } } - md_lock(0); + fclose(fp); /* Display the scores */ @@ -668,7 +665,6 @@ center(short row, const char *buf) static void sf_error(void) { - md_lock(0); messagef(1, "%s", ""); /* gcc objects to just "" */ clean_up("sorry, score file is out of order"); } |