Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / global / pidfile.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2011 New Dream Network
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15 #include "common/debug.h"
16 #include "common/errno.h"
17 #include "common/safe_io.h"
18 #include "global/pidfile.h"
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #if defined(__FreeBSD__)
27 #include <sys/param.h>
28 #endif
29
30 #include "include/compat.h"
31
32 //
33 // derr can be used for functions exclusively called from pidfile_write
34 //
35 // cerr must be used for functions called by pidfile_remove because
36 // logging is not functional when it is called. cerr output is lost
37 // when the caller is daemonized but it will show if not (-f)
38 //
39 #define dout_context g_ceph_context
40 #define dout_prefix *_dout
41 #define dout_subsys ceph_subsys_
42
43 struct pidfh {
44   int pf_fd;
45   char pf_path[PATH_MAX + 1];
46   dev_t pf_dev;
47   ino_t pf_ino;
48
49   pidfh() {
50     reset();
51   }
52   ~pidfh() {
53     remove();
54   }
55
56   bool is_open() {
57     return pf_path[0] != '\0' && pf_fd != -1;
58   }
59   void reset() {
60     pf_fd = -1;
61     memset(pf_path, 0, sizeof(pf_path));
62     pf_dev = 0;
63     pf_ino = 0;
64   }
65   int verify();
66   int remove();
67   int open(const md_config_t *conf);
68   int write();
69 };
70
71 static pidfh *pfh = nullptr;
72
73 int pidfh::verify() {
74   // check that the file we opened still is the same
75   if (pf_fd == -1)
76     return -EINVAL;
77   struct stat st;
78   if (stat(pf_path, &st) == -1)
79     return -errno;
80   if (st.st_dev != pf_dev || st.st_ino != pf_ino)
81     return -ESTALE;
82   return 0;
83 }
84
85 int pidfh::remove()
86 {
87   if (!pf_path[0])
88     return 0;
89
90   int ret;
91   if ((ret = verify()) < 0) {
92     if (pf_fd != -1) {
93       ::close(pf_fd);
94       reset();
95     }
96     return ret;
97   }
98
99   // seek to the beginning of the file before reading
100   ret = ::lseek(pf_fd, 0, SEEK_SET);
101   if (ret < 0) {
102     std::cerr << __func__ << " lseek failed "
103               << cpp_strerror(errno) << std::endl;
104     return -errno;
105   }
106
107   // check that the pid file still has our pid in it
108   char buf[32];
109   memset(buf, 0, sizeof(buf));
110   ssize_t res = safe_read(pf_fd, buf, sizeof(buf));
111   ::close(pf_fd);
112   if (res < 0) {
113     std::cerr << __func__ << " safe_read failed "
114               << cpp_strerror(-res) << std::endl;
115     return res;
116   }
117
118   int a = atoi(buf);
119   if (a != getpid()) {
120     std::cerr << __func__ << " the pid found in the file is "
121               << a << " which is different from getpid() "
122               << getpid() << std::endl;
123     return -EDOM;
124   }
125   ret = ::unlink(pf_path);
126   if (ret < 0) {
127     std::cerr << __func__ << " unlink " << pf_path << " failed "
128               << cpp_strerror(errno) << std::endl;
129     return -errno;
130   }
131   reset();
132   return 0;
133 }
134
135 int pidfh::open(const md_config_t *conf)
136 {
137   int len = snprintf(pf_path, sizeof(pf_path),
138                     "%s", conf->pid_file.c_str());
139
140   if (len >= (int)sizeof(pf_path))
141     return -ENAMETOOLONG;
142
143   int fd;
144   fd = ::open(pf_path, O_CREAT|O_RDWR, 0644);
145   if (fd < 0) {
146     int err = errno;
147     derr << __func__ << ": failed to open pid file '"
148          << pf_path << "': " << cpp_strerror(err) << dendl;
149     reset();
150     return -err;
151   }
152   struct stat st;
153   if (fstat(fd, &st) == -1) {
154     int err = errno;
155     derr << __func__ << ": failed to fstat pid file '"
156          << pf_path << "': " << cpp_strerror(err) << dendl;
157     ::close(fd);
158     reset();
159     return -err;
160   }
161
162   pf_fd = fd;
163   pf_dev = st.st_dev;
164   pf_ino = st.st_ino;
165
166   struct flock l = {
167     .l_type = F_WRLCK,
168     .l_whence = SEEK_SET,
169     .l_start = 0,
170     .l_len = 0
171   };
172   int r = ::fcntl(pf_fd, F_SETLK, &l);
173   if (r < 0) {
174     derr << __func__ << ": failed to lock pidfile "
175          << pf_path << " because another process locked it." << dendl;
176     ::close(pf_fd);
177     reset();
178     return -errno;
179   }
180   return 0;
181 }
182
183 int pidfh::write()
184 {
185   if (!is_open())
186     return 0;
187
188   char buf[32];
189   int len = snprintf(buf, sizeof(buf), "%d\n", getpid());
190   if (::ftruncate(pf_fd, 0) < 0) {
191     int err = errno;
192     derr << __func__ << ": failed to ftruncate the pid file '"
193          << pf_path << "': " << cpp_strerror(err) << dendl;
194     return -err;
195   }
196   ssize_t res = safe_write(pf_fd, buf, len);
197   if (res < 0) {
198     derr << __func__ << ": failed to write to pid file '"
199          << pf_path << "': " << cpp_strerror(-res) << dendl;
200     return res;
201   }
202   return 0;
203 }
204
205 void pidfile_remove()
206 {
207   if (pfh != nullptr)
208     delete pfh;
209   pfh = nullptr;
210 }
211
212 int pidfile_write(const md_config_t *conf)
213 {
214   if (conf->pid_file.empty()) {
215     dout(0) << __func__ << ": ignore empty --pid-file" << dendl;
216     return 0;
217   }
218
219   assert(pfh == nullptr);
220
221   pfh = new pidfh();
222   if (atexit(pidfile_remove)) {
223     derr << __func__ << ": failed to set pidfile_remove function "
224          << "to run at exit." << dendl;
225     return -EINVAL;
226   }
227
228   int r = pfh->open(conf);
229   if (r != 0) {
230     pidfile_remove();
231     return r;
232   }
233
234   r = pfh->write();
235   if (r != 0) {
236     pidfile_remove();
237     return r;
238   }
239
240   return 0;
241 }