00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <errno.h>
00015 #include <string.h>
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 #include <sstream>
00019 #include <stdio.h>
00020
00021
00022 #include "assa/CommonUtils.h"
00023 #include "assa/PidFileLock.h"
00024
00025 using namespace ASSA;
00026
00027
00028
00029
00030
00031 PidFileLock::
00032 PidFileLock () :
00033 m_fd (-1),
00034 m_error (0),
00035 m_error_msg ("no errors")
00036 {
00037 trace_with_mask ("PidFileLock::PidFileLock", PIDFLOCK);
00038
00039 l_whence = SEEK_SET;
00040 l_start = l_len = l_pid = 0;
00041 }
00042
00043 PidFileLock::
00044 ~PidFileLock ()
00045 {
00046 trace_with_mask ("PidFileLock::~PidFileLock", PIDFLOCK);
00047
00048 if (m_fd != -1) {
00049 if (unlock_region () == 0) {
00050 DL((PIDFLOCK,"PID file unlocked.\n"));
00051
00052 unlink (m_filename.c_str ());
00053 DL((PIDFLOCK,"PID file removed.\n"));
00054 }
00055 close (m_fd);
00056 DL((PIDFLOCK,"PID lock file closed.\n"));
00057 }
00058 }
00059
00060 bool
00061 PidFileLock::
00062 lock (const string& fname_)
00063 {
00064 trace_with_mask ("PidFileLock::lock", PIDFLOCK);
00065
00066 int val;
00067 int len;
00068 m_filename = Utils::strenv (fname_.c_str ());
00069 val = len = 0;
00070
00071 DL((PIDFLOCK,"PID lock file: \"%s\"\n", m_filename.c_str ()));
00072
00073 if (open_pid_file (m_filename) < 0) {
00074 goto done;
00075 }
00076 DL((PIDFLOCK,"PID lock file opened and locked (fd=%d).\n", m_fd));
00077
00080 if (ftruncate (m_fd, 0) < 0) {
00081 log_error("ftruncate() error");
00082 goto done;
00083 }
00084 DL((PIDFLOCK,"PID lock file truncated.\n"));
00085
00088 if (write_pid () < 0) {
00089 log_error("write(PID) error");
00090 goto done;
00091 }
00092
00095 if ((val = ::fcntl(m_fd, F_GETFD, 0)) < 0) {
00096 log_error("fcntl(F_GETFD) error");
00097 goto done;
00098 }
00099 val |= FD_CLOEXEC;
00100
00101 if (::fcntl (m_fd, F_SETFD, val) < 0) {
00102 log_error("fcntl(F_SETFD) error");
00103 goto done;
00104 }
00105 DL((PIDFLOCK,"CLOSE-ON-EXEC is set on FD.\n"));
00106
00107 done:
00108 if (get_error () != 0) {
00109 ::close (m_fd);
00110 m_fd = -1;
00111 }
00112 return m_error == 0 ? true : false;
00113 }
00114
00115
00125 int
00126 PidFileLock::
00127 write_pid ()
00128 {
00129 trace_with_mask ("PidFileLock::write_pid", PIDFLOCK);
00130
00131 std::ostringstream mypid;
00132 size_t len;
00133
00134 this->l_pid = getpid ();
00135 mypid << this->l_pid << std::ends;
00136 len = strlen (mypid.str ().c_str ());
00137
00138 #ifdef __CYGWIN__
00139
00140 unlock_region ();
00141 lock_region_exclusive ();
00142
00143 if (write (m_fd, mypid.str ().c_str (), len) != len) {
00144 return -1;
00145 }
00146 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", l_pid));
00147 unlock_region ();
00148 lock_region ();
00149
00150 #else // POSIX-compliant locks
00151
00152 if (write (m_fd, mypid.str ().c_str (), len) != len) {
00153 return -1;
00154 }
00155 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", this->l_pid));
00156
00157 #endif
00158 return 0;
00159 }
00160
00161
00162
00163
00164
00165
00166 int
00167 PidFileLock::
00168 lock_region ()
00169 {
00170 trace_with_mask ("PidFileLock::lock_region", PIDFLOCK);
00171 int ret;
00172
00173 #ifdef __CYGWIN__
00174 this->l_type = F_RDLCK;
00175 #else
00176 this->l_type = F_WRLCK;
00177 #endif
00178
00179 this->l_start = 0;
00180 this->l_whence = SEEK_SET;
00181 this->l_len = 0;
00182
00183 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00184
00185 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, %s) returned: %d\n",
00186 m_fd,
00187 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
00188 ret));
00189
00190 return (ret);
00191 }
00192
00193
00194 int
00195 PidFileLock::
00196 lock_region_exclusive ()
00197 {
00198 trace_with_mask ("PidFileLock::lock_region_exclusive", PIDFLOCK);
00199 int ret = 0;
00200
00201 #ifdef __CYGWIN__
00202 this->l_type = F_WRLCK;
00203 this->l_start = 0;
00204 this->l_whence = SEEK_SET;
00205 this->l_len = 0;
00206
00207 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00208
00209 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_WRLCK) returned: %d\n", m_fd, ret));
00210 #endif
00211
00212 return (ret);
00213 }
00214
00215 int
00216 PidFileLock::
00217 unlock_region ()
00218 {
00219 trace_with_mask ("PidFileLock::unlock_region", PIDFLOCK);
00220 int ret;
00221
00222 this->l_type = F_UNLCK;
00223 this->l_start = 0;
00224 this->l_whence = SEEK_SET;
00225 this->l_len = 0;
00226
00227 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00228
00229 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_UNLCK) returned: %d\n",
00230 m_fd, ret));
00231
00232 return (ret);
00233 }
00234
00235
00264 int
00265 PidFileLock::
00266 get_lock_status ()
00267 {
00268 trace_with_mask ("PidFileLock::get_lock_status", PIDFLOCK);
00269 int ret;
00270
00271 #ifndef __CYGWIN__ // POSIX-compliant locking
00272
00273 this->l_type = F_WRLCK;
00274 this->l_start = 0;
00275 this->l_whence = SEEK_SET;
00276 this->l_len = 0;
00277
00278 ret = ::fcntl (m_fd, F_GETLK, static_cast<struct flock*>(this));
00279
00280 DL((PIDFLOCK,"fcntl(fd=%d, F_GETLK, %s) returned: %d\n",
00281 m_fd,
00282 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
00283 ret));
00284 if (ret < 0) {
00285 EL ((PIDFLOCK,"fcntl() failed. l_pid = %d\n", this->l_pid));
00286 }
00287 return (ret);
00288
00289 #else // CYGWIN
00290
00291 if (lock_region_exclusive () < 0) {
00292 if (unlock_region () < 0) {
00293 char buf[64];
00294 pid_t pid;
00295 this->l_type = F_RDLCK;
00296 if (read (m_fd, buf, 64) > 0) {
00297 if (sscanf (buf, "%d", &pid) == 1) {
00298 this->l_pid = pid;
00299 }
00300 }
00301 else {
00302 this->l_pid = 1;
00303 }
00304 }
00305 }
00306 else {
00307 unlock_region ();
00308 }
00309 return (0);
00310
00311 #endif
00312 }
00313
00318 pid_t
00319 PidFileLock::
00320 test_region ()
00321 {
00322 trace_with_mask ("PidFileLock::test_region", PIDFLOCK);
00323 int ret;
00324
00325 ret = get_lock_status ();
00326
00327 if (ret < 0) {
00328 DL((PIDFLOCK,"Failed to retrieve lock status.\n"));
00329 return 1;
00330 }
00331 if (this->l_type == F_UNLCK) {
00332 DL((PIDFLOCK,"Region is not locked.\n"));
00333 return(0);
00334 }
00335
00336 DL((PIDFLOCK,"Region is already locked by PID %d\n", this->l_pid));
00337 return (this->l_pid);
00338 }
00339
00340
00341 void
00342 PidFileLock::
00343 dump (void)
00344 {
00345 trace_with_mask("PidFileLock::dump", PIDFLOCK);
00346
00347 DL((PIDFLOCK,"m_filename : \"%s\"\n", m_filename.c_str()));
00348 DL((PIDFLOCK,"m_error : %d\n", get_error ()));
00349 DL((PIDFLOCK,"m_error_msg: \"%s\"\n", get_error_msg ()));
00350 DL((PIDFLOCK,"m_fd : %d\n", m_fd));
00351
00352 if (m_fd == -1) return;
00353
00354 test_region ();
00355
00356 if (this->l_type == F_RDLCK)
00357 DL((PIDFLOCK,"l_type : F_RDLCK"));
00358
00359 if (this->l_type == F_WRLCK)
00360 DL((PIDFLOCK,"l_type : F_WRLCK"));
00361
00362 if (this->l_type == F_UNLCK)
00363 DL((PIDFLOCK,"l_type : F_UNLCK"));
00364
00365 DL((PIDFLOCK,"l_whence : %s\n",
00366 this->l_whence == SEEK_SET ? "SEEK_SET" :
00367 this->l_whence == SEEK_CUR ? "SEEK_CUR" : "SEEK_END"));
00368
00369 DL((PIDFLOCK,"l_start : %d\n", this->l_start));
00370 DL((PIDFLOCK,"l_len : %d\n", this->l_len ));
00371 DL((PIDFLOCK,"l_pid : %ld\n", this->l_pid ));
00372 }
00373
00374 void
00375 PidFileLock::
00376 log_error (const char* msg_)
00377 {
00378 m_error = errno;
00379 EL((ERROR, "Error: \"Failed to get a lock on PID file - %s\".\n", msg_));
00380 }
00381
00382
00387 pid_t
00388 PidFileLock::
00389 open_pid_file (const std::string& fname_)
00390 {
00391 trace_with_mask("PidFileLock::open_pid_file", PIDFLOCK);
00392
00393 m_fd = ::open (fname_.c_str (), O_WRONLY|O_CREAT, 0644);
00394 if (m_fd < 0) {
00395 log_error("open() error.");
00396 return -1;
00397 }
00398
00403 pid_t owner_pid;
00404 if ((owner_pid = test_region ()) > 0) {
00405 log_error ("PID file is already locked (by someone).");
00406 m_error = EPERM;
00407 return -1;
00408 }
00409
00412 if (lock_region () < 0) {
00413 if (errno == EACCES || errno == EAGAIN) {
00414 log_error("PID file is locked by another process");
00415 }
00416 else {
00417 log_error("write lock error");
00418 }
00419 return -1;
00420 }
00421
00422 return 0;
00423 }