Rev 108 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
69 | luk | 1 | |
2 | /// Application instance class implementation |
||
3 | /** |
||
4 | * \file appinst.cpp |
||
5 | * |
||
108 | luk | 6 | * Copyright (C) 2007, 2008, 2012 Lukas Jelinek, <lukas@aiken.cz> |
69 | luk | 7 | * |
8 | * This program is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of one of the following licenses: |
||
10 | * |
||
11 | * \li 1. X11-style license (see LICENSE-X11) |
||
12 | * \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL) |
||
13 | * \li 3. GNU General Public License, version 2 (see LICENSE-GPL) |
||
14 | * |
||
15 | * If you want to help with choosing the best license for you, |
||
16 | * please visit http://www.gnu.org/licenses/license-list.html. |
||
17 | * |
||
108 | luk | 18 | * Credits: |
19 | * Christian Ruppert (new include to build with GCC 4.4+) |
||
20 | * |
||
69 | luk | 21 | */ |
22 | |||
23 | |||
24 | #include <fcntl.h> |
||
25 | #include <unistd.h> |
||
26 | #include <errno.h> |
||
27 | #include <signal.h> |
||
108 | luk | 28 | #include <cstdio> |
69 | luk | 29 | |
30 | #include "appinst.h" |
||
31 | |||
73 | luk | 32 | /// Lockfile permissions (currently 0644) |
33 | #define APPLOCK_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) |
||
69 | luk | 34 | |
35 | |||
71 | luk | 36 | AppInstance::AppInstance(const std::string& rName, const std::string& rBase) |
37 | : m_fLocked(false) |
||
69 | luk | 38 | { |
71 | luk | 39 | std::string base(rBase); |
40 | if (base.empty()) |
||
41 | base = APPLOCK_BASEDIR; |
||
69 | luk | 42 | |
71 | luk | 43 | if (base[base.length()-1] == '/') |
44 | m_path = base + rName + ".pid"; |
||
45 | else |
||
46 | m_path = base + "/" + rName + ".pid"; |
||
69 | luk | 47 | } |
48 | |||
49 | AppInstance::~AppInstance() |
||
50 | { |
||
51 | try { |
||
52 | Unlock(); |
||
53 | } catch (AppInstException e) {} |
||
54 | } |
||
55 | |||
71 | luk | 56 | bool AppInstance::DoLock() |
69 | luk | 57 | { |
73 | luk | 58 | int fd = open(m_path.c_str(), O_WRONLY | O_CREAT | O_EXCL, APPLOCK_PERM); |
69 | luk | 59 | if (fd != -1) { |
60 | FILE* f = fdopen(fd, "w"); |
||
61 | if (f == NULL) { |
||
62 | AppInstException e(errno); |
||
63 | close(fd); |
||
64 | throw e; |
||
65 | } |
||
66 | |||
67 | if (fprintf(f, "%u", (unsigned) getpid()) <= 0) { |
||
68 | AppInstException e(errno); |
||
69 | fclose(f); |
||
70 | throw e; |
||
71 | } |
||
72 | |||
73 | if (fclose(f) != 0) |
||
74 | throw AppInstException(errno); |
||
75 | |||
76 | m_fLocked = true; |
||
77 | return true; |
||
78 | } |
||
79 | |||
80 | if (errno != EEXIST) |
||
81 | throw AppInstException(errno); |
||
82 | |||
83 | return false; |
||
84 | } |
||
85 | |||
86 | bool AppInstance::Lock() |
||
87 | { |
||
88 | for (int i=0; i<100; i++) { |
||
71 | luk | 89 | if (DoLock()) |
69 | luk | 90 | return true; |
91 | |||
71 | luk | 92 | FILE* f = fopen(m_path.c_str(), "r"); |
69 | luk | 93 | if (f == NULL) { |
94 | if (errno != ENOENT) |
||
95 | throw AppInstException(errno); |
||
96 | } |
||
97 | else { |
||
98 | unsigned pid; |
||
99 | ssize_t len = fscanf(f, "%u", &pid); |
||
100 | if (len == -1) { |
||
101 | AppInstException e(errno); |
||
102 | fclose(f); |
||
103 | throw e; |
||
104 | } |
||
105 | else if (len == 0) { |
||
106 | AppInstException e(EIO); |
||
107 | fclose(f); |
||
108 | throw e; |
||
109 | } |
||
110 | |||
111 | fclose(f); |
||
112 | |||
113 | int res = kill((pid_t) pid, 0); |
||
114 | if (res == 0) |
||
115 | return false; |
||
116 | |||
117 | if (errno != ESRCH) |
||
118 | throw AppInstException(errno); |
||
119 | |||
71 | luk | 120 | res = unlink(m_path.c_str()); |
69 | luk | 121 | if (res != 0 && errno != ENOENT) |
122 | throw AppInstException(errno); |
||
123 | } |
||
124 | } |
||
125 | |||
126 | return false; |
||
127 | } |
||
128 | |||
129 | void AppInstance::Unlock() |
||
130 | { |
||
131 | if (!m_fLocked) |
||
132 | return; |
||
133 | |||
71 | luk | 134 | if (unlink(m_path.c_str()) != 0 && errno != ENOENT) |
69 | luk | 135 | throw AppInstException(errno); |
136 | |||
137 | m_fLocked = false; |
||
138 | } |
||
139 | |||
140 | bool AppInstance::Exists() const |
||
141 | { |
||
142 | if (m_fLocked) |
||
143 | return true; |
||
144 | |||
71 | luk | 145 | FILE* f = fopen(m_path.c_str(), "r"); |
69 | luk | 146 | if (f == NULL) { |
147 | if (errno == ENOENT) |
||
148 | return false; |
||
149 | else |
||
150 | throw AppInstException(errno); |
||
151 | } |
||
152 | |||
153 | bool ok = false; |
||
154 | |||
155 | unsigned pid; |
||
156 | if (fscanf(f, "%u", &pid) == 1) { |
||
157 | if (kill((pid_t) pid, 0) == 0) |
||
158 | ok = true; |
||
159 | else if (errno != ESRCH) { |
||
160 | AppInstException e(errno); |
||
161 | fclose(f); |
||
162 | throw e; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | fclose(f); |
||
167 | |||
168 | return ok; |
||
169 | } |
||
170 | |||
171 | bool AppInstance::SendSignal(int iSigNo) const |
||
172 | { |
||
71 | luk | 173 | FILE* f = fopen(m_path.c_str(), "r"); |
69 | luk | 174 | if (f == NULL) { |
175 | if (errno == ENOENT) |
||
176 | return false; |
||
177 | else |
||
178 | throw AppInstException(errno); |
||
179 | } |
||
180 | |||
181 | bool ok = false; |
||
182 | |||
183 | unsigned pid; |
||
184 | if (fscanf(f, "%u", &pid) == 1) { |
||
185 | if (pid != (unsigned) getpid()) { |
||
186 | if (kill((pid_t) pid, iSigNo) == 0) { |
||
187 | ok = true; |
||
188 | } |
||
189 | else if (errno != ESRCH) { |
||
190 | AppInstException e(errno); |
||
191 | fclose(f); |
||
192 | throw e; |
||
193 | } |
||
194 | } |
||
195 | } |
||
196 | |||
197 | fclose(f); |
||
198 | |||
199 | return ok; |
||
200 | } |
||
201 |