libmsngr  1.1
 All Data Structures Files Functions Variables Enumerations Enumerator Macros Groups
msngr_lockfile.c
Go to the documentation of this file.
1 /*******************************************************************************
2 *
3 * COPYRIGHT (C) 2010 Battelle Memorial Institute. All Rights Reserved.
4 *
5 ********************************************************************************
6 *
7 * Author:
8 * name: Brian Ermold
9 * phone: (509) 375-2277
10 * email: brian.ermold@pnl.gov
11 *
12 ********************************************************************************
13 *
14 * REPOSITORY INFORMATION:
15 * $Revision: 12907 $
16 * $Author: ermold $
17 * $Date: 2012-02-23 07:10:44 +0000 (Thu, 23 Feb 2012) $
18 *
19 ********************************************************************************
20 *
21 * NOTE: DOXYGEN is used to generate documentation for this file.
22 *
23 *******************************************************************************/
24 
25 /** @file msngr_lockfile.c
26  * Lock File Functions.
27  */
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <errno.h>
34 
35 #include "messenger.h"
36 
37 /**
38  * @defgroup LOCK_FILES Lock Files
39  */
40 /*@{*/
41 
42 /*******************************************************************************
43  * Private Functions
44  */
45 /** @privatesection */
46 
47 /*******************************************************************************
48  * Public Functions
49  */
50 /** @publicsection */
51 
52 /**
53  * Remove a lockfile.
54  *
55  * The space pointed to by errstr should be large enough to
56  * hold MAX_LOCKFILE_ERROR bytes. Any less than that and the
57  * error message could be truncated.
58  *
59  * @param path - path to the lockfile
60  * @param name - name of the lockfile
61  * @param errlen - length of the error message buffer
62  * @param errstr - output: error message
63  *
64  * @return
65  * - 1 if successful
66  * - 0 the lockfile did not exist
67  * - -1 if an error occurred
68  */
70  const char *path,
71  const char *name,
72  size_t errlen,
73  char *errstr)
74 {
75  char lockfile[PATH_MAX];
76 
77  snprintf(lockfile, PATH_MAX, "%s/%s", path, name);
78 
79  /* Check to see if the lockfile exists */
80 
81  if (access(lockfile, F_OK) == 0) {
82 
83  if (unlink(lockfile) != 0) {
84 
85  snprintf(errstr, errlen,
86  "Could not remove lockfile: %s\n"
87  " -> %s\n",
88  lockfile, strerror(errno));
89 
90  return(-1);
91  }
92 
93  return(1);
94  }
95  else if (errno != ENOENT) {
96 
97  snprintf(errstr, errlen,
98  "Could not access lockfile: %s\n"
99  " -> %s\n",
100  lockfile, strerror(errno));
101 
102  return(-1);
103  }
104 
105  return(0);
106 }
107 
108 /**
109  * Create a lockfile.
110  *
111  * This function will print the time, hostname and process id
112  * into the lockfile.
113  *
114  * The space pointed to by errstr should be large enough to
115  * hold MAX_LOCKFILE_ERROR bytes. Any less than that and the
116  * error message could be truncated.
117  *
118  * @param path - path to the lockfile
119  * @param name - name of the lockfile
120  * @param flags - control flags (reserved for future use)
121  * @param errlen - length of the error message buffer
122  * @param errstr - output: error message
123  *
124  * @return
125  * - 2 if a stale lockfile was found and removed.
126  * - 1 if successful
127  * - 0 the lockfile already exists (error message will be set)
128  * - -1 if an error occurred
129  */
131  const char *path,
132  const char *name,
133  int flags,
134  size_t errlen,
135  char *errstr)
136 {
137  char lockfile[PATH_MAX];
138  FILE *lockfile_fp;
139  char hostname[256];
140  pid_t pid;
141  time_t pid_time;
142  char time_string[32];
143  int nbytes;
144 
145  char lockfile_string[256];
146  char *chrp;
147  char *lockfile_host;
148  pid_t lockfile_pid;
149  time_t lockfile_time;
150 
151  int retval = 1;
152 
153  flags = 0; /* prevent compiler warning */
154 
155  snprintf(lockfile, PATH_MAX, "%s/%s", path, name);
156 
157  /* Get hostname */
158 
159  if (gethostname(hostname, 256) == -1) {
160 
161  snprintf(errstr, errlen,
162  "Could not get hostname for lockfile:\n"
163  " -> %s\n"
164  " -> %s\n",
165  lockfile, strerror(errno));
166 
167  return(-1);
168  }
169 
170  /* Make sure the path to the lockfile exists */
171 
172  if (!msngr_make_path(path, 00775, errlen, errstr)) {
173  return(0);
174  }
175 
176  /* Check to see if the lockfile already exists */
177 
178  if (access(lockfile, F_OK) == 0) {
179 
180  /* Open the existing lockfile */
181 
182  lockfile_fp = fopen(lockfile, "r");
183 
184  if (!lockfile_fp) {
185 
186  snprintf(errstr, errlen,
187  "Lockfile exists but could not be opened:\n"
188  " -> %s\n"
189  " -> %s\n",
190  lockfile, strerror(errno));
191 
192  return(-1);
193  }
194 
195  /* Read in the identifier line */
196 
197  if (!fgets(lockfile_string, 256, lockfile_fp)) {
198 
199  snprintf(errstr, errlen,
200  "Lockfile exists but could not be read:\n"
201  " -> %s\n"
202  " -> %s\n",
203  lockfile, strerror(errno));
204 
205  return(-1);
206  }
207 
208  /* Duplicate the line and set pointer to hostname */
209 
210  lockfile_host = strdup(lockfile_string);
211  if (!lockfile_host) {
212 
213  snprintf(errstr, errlen,
214  "Lockfile exists:\n"
215  " -> %s\n"
216  " -> but could not parse identifier string: '%s'\n"
217  " -> memory allocation error",
218  lockfile, lockfile_string);
219 
220  return(-1);
221  }
222 
223  /* Get the pid of the locked process */
224 
225  chrp = strchr(lockfile_host, ':');
226  if (!chrp) {
227 
228  snprintf(errstr, errlen,
229  "Lockfile exists:\n"
230  " -> %s\n"
231  " -> but has an invalid identifier string: '%s'\n",
232  lockfile, lockfile_string);
233 
234  free(lockfile_host);
235  return(-1);
236  }
237  *chrp = '\0';
238 
239  lockfile_pid = atoi(++chrp);
240 
241  /* Get the start time of the locked process */
242 
243  chrp = strchr(chrp, ':');
244  if (!chrp) {
245 
246  snprintf(errstr, errlen,
247  "Lockfile exists:\n"
248  " -> %s\n"
249  " -> but has an invalid identifier string: '%s'\n",
250  lockfile, lockfile_string);
251 
252  free(lockfile_host);
253  return(-1);
254  }
255 
256  lockfile_time = (time_t)atol(++chrp);
257 
258  /* Check if this process is still running. */
259 
260  pid_time = msngr_get_process_start_time(lockfile_pid);
261 
262  if ((strcmp(lockfile_host, hostname) == 0) &&
263  (lockfile_time == pid_time) ) {
264 
265  snprintf(errstr, errlen,
266  "Lockfile exists:\n"
267  " -> %s\n"
268  " -> %s\n",
269  lockfile, lockfile_string);
270 
271  free(lockfile_host);
272  return(0);
273  }
274 
275  free(lockfile_host);
276 
277  /* We found a stale lockfile so clean it up and continue... */
278 
279  if (lockfile_remove(path, name, errlen, errstr) < 0) {
280  return(-1);
281  }
282 
283  retval = 2;
284  }
285  else if (errno != ENOENT) {
286 
287  snprintf(errstr, errlen,
288  "Could not check if lockfile exists:\n"
289  " -> %s\n"
290  " -> %s\n",
291  lockfile, strerror(errno));
292 
293  return(-1);
294  }
295 
296  /* Get process ID and start time */
297 
298  pid = getpid();
299  pid_time = msngr_get_process_start_time(pid);
300  msngr_format_time(pid_time, time_string);
301 
302  /* Create the lockfile */
303 
304  lockfile_fp = fopen(lockfile, "w");
305 
306  if (!lockfile_fp) {
307 
308  snprintf(errstr, errlen,
309  "Could not create lockfile:\n"
310  " -> %s\n"
311  " -> %s\n",
312  lockfile, strerror(errno));
313 
314  return(-1);
315  }
316 
317  nbytes = fprintf(lockfile_fp, "%s:%d:%ld %s\n",
318  hostname, (int)pid, (long)pid_time, time_string);
319 
320  if (nbytes < 0) {
321 
322  snprintf(errstr, errlen,
323  "Could not write to lockfile:\n"
324  " -> %s\n"
325  " -> %s\n",
326  lockfile, strerror(errno));
327 
328  fclose(lockfile_fp);
329  unlink(lockfile);
330 
331  return(-1);
332  }
333 
334  if (fclose(lockfile_fp) != 0) {
335 
336  snprintf(errstr, errlen,
337  "Could not close lockfile:\n"
338  " -> %s\n"
339  " -> %s\n",
340  lockfile, strerror(errno));
341 
342  unlink(lockfile);
343 
344  return(-1);
345  }
346 
347  return(retval);
348 }
349 
350 /*@}*/