Imported Upstream version 1.5
[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 #include "config.h"
12
13
14 Unique::Unique()
15 {
16     // Get path to the current binary.
17     // It's a bit ugly, I guess, to rely on /proc, but it'll do for now.
18     // Also, /proc has different layout on Linux and BSD, so there is ugly
19     // conditional compilation in configure script.
20     char* filename = new char[PATH_MAX + 1];
21     int bytes = readlink(PROC_SELF_PATH, filename,
22                          sizeof(*filename) * PATH_MAX);
23     if (bytes > PATH_MAX - 1) {
24         bytes = PATH_MAX;
25     }
26     filename[bytes] = '\0';
27
28     // Get unique key for semaphore.
29     semaphore_key = ftok(filename, 1);
30     if (semaphore_key == -1) {
31         throw new UniqueException("ftok failed");
32     }
33     delete[] filename;
34 }
35
36 Unique::~Unique()
37 {
38 }
39
40 bool Unique::isRunning()
41 {
42     int semid = semget(semaphore_key, 0, 0);
43     if (semid == -1) {
44         return false;
45     }
46     return true;
47 }
48
49 void Unique::start()
50 {
51     if (!isRunning()) {
52         // Create semaphore; fail if already exists.
53         int semid = semget(semaphore_key, 1, IPC_CREAT | IPC_EXCL | 0660);
54         if (semid == -1) {
55             throw UniqueException("semget failed while creating semaphore");
56         }
57
58         // Perform an operation on semaphore so that semctl(GETPID) returns
59         // current PID.
60         struct sembuf ops = {0, 1, 0};
61         if (semop(semid, &ops, 1) == -1) {
62             throw UniqueException("semop failed");
63         }
64     }
65 }
66
67 void Unique::signal(int signal_id)
68 {
69     kill(signal_id);
70 }
71 void Unique::kill()
72 {
73     kill(SIGTERM);
74 }
75 void Unique::kill(int signal_id)
76 {
77     if (isRunning()) {
78         // Get semaphore; fail if not present.
79         int semid = semget(semaphore_key, 1, 0660);
80         if (semid == -1) {
81             throw UniqueException("semget failed while trying to kill");
82         }
83
84         // Get the pid from semaphore value (stored before) to kill the process.
85         int pid = semctl(semid, 0, GETPID, 0);
86         if (pid <= 0) {
87             throw UniqueException("semctl(GETPID) failed");
88         }
89         if (::kill(pid, signal_id)) {
90             throw UniqueException("kill failed");
91         }
92     }
93 }
94
95 void Unique::stop()
96 {
97     // Clean up semaphore, if exists.
98     int semid = semget(semaphore_key, 1, 0660);
99     if (semid != -1) {
100         semctl(semid, 0, IPC_RMID, 0);
101     }
102 }