Skip to content

Commit

Permalink
Rewrite Unique thingy again
Browse files Browse the repository at this point in the history
This time it first uses config file path for ftok, if present. If not
present, it tries to obtain executable path via different methods.

Relying on argv[0] was a bad idea, because:

* some programs that launch gsimplecal may not set it properly;
* when launched from $PATH, it contains only file name, no path.

Hopefully, this fixes #17 this time.
  • Loading branch information
dmedvinsky committed Nov 6, 2013
1 parent 91473a7 commit aecda27
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 18 deletions.
5 changes: 4 additions & 1 deletion configure.ac
Expand Up @@ -60,6 +60,7 @@ AC_CHECK_HEADERS([iostream \
sys/types.h \
sys/ipc.h \
sys/sem.h \
sys/sysctl.h \
signal.h \
limits.h])

Expand All @@ -72,14 +73,16 @@ AC_CHECK_FUNCS([atexit \
execl \
fork \
ftok \
getexecname \
gettimeofday \
kill \
readlink \
semctl \
semget \
setenv \
signal \
strlcpy])
strlcpy \
sysctl])


# Flags
Expand Down
73 changes: 59 additions & 14 deletions src/Unique.cpp
@@ -1,33 +1,31 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <limits.h>
#include <sys/sem.h>
#include <signal.h>
#include <sys/sem.h>
#include <sys/sysctl.h>
#include <sys/types.h>

#include "Unique.hpp"
#include "config.h"


Unique::Unique(const char* const cmd)
Unique::Unique(const char *const path)
{
char* filename = new char[PATH_MAX + 1];
#if HAVE_STRLCPY
strlcpy(filename, cmd, PATH_MAX);
#else
strncpy(filename, cmd, PATH_MAX);
filename[PATH_MAX] = '\0';
#endif
char pathname[PATH_MAX + 1];

if (path) {
getPathnameFromFile(path, *&pathname);
} else {
getPathnameFromExe(*&pathname);
}

// Get unique key for semaphore.
semaphore_key = ftok(filename, 1);
semaphore_key = ftok(pathname, 1);
if (semaphore_key == -1) {
throw new UniqueException("ftok failed");
}
delete[] filename;
}

Unique::~Unique()
Expand Down Expand Up @@ -97,3 +95,50 @@ void Unique::stop()
semctl(semid, 0, IPC_RMID, 0);
}
}

void Unique::getPathnameFromFile(const char *const path, char* pathname)
{
#if HAVE_STRLCPY
strlcpy(pathname, path, PATH_MAX + 1);
#else
strncpy(pathname, path, PATH_MAX);
pathname[PATH_MAX] = '\0';
#endif
}

void Unique::getPathnameFromExe(char* pathname)
{
#if HAVE_GETEXECNAME && HAVE_STRLCPY
// Try getexecname (Solaris).
const char* execname = getexecname();
strlcpy(pathname, execname, PATH_MAX + 1);
#elif HAVE_SYSCTL && defined(CTL_KERN) && defined(KERN_PROC) && defined(KERN_PROC_PATHNAME)
// Try sysctl call (FreeBSD).
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
size_t cb = PATH_MAX;
sysctl(mib, 4, pathname, &cb, NULL, 0);
#else
// Try reading procfs links.
const char *const paths[] = {
"/proc/self/exe", // Linux
"/proc/curproc/exe", // NetBSD
"/proc/curproc/file", // FreeBSD with procfs
NULL
};
for (const char *const *path = paths; *path; path++) {
pathname[0] = 0;
int bytes = readlink(*path, pathname, sizeof(*pathname) * PATH_MAX);
if (bytes > 0) {
if (bytes > PATH_MAX - 1) {
bytes = PATH_MAX;
}
pathname[bytes] = '\0';
break;
}
}
#endif
}
5 changes: 4 additions & 1 deletion src/Unique.hpp
Expand Up @@ -25,7 +25,7 @@ class UniqueException : public exception
class Unique
{
public:
Unique(const char* const cmd);
Unique(const char* const path);
~Unique();

bool isRunning();
Expand All @@ -38,6 +38,9 @@ class Unique
protected:
key_t semaphore_key;

private:
void getPathnameFromFile(const char *const path, char* pathname);
void getPathnameFromExe(char* pathname);
};

#endif
5 changes: 3 additions & 2 deletions src/gsimplecal.cpp
Expand Up @@ -70,7 +70,9 @@ int main(int argc, char *argv[])
}
}

Unique* unique = new Unique(argv[0]);
Config* config = Config::getInstance();

Unique* unique = new Unique(config->getPath());
if (unique->isRunning()) {
try {
if (argc >= 2 && strcmp(argv[1], "next_month") == 0) {
Expand All @@ -96,7 +98,6 @@ int main(int argc, char *argv[])
signal(SIGUSR2, &signal_handler);
signal(SIGCHLD, SIG_IGN);

Config* config = Config::getInstance();
if (config->force_lang.length()) {
// Must be done before gtk_init call.
setenv("LANG", config->force_lang.c_str(), 1);
Expand Down

2 comments on commit aecda27

@WorMzy
Copy link

@WorMzy WorMzy commented on aecda27 Nov 6, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's working here (GTK2 build), thank you.

@dmedvinsky
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for letting me know!

I'm planning to make a new release soon if things go smooth and no issues arise. Not that you'd care, since you seem to be using latest build, but whatever. 😏

Please sign in to comment.