1 /* pidfile handling for DBMail, many thanks to Tridge and Samba
2  * for making their software available under the GNU GPL.
3  *
4  * Modified for DBMail by Aaron Stone, July 9, 2004.
5  */
6 
7 /* this code is broken - there is a race condition with the unlink (tridge) */
8 
9 /*
10    Unix SMB/CIFS implementation.
11    pidfile handling
12    Copyright (C) Andrew Tridgell 1998
13 
14    This program is free software; you can redistribute it and/or modify
15    it under the terms of the GNU General Public License as published by
16    the Free Software Foundation; either version 2 of the License, or
17    (at your option) any later version.
18 
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License for more details.
23 
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28 
29 #include "dbmail.h"
30 #define THIS_MODULE "pidfile"
31 
32 /* These are used by pidfile_remove. */
33 static FILE *pidfile_to_close;
34 static char *pidfile_to_remove;
35 
36 /* Check if a process exists. */
process_exists(pid_t pid)37 static int process_exists(pid_t pid)
38 {
39 	if (pid > 0)
40 		return (kill(pid, 0) == 0 || errno != ESRCH);
41 	return 0;
42 }
43 
44 /* Return the pid in a pidfile, or return 0
45  * if the process or pidfile does not exist. */
pidfile_pid(const char * pidFile)46 static pid_t pidfile_pid(const char *pidFile)
47 {
48 	FILE *f;
49 	char pidstr[20];
50 	unsigned ret;
51 
52 	memset(pidstr, 0, sizeof(pidstr));
53 
54 	if (!(f = fopen(pidFile, "r"))) {
55 		return 0;
56 	}
57 
58 	if (fread(pidstr, sizeof(char), sizeof(pidstr)-1, f) <= 0) {
59 		goto noproc;
60 	}
61 
62 	ret = atoi(pidstr);
63 
64 	if (!process_exists((pid_t)ret)) {
65 		goto noproc;
66 	}
67 
68 	fclose(f);
69 	return (pid_t)ret;
70 
71  noproc:
72 	fclose(f);
73 	unlink(pidFile);
74 	return 0;
75 }
76 
pidfile_remove(void)77 static void pidfile_remove(void)
78 {
79 	int res;
80 
81 	if (pidfile_to_close) {
82 		res = fclose(pidfile_to_close);
83 		if (res) TRACE(TRACE_ERR, "Error closing pidfile: [%s].",
84 			strerror(errno));
85 		pidfile_to_close = NULL;
86 	}
87 
88 	if (pidfile_to_remove) {
89 		res = unlink(pidfile_to_remove);
90 		if (res) TRACE(TRACE_ERR, "Error unlinking pidfile [%s]: [%s].",
91 			pidfile_to_remove, strerror(errno));
92 		g_free(pidfile_to_remove);
93 		pidfile_to_remove = NULL;
94 	}
95 
96 }
97 
98 /* Create a pidfile and leave it open. */
pidfile_create(const char * pidFile,pid_t pid)99 void pidfile_create(const char *pidFile, pid_t pid)
100 {
101 	FILE *f;
102 	pid_t oldpid;
103 
104 	oldpid = pidfile_pid(pidFile);
105 
106 	if (oldpid != 0) {
107 		TRACE(TRACE_EMERG, "File [%s] exists and process id [%d] is running.",
108 			pidFile, (int)pid);
109 	}
110 
111 	if (!(f = fopen(pidFile, "w"))) {
112 		int serr = errno;
113 		TRACE(TRACE_EMERG, "open pidfile [%s] failed: [%s]",
114 				pidFile, strerror(serr));
115 		return;
116 	}
117 	if (chmod(pidFile, 0644)) {
118 		int serr = errno;
119 		TRACE(TRACE_EMERG, "chown pidfile [%s] failed: [%s]",
120 			       	pidFile, strerror(serr));
121 		fclose(f);
122 		return;
123 	}
124 
125 	fprintf(f, "%u\n", pid);
126 	fflush(f);
127 
128 	/* Leave pid file open & locked for the duration,
129 	 * but close and remove it upon termination.  */
130 	atexit(pidfile_remove);
131 
132 	pidfile_to_close = f;
133 	pidfile_to_remove = g_strdup(pidFile);
134 
135 }
136 
137