From 80c71e2330f960688682a7704d2a061663e915dc Mon Sep 17 00:00:00 2001 From: wdlkmpx Date: Sat, 30 Jan 2021 10:15:32 +0800 Subject: [PATCH 1/5] gtkballs.c/h: add get_config_dir_file() to store/read files from in $XDG_CONFIG_HOME/games (usually ~/.config/games) it's possible to provide any directory through a modified XDG_CONFIG_HOME --- src/gtkballs.c | 39 +++++++++++++++++++++++++++++++++++---- src/gtkballs.h | 1 + 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/gtkballs.c b/src/gtkballs.c index 1c10c4c..99937ea 100644 --- a/src/gtkballs.c +++ b/src/gtkballs.c @@ -22,6 +22,31 @@ #include "game.h" #include "mainmenu.h" #include "mainwin.h" +#include +#include /* mkdir */ + + +#define P_DIR "games" +char * get_config_dir_file (const char * file) +{ + /* returns a path that must be freed with g_free */ + char * config_home, * res; +#if __MINGW32__ + config_home = getenv ("LOCALAPPDATA"); /* XP */ + if (!config_home) { + config_home = getenv ("APPDATA"); + } +#else + config_home = getenv ("XDG_CONFIG_HOME"); +#endif + if (config_home) { + res = g_build_filename (config_home, P_DIR, file, NULL); + } else { + res = g_build_filename (g_get_home_dir(), ".config", P_DIR, file, NULL); + } + return res; +} + gint destroy_lines(gboolean count_score) { gint i = game_destroy_lines(count_score); @@ -113,6 +138,7 @@ void new_game(void) draw_board(); } +// ================================================================== int main(int argc, char **argv) { @@ -120,7 +146,7 @@ int main(int argc, char **argv) struct timeval tv; struct timezone tz; struct score_board scoreboard[10]; - gchar *err, *mapfile; + gchar *err, *mapfile, * confdir; /* setup all i18n stuff */ #ifdef ENABLE_NLS @@ -138,12 +164,17 @@ int main(int argc, char **argv) gettimeofday(&tv, &tz); srand((unsigned int)tv.tv_usec); - /* load user's preferences */ - load_preferences(); - /* initialize gtk */ gtk_init (&argc, &argv); + /* Make sure confdir exists */ + confdir = get_config_dir_file (NULL); + g_mkdir_with_parents (confdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + g_free (confdir); + + /* load user's preferences */ + load_preferences(); + /* load theme, fallback to default if specifed theme cannot be loaded */ if (!(i = load_theme(pref_get_theme_name()))) { if (strcmp(pref_get_theme_name(), pref_get_default_theme_name()) != 0) { diff --git a/src/gtkballs.h b/src/gtkballs.h index 4afecf0..a081a85 100644 --- a/src/gtkballs.h +++ b/src/gtkballs.h @@ -26,6 +26,7 @@ extern GtkWindow * main_window; # define N_(String) (String) #endif /* ENABLE_NLS */ +char * get_config_dir_file (const char * file); void new_game(void); void new_turn(gint number, gboolean first); void undo_move(GtkWidget *widget, gpointer data); From 964bfccbc6ee3649b04e70bd4b9f08fa9b40787b Mon Sep 17 00:00:00 2001 From: wdlkmpx Date: Sat, 30 Jan 2021 10:55:17 +0800 Subject: [PATCH 2/5] store gtkballs-scores in get_config_dir_file() remove child.c/h and the complex logic behind storing files in /var which usually only the root user can access --- src/Makefile.am | 2 +- src/child.c | 147 ----------------------------------------------- src/child.h | 13 ----- src/gtkballs.c | 10 +--- src/mainwin.c | 7 --- src/scoreboard.c | 52 ++++++----------- src/scoreboard.h | 4 -- 7 files changed, 19 insertions(+), 216 deletions(-) delete mode 100644 src/child.c delete mode 100644 src/child.h diff --git a/src/Makefile.am b/src/Makefile.am index d34b3df..6120ff6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ gtkballs_SOURCES = gtkballs.c gtkballs.h gfx.c gfx.h \ path.c path.h preferences.c preferences.h \ scoreboard.c scoreboard.h themerc.c themerc.h \ gtkutils.c gtkutils.h mainmenu.c mainmenu.h \ - rules.c rules.h about.c about.h child.c child.h \ + rules.c rules.h about.c about.h \ theme.c theme.h savegame.c savegame.h \ savedialog.c savedialog.h halloffame.c halloffame.h \ inputname.c inputname.h rulesdialog.c rulesdialog.h \ diff --git a/src/child.c b/src/child.c deleted file mode 100644 index 8959210..0000000 --- a/src/child.c +++ /dev/null @@ -1,147 +0,0 @@ -/* child.c - spawn child, that works with extra privileges - * to be able to write scores. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - */ -#include -#include /* select() */ -#include /* pid_t */ -#include /* open() */ -#include /* fcntl() */ -#include /* sigaction() */ -#include /* pipe() */ -#include /* strerror() */ -#include /* errno */ -#include /* exit() */ -#include /* waitpid() */ -#include /* printf() */ - -volatile sig_atomic_t _child_writer_alive = 0; -gboolean _child_writer_dead_warned = 0; - -int child_writer_alive(void){ - return _child_writer_alive; -} - -int child_writer_dead_handler(void) { - if (_child_writer_alive == 0 && _child_writer_dead_warned == 0) { - _child_writer_dead_warned = 1; - return 1; - } - return 0; -} - -void child_process_score_writer(int chfd, gchar *score_file) -{ - fd_set rfds; - int i; - int fd=-1; - gchar *buf; - size_t sz; - sigset_t sset; - struct flock lockinfo; - gchar *score_file_full = g_strconcat(LOCALSTATEDIR, score_file, NULL); - - while (1) - { - FD_ZERO(&rfds); - FD_SET(chfd, &rfds); - if (select(chfd + 1, &rfds, NULL, NULL, NULL) > 0) - { - if (read(chfd, &sz, sizeof(sz)) <= 0) { - exit(0); - } - /* block signals before writing, to prevent possible file corruption */ - sigemptyset(&sset); - sigaddset(&sset, SIGHUP); - sigaddset(&sset, SIGINT); - sigaddset(&sset, SIGQUIT); - sigaddset(&sset, SIGTERM); - sigprocmask(SIG_BLOCK, &sset, NULL); - fd = open(score_file_full, O_WRONLY | O_TRUNC); - if (fd != -1) { - /* get write lock before writing scores */ - lockinfo.l_whence = SEEK_SET; - lockinfo.l_start = 0; - lockinfo.l_len = 0; - - i = 0; - while (1) { - lockinfo.l_type=F_WRLCK; - if (!fcntl(fd, F_SETLK, &lockinfo)) { - break; - } - if (i >= 3) { - close(fd); - fd = -1; - } - i++; - } - } - while (sz > 0) { - buf=g_malloc(sz); - read(chfd, buf, sz); - if (fd != -1) { - write(fd, buf, sz); - } - g_free(buf); - read(chfd, &sz, sizeof(sz)); - } - - if (fd != -1) { - close(fd); - } else { - /* FIXME: here should be some sort of error reporting to parent */ - } - sigprocmask(SIG_UNBLOCK, &sset, NULL); - } - } -} - -static void sigchld_handler(int param) -{ - pid_t ret = waitpid(0, NULL, WNOHANG); - - if (ret > 0) { /* score writer process killed by bastards! */ - _child_writer_alive = 0; - } -} - -int child_setup(gchar *score_file) -{ - pid_t pid; - struct sigaction sact; - int sfds[2]; - - /* set up SIGCHLD handler, so we can know if our score writer process - terminated while we run... */ - sact.sa_handler = sigchld_handler; - sigemptyset(&sact.sa_mask); - sact.sa_flags = 0; -#ifdef SA_RESTART - sact.sa_flags |= SA_RESTART; -#endif - if (sigaction(SIGCHLD, &sact, NULL) < 0) { - printf("cannot setup SIGCHLD handler.\n"); - return -1; - } - if (pipe(sfds) == -1) { - printf("pipe() failed: %s\n", strerror(errno)); - return -1; - } - pid = fork(); - if (pid == -1) { - printf("cannot fork: %s\n", strerror(errno)); - return -1; - } else if (pid == 0) { - close(sfds[1]); - child_process_score_writer(sfds[0], score_file); - } - close(sfds[0]); - _child_writer_alive = 1; - - return sfds[1]; -} diff --git a/src/child.h b/src/child.h deleted file mode 100644 index 8f9a29d..0000000 --- a/src/child.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __CHILD_H__ -#define __CHILD_H__ - -/* spawn score writer process */ -int child_setup(gchar *score_file); - -/* check if child process alive or not */ -int child_writer_alive(void); - -/* check score writer process and display warning if not running */ -int child_writer_dead_handler(void); - -#endif diff --git a/src/gtkballs.c b/src/gtkballs.c index 99937ea..372614c 100644 --- a/src/gtkballs.c +++ b/src/gtkballs.c @@ -16,7 +16,6 @@ #include "prefs.h" /* preferences */ #include "scoreboard.h" /* read_score, score_setup */ #include "gfx.h" -#include "child.h" #include "theme.h" #include "inputname.h" /* input_name_dialog */ #include "game.h" @@ -155,11 +154,6 @@ int main(int argc, char **argv) bind_textdomain_codeset(PACKAGE, "UTF8"); #endif /* ENABLE_NLS */ - /* drop privileges after spawning child with extra privs */ - if (score_setup() == -1) - return 1; - setregid(getgid(), getgid()); - /* initialize random seed */ gettimeofday(&tv, &tz); srand((unsigned int)tv.tv_usec); @@ -201,9 +195,7 @@ int main(int argc, char **argv) remake_board(-1, 1); /* read and set scores */ - if (!read_score(scoreboard, NULL, NULL)) { - ut_simple_message_box(_("Unable to read score.\n")); - } + read_score (scoreboard, NULL, NULL); mw_set_hi_score(scoreboard[0].score); mw_set_user_score(0); diff --git a/src/mainwin.c b/src/mainwin.c index 268e3f5..86983b7 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -14,7 +14,6 @@ #include "gtkutils.h" #include "mainmenu.h" /* menu_* */ #include "game.h" -#include "child.h" GtkWindow * main_window; @@ -78,12 +77,6 @@ gboolean _countdown_timer(gpointer data) GtkLabel *label = data; gint trem; - if (child_writer_dead_handler()) { - ut_simple_message_box_with_title(_("Score writer process died unexpectedly. No scores will be writen!\n" \ - "Save your game and restart programm.\n"), - _("Who Killed Bambi?")); - } - if (!timer_is_running()) { gtk_label_set_text(label, _("Time is unlimited")); return TRUE; diff --git a/src/scoreboard.c b/src/scoreboard.c index 571ca8e..688bc26 100644 --- a/src/scoreboard.c +++ b/src/scoreboard.c @@ -16,19 +16,11 @@ #include "gtkballs.h" #include "scoreboard.h" -#include "child.h" /* child_writer_alive, child_setup */ #include "game.h" +#define SCORE_FILE "gtkballs-scores" #define BUFFER_SIZE 1024 -int _score_fd = -1; - -gint score_setup(void) -{ - _score_fd = child_setup(SCORE_FILE); - return _score_fd; -} - void free_score_board_full(struct score_board_full *bf, gint nbf) { @@ -44,10 +36,13 @@ void free_score_board_full(struct score_board_full *bf, gint nbf) gint write_score(struct score_board *b, struct score_board_full *bf, gint nbf) { gint i; - gchar *buf, *tname, *tdate, *rules; - size_t sz; + gchar *tname, *tdate, *rules; + char * score_file = get_config_dir_file (SCORE_FILE); + FILE * fd; - if (child_writer_alive() == 0) { + fd = fopen (score_file, "w"); + if (!fd) { + g_free (score_file); return FALSE; } @@ -63,27 +58,19 @@ gint write_score(struct score_board *b, struct score_board_full *bf, gint nbf) tdate = g_strdup(_("Unknown")); } rules = rules_get_as_str(); - buf = g_strdup_printf("%s\t%i\t%s\t%s\n", tname, b[i].score, tdate, rules); - sz = strlen(buf); - write(_score_fd, &sz, sizeof(sz)); - write(_score_fd, buf, strlen(buf)); + fprintf (fd, "%s\t%i\t%s\t%s\n", tname, b[i].score, tdate, rules); g_free(rules); g_free(tdate); g_free(tname); - g_free(buf); } } for (i = 0; i < nbf; i++) { if (strlen(bf[i].name)) { - buf = g_strdup_printf("%s\t%i\t%s\t%s\n", bf[i].name, bf[i].score, bf[i].date, bf[i].rules); - sz = strlen(buf); - write(_score_fd, &sz, sizeof(sz)); - write(_score_fd, buf, strlen(buf)); - g_free(buf); + fprintf (fd, "%s\t%i\t%s\t%s\n", bf[i].name, bf[i].score, bf[i].date, bf[i].rules); } } - sz = 0; - write(_score_fd, &sz, sizeof(sz)); + g_free (score_file); + fclose (fd); return TRUE; } @@ -104,24 +91,17 @@ gint read_score(struct score_board *b, struct score_board_full **bf, gint *nbf) gchar **str_val, *tstr, **tstr_val; gint valid, sc, fsc; gsize br, bw; - struct flock lockinfo; + char * score_file = get_config_dir_file (SCORE_FILE); gchar *g_rules = NULL; memset(b, 0, sizeof(struct score_board) * 10); - if (!(fp = fopen(LOCALSTATEDIR SCORE_FILE, "r"))) { - return FALSE; + if (!(fp = fopen(score_file, "r"))) { + g_free (score_file); + return TRUE; } - do { - lockinfo.l_whence = SEEK_SET; - lockinfo.l_start = 0; - lockinfo.l_len = 0; - lockinfo.l_type = F_WRLCK; - fcntl(fileno(fp), F_GETLK, &lockinfo); - } while (lockinfo.l_type != F_UNLCK); - sc = 0; fsc = 0; while (fgets(buffer, BUFFER_SIZE, fp)) @@ -198,6 +178,8 @@ gint read_score(struct score_board *b, struct score_board_full **bf, gint *nbf) } g_strfreev(str_val); } + + g_free (score_file); fclose(fp); qsort(b, 10, sizeof(struct score_board), score_sort); diff --git a/src/scoreboard.h b/src/scoreboard.h index 328e526..788376b 100644 --- a/src/scoreboard.h +++ b/src/scoreboard.h @@ -1,8 +1,6 @@ #ifndef __SCOREBOARD_H__ #define __SCOREBOARD_H__ -#define SCORE_FILE "/gtkballs-scores" - struct score_board { gchar name[30]; gint score; @@ -16,8 +14,6 @@ struct score_board_full { gchar *rules; }; -gint score_setup(void); - void free_score_board_full(struct score_board_full *bf, gint nbf); gint write_score(struct score_board *, struct score_board_full *, gint); gint read_score(struct score_board *, struct score_board_full **, gint *); From 1cb51e315533bb9d06243fe67053f8ce7c3ad73a Mon Sep 17 00:00:00 2001 From: wdlkmpx Date: Sat, 30 Jan 2021 11:07:50 +0800 Subject: [PATCH 3/5] prefs.c: store gtkballs.ini in get_config_dir_file() --- src/prefs.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/prefs.c b/src/prefs.c index 13cce52..29f9ef8 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -15,7 +15,7 @@ #include "gtkballs.h" /* for _() */ #define BUFFER_SIZE 1024 -#define CONFIG_FILE_NAME ".gtkballsrc" +#define CONFIG_FILE_NAME "gtkballs.ini" gint _show_next_colors = TRUE; gint _show_path = TRUE; @@ -112,17 +112,6 @@ void pref_set_theme_name(gchar *name) { _theme_name = g_strdup(name); } -gchar *find_rc_file(void) { - gchar *rc_file = NULL; - - if (getenv("HOME")) { - rc_file = g_strdup_printf("%s/%s", getenv ("HOME"), CONFIG_FILE_NAME); - } else { /* unable to find $HOME, assuming current directory */ - rc_file = g_strdup(CONFIG_FILE_NAME); - } - - return rc_file; -} /* converts string to TRUE/FALSE. "true", "yes" or "1" is TRUE, otherwise - FALSE */ gboolean pref_str_to_bool(gchar *val) { @@ -152,7 +141,7 @@ void load_preferences(void) if (!_theme_name) { _theme_name = g_strdup(_default_theme_name); } - rc_file = find_rc_file(); + rc_file = get_config_dir_file (CONFIG_FILE_NAME); if ((fp = fopen(rc_file, "r"))) { while(fgets(buffer, BUFFER_SIZE, fp)) @@ -219,7 +208,7 @@ gchar *save_preferences (void) gchar *rc_file/*, *err*/; gchar *ret = NULL; - rc_file = find_rc_file(); + rc_file = get_config_dir_file (CONFIG_FILE_NAME); if ((fp = fopen(rc_file, "w"))) { write_pref_string(fp, "show_hints", pref_bool_to_str(_show_next_colors)); write_pref_string(fp, "show_path", pref_bool_to_str(_show_path)); From 11fc1fb3216f5d0c53a7df3daec43dc0d5846b26 Mon Sep 17 00:00:00 2001 From: wdlkmpx Date: Sat, 30 Jan 2021 11:08:41 +0800 Subject: [PATCH 4/5] gtkballs.c: store gtkballs-accel.map in get_config_dir_file() --- src/gtkballs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gtkballs.c b/src/gtkballs.c index 372614c..a5a071d 100644 --- a/src/gtkballs.c +++ b/src/gtkballs.c @@ -199,14 +199,14 @@ int main(int argc, char **argv) mw_set_hi_score(scoreboard[0].score); mw_set_user_score(0); - mapfile = g_strconcat(getenv("HOME"), G_DIR_SEPARATOR_S, ".gtkballs", - G_DIR_SEPARATOR_S, "accel.map", NULL); + mapfile = get_config_dir_file ("gtkballs-accel.map"); gtk_accel_map_load (mapfile); /* enter main application loop */ gtk_main(); gtk_accel_map_save (mapfile); + g_free (mapfile); return 0; } From d54080fbedf049e7ad51154073d29840d36c6c29 Mon Sep 17 00:00:00 2001 From: wdlkmpx Date: Fri, 12 Feb 2021 21:19:34 +0800 Subject: [PATCH 5/5] scoreboard.c: fix segfault --- src/scoreboard.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/scoreboard.c b/src/scoreboard.c index 688bc26..23d8ea2 100644 --- a/src/scoreboard.c +++ b/src/scoreboard.c @@ -98,6 +98,9 @@ gint read_score(struct score_board *b, struct score_board_full **bf, gint *nbf) memset(b, 0, sizeof(struct score_board) * 10); if (!(fp = fopen(score_file, "r"))) { + if (nbf) { + *nbf = 0; + } g_free (score_file); return TRUE; }