
When packaging games, one of the operations I often have to do to the source code is modifying it so that it uses absolute file and directory names instead of relative ones. When coders develop for Windows, or when they develop their games to be able to play them from their home directory, they just would go that way and won’t care about it, but when the idea is installing the files in the system, the
Filesystem Hierarchy Standard (
FHS) must be respected, and thus things will need to be place in their proper directories.
For read-only files, this is not a big deal, all that has to be done is replacing the relative file name in the file opening commands with the absolute one, doing fopen(”/usr/share/games/package/dir/file”) instead of fopen(”dir/file”). I usually prefer to do it like fopen(DATADIR “/dir/file”) and set DATADIR from the Makefile, with a -DDATADIR=\”/usr/share/games/package\” switch added to the CFLAGS, and maybe also setting it inside the code if it’s not previously defined (#ifndef and so).
There are some files and directories in which doing this is not possible, because they want read-write permissions. This files include saving the configuration, hiscores, new levels created with the game editor, game saves and so. They might be moved to some directory under “/var/lib/”, and create a new group en the system so that it’s writable, and so on. I don’t like that approach a single bit. I prefer to move all tthat data to the user’s directory. This is not as straightforward as it was for read-only data, but it’s not really that difficult anyway. It would be more or less like:
#ifndef _WIN32
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <pwd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
#ifndef _WIN32
char file[PATH_MAX];
char *home;
struct passwd *passwd;
if (!getuid() !(home = getenv("HOME")))
passwd = getpwuid (getuid());
home=passwd->pw_dir;
if (!home)
fprintf(stderr, "$HOME is not defined.n");
exit(-1)
if (strlen(home) > PATH_MAX - sizeof("/.package/settings.ini"))
fprintf(stderr, "$HOME is excessively long.n");
exit(-1)
snprintf(file, sizeof(file), "%s/.package", home);
mkdir(file, S_IRWXU S_IRWXG S_IROTH S_IXOTH) == 0;
strncat(file, "/settings.ini", sizeof(file)-1);
#else
char file[21];
snprintf(file, sizeof(file), "./Data/settings.ini");
#endif
FILE *f = fopen(file, "w");
Sometimes you also need that the files are already created, you can check if they already exist with stat(), and then acting accordingly, either creating them from your C code, or maybe triggering a system() shell call whith whatever is needed.
struct stat stat_buf;
stat(file, &stat_buf);
if (stat(file, &stat_buf) == -1)
int settings_fd = creat(file, O_WRONLY);
close(settings_fd);
NOTE: I’ve updated the code to add some suggestions. Thanks to Gon ri Le Bouder and Nico Golde.