libutil++  1.9.3
 All Classes Functions Variables
PidFile.cpp
1 /*
2 ** libutil++
3 ** $Id: PidFile.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: PidFile.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "PidFile.h"
12 
13 #include <stdio.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <unistd.h>
18 #include <sys/stat.h>
19 #include <sys/file.h>
20 
21 using namespace sella::util;
22 
23 PidFile::PidFile(const std::string &file, uid_t uid, gid_t gid) throw () : file(file), uid(uid), gid(gid) {
24  assert(!file.empty());
25 }
26 
27 PidFile::PidFile(const PidFile &other) : file(other.file), uid(other.uid), gid(other.gid) {
28 }
29 
30 PidFile::~PidFile() {
31 }
32 
33 PidFile& PidFile::operator=(const PidFile &other) throw () {
34  if (this != &other) {
35  this->file = other.file;
36  this->uid = other.uid;
37  this->gid = other.gid;
38  }
39 
40  return *this;
41 }
42 
43 const std::string& PidFile::get(void) const throw () {
44  return file;
45 }
46 
47 int PidFile::read(void) const throw (PidFileException) {
48  int pid;
49  FILE *h;
50 
51  if ((h = fopen(file.c_str(), "r")) == NULL) {
52  THROW(PidFileException, "Failed to open file '%s'", file.c_str());
53  }
54 
55  if (fscanf(h, "%d", &pid) == EOF) {
56  THROW(PidFileException, "Failed to read file '%s'", file.c_str());
57  }
58 
59  fclose(h);
60 
61  return pid;
62 }
63 
64 int PidFile::write(void) const throw (PidFileException) {
65  int fd, pid;
66  FILE *h;
67 
68  if ((fd = open(file.c_str(), O_RDWR|O_CREAT, 0644)) == -1 || (h = fdopen(fd, "r+")) == NULL) {
69  THROW(PidFileException, "Failed to open or create file '%s'", file.c_str());
70  }
71 
72  if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
73  if (fscanf(h, "%d", &pid) == EOF) {
74  pid = -1;
75  }
76  fclose(h);
77 
78  THROW(PidFileException, "Lock on file '%s' is already held by pid %d", file.c_str(), pid);
79  }
80 
81  pid = getpid();
82 
83  if (fprintf(h, "%d\n", pid) < 1) {
84  close(fd);
85 
86  THROW2(PidFileException, "Failed to write pid %d to file '%s'", pid, file.c_str());
87  }
88 
89  fflush(h);
90 
91  if (flock(fd, LOCK_UN) == -1) {
92  THROW2(PidFileException, "Failed to unlock file '%s'", file.c_str());
93  }
94 
95  if (uid != (__UID_T_TYPE) -1 || gid != (__GID_T_TYPE) -1) {
96  if (fchown(fd, uid, gid) != 0) {
97  THROW2(PidFileException, "Failed to change owner of file '%s' to %d:%d", file.c_str(), uid, gid);
98  }
99  }
100 
101  close(fd);
102 
103  return pid;
104 }
105 
106 void PidFile::remove(void) const throw (PidFileException) {
107  if (unlink(file.c_str()) != 0) {
108  THROW2(PidFileException, "Failed to remove file '%s'", file.c_str());
109  }
110 }
111 
112 bool PidFile::isOwner(void) const throw () {
113  int pid;
114 
115  try {
116  pid = read();
117  } catch (PidFileException) {
118  return false;
119  }
120 
121  return (pid == getpid());
122 }
123 
124 bool PidFile::isLive(void) const throw () {
125  int pid;
126 
127  try {
128  pid = read();
129  } catch (PidFileException) {
130  return false;
131  }
132 
133  if (pid == getpid()) {
134  return true;
135  }
136 
137  /* Doesn't actually send a signal, but checks for existance. */
138  if (pid == 0 || (kill(pid, 0) != 0 && errno == ESRCH)) {
139  return false;
140  }
141 
142  return true;
143 }
144 
145 bool PidFile::isFile(void) const throw () {
146  FILE *h;
147 
148  if ((h = fopen(file.c_str(), "r")) == NULL) {
149  return false;
150  }
151 
152  fclose(h);
153 
154  return true;
155 }
156 
157 const PidFile::shared PidFile::shared_ptr(const std::string &file, uid_t uid, gid_t gid) throw () {
158  return std::make_shared<PidFile>(file, uid, gid);
159 }
160 
161 /*
162 ** vim: noet ts=3 sw=3
163 */