7df248b96d8df38750045095378715f324cad1c0
[debian/gsimplecal.git] / src / Unique.cpp
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <sys/types.h>
5 #include <sys/ipc.h>
6 #include <limits.h>
7 #include <sys/sem.h>
8 #include <signal.h>
9
10 #include "Unique.hpp"
11
12
13 union semun
14 {
15     int val;
16 };
17
18
19 Unique::Unique()
20 {
21     // Get path to the current binary.
22     // It's a bit ugly, I guess, to rely on /proc, but it'll do for now.
23     char szTmp[32];
24     sprintf(szTmp, "/proc/%d/exe", getpid());
25
26     char* filename = new char[PATH_MAX + 1];
27     int bytes = readlink(szTmp, filename,
28                          sizeof(*filename) * PATH_MAX);
29     if (bytes > PATH_MAX - 1) {
30         bytes = PATH_MAX;
31     }
32     filename[bytes] = '\0';
33
34     // Get unique key for semaphore.
35     semaphore_key = ftok(filename, 1);
36     if (semaphore_key == -1) {
37         throw new UniqueException("ftok failed");
38     }
39     delete[] filename;
40 }
41
42 Unique::~Unique()
43 {
44 }
45
46 bool Unique::isRunning()
47 {
48     int semid = semget(semaphore_key, 0, 0);
49     if (semid == -1) {
50         return false;
51     }
52     return true;
53 }
54
55 void Unique::start()
56 {
57     if (!isRunning()) {
58         // Create semaphore; fail if already exists.
59         int semid = semget(semaphore_key, 1,
60                            IPC_CREAT | IPC_EXCL | 0660);
61         if (semid == -1) {
62             throw UniqueException("semget failed while creating semaphore");
63         }
64
65         // Set initial semaphore value to the current pid, so we could use it to
66         // kill the process from the second instance.
67         union semun semopts;
68         semopts.val = getpid();
69         if (semctl(semid, 0, SETVAL, semopts) == -1) {
70             throw UniqueException("semctl (SETVAL) failed");
71         }
72     }
73 }
74
75 void Unique::signal(int signal_id)
76 {
77     kill(signal_id);
78 }
79 void Unique::kill()
80 {
81     kill(SIGTERM);
82 }
83 void Unique::kill(int signal_id)
84 {
85     if (isRunning()) {
86         // Get semaphore; fail if not present.
87         int semid = semget(semaphore_key, 1, 0660);
88         if (semid == -1) {
89             throw UniqueException("semget failed while trying to kill");
90         }
91
92         // Get the pid from semaphore value (stored before) to kill the process.
93         int pid = semctl(semid, 0, GETVAL, 0);
94         if (pid <= 0) {
95             throw UniqueException("semctl (GETVAL) failed");
96         }
97         if (::kill(pid, signal_id)) {
98             throw UniqueException("kill failed");
99         }
100     }
101 }
102
103 void Unique::stop()
104 {
105     int semid = semget(semaphore_key, 1, 0660);
106     if (semid != -1) {
107         semctl(semid, 0, IPC_RMID, 0);
108     }
109 }