1 /*
2  *	binkleyforce -- unix FTN mailer project
3  *
4  *	Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
5  *
6  *	This program is free software; you can redistribute it and/or modify
7  *	it under the terms of the GNU General Public License as published by
8  *	the Free Software Foundation; either version 2 of the License, or
9  *	(at your option) any later version.
10  *
11  *	$Id: u_plock.c,v 1.1.1.1 2004/09/09 09:52:39 kstepanenkov Exp $
12  */
13 
14 #include "includes.h"
15 #include "confread.h"
16 #include "logger.h"
17 #include "util.h"
18 #include "outbound.h"
19 
plock_read(const char * lockname)20 pid_t plock_read(const char *lockname)
21 {
22 	FILE *fp = NULL;
23 	pid_t pid = 0;
24 
25 	ASSERT(lockname != NULL);
26 
27 	if( (fp = file_open(lockname, "rt")) )
28 	{
29 		if( fscanf(fp, "%d", &pid) != 1 )
30 			pid = 0;
31 		file_close(fp);
32 	}
33 
34 	DEB((D_OUTBOUND, "plock_read: file \"%s\", PID = %d", lockname, pid));
35 
36 	return pid;
37 }
38 
plock_write(const char * lockname)39 pid_t plock_write(const char *lockname)
40 {
41 	int fd, rc = PLOCK_OK;
42 	char buf[32];
43 
44 	ASSERT(lockname != NULL);
45 
46 	if( (fd = open(lockname, O_CREAT | O_RDWR, 0644)) < 0 )
47 		/* Don't log any errors, really we can have
48 		 * no outbound directory for this address */
49 		return PLOCK_ERROR;
50 
51 	chmod(lockname, 0644);
52 
53 	sprintf(buf, "%10d\n", (int)getpid());
54 
55 	if( write(fd, (char *)buf, strlen(buf)) != strlen(buf) )
56 	{
57 		logerr("can't write PID to the lock file \"%s\"", lockname);
58 		rc = PLOCK_ERROR;
59 	}
60 
61 	close(fd);
62 
63 	if( rc != PLOCK_OK )
64 		unlink(lockname);
65 
66 	return rc;
67 }
68 
69 /*
70  * Return codes:
71  *   PLOCK_OK
72  *   PLOCK_EXIST
73  *   PLOCK_ERROR
74  *   PLOCK_OURBSY
75  */
plock_check(const char * lockname)76 int plock_check(const char *lockname)
77 {
78 	pid_t pid = 0;
79 	struct stat st;
80 
81 	ASSERT(lockname != NULL);
82 
83 	if( stat(lockname, &st) && errno == ENOENT )
84 		return PLOCK_OK;
85 
86 	if( (pid = plock_read(lockname)) == 0 )
87 		return (errno == ENOENT) ? PLOCK_OK : PLOCK_ERROR;
88 
89 	if( pid == getpid() )
90 		return PLOCK_OURLOCK; /* Should we unlink it? */
91 
92 	if( kill(pid, 0) == -1 && errno == ESRCH )
93 	{
94 		/*
95 		 * That process no longer exists,
96 		 * try to remove lock file
97 		 */
98 		bf_log("remove stale lock file \"%s\", PID %d",
99 			lockname, (int)pid);
100 
101 		if( !unlink(lockname) )
102 			return PLOCK_OK;
103 		else
104 		{
105 			logerr("cannot remove lock file");
106 			return PLOCK_ERROR;
107 		}
108 	}
109 
110 	return PLOCK_EXIST; /* locking process still lives */
111 }
112 
plock_link(const char * lockname,const char * tmpname)113 int plock_link(const char *lockname, const char *tmpname)
114 {
115 	int rc;
116 
117 	ASSERT(lockname != NULL && tmpname != NULL);
118 
119 	if( !link(tmpname, lockname) )
120 	{
121 		unlink(tmpname);
122 		return PLOCK_OK;
123 	}
124 
125 	/* Can't create link */
126 	if( errno == EEXIST )
127 	{
128 		if( (rc = plock_check(lockname)) != PLOCK_OK )
129 		{
130 			if( rc == PLOCK_OURLOCK )
131 				rc = PLOCK_OK;
132 		}
133 		else if( link(tmpname, lockname) )
134 		{
135 			logerr("cannot link lock \"%s\" to \"%s\"", tmpname, lockname);
136 			rc = PLOCK_ERROR;
137 		} else
138 			rc = PLOCK_OK;
139 	}
140 	else
141 	{
142 		logerr("cannot link lock \"%s\" to \"%s\"", tmpname, lockname);
143 		rc = PLOCK_ERROR;
144 	}
145 
146 	if( unlink(tmpname) == -1 && errno != ENOENT )
147 		logerr("cannot remove lock file \"%s\"", tmpname);
148 
149 	return rc;
150 }
151 
plock_create(const char * lockname)152 int plock_create(const char *lockname)
153 {
154 	int rc;
155 	char *tmpname, *p;
156 
157 	ASSERT(lockname != NULL);
158 
159 	tmpname = xstrcpy(lockname);
160 	if( (p = strrchr(tmpname, DIRSEPCHR)) && p != tmpname )
161 		*++p = '\0';
162 	else
163 	{
164 		free(tmpname);
165 		return PLOCK_ERROR;
166 	}
167 	tmpname = xstrcat(tmpname, "bforce-XXXXXX");
168 
169 	if( (p = mktemp(tmpname)) == NULL )
170 	{
171 		logerr("can't generate unique file name from \"%s\"", tmpname);
172 		free(tmpname);
173 		return PLOCK_ERROR;
174 	}
175 
176 	if( (rc = plock_write(p)) == PLOCK_OK )
177 		rc = plock_link(lockname, p);
178 
179 	DEB((D_OUTBOUND, "out_bsy_createfile: createlink(\"%s\", \"%s\"), rc = %d",
180 		lockname, p, rc));
181 
182 	free(tmpname);
183 
184 	return rc;
185 }
186 
plock_remove(const char * lockname)187 int plock_remove(const char *lockname)
188 {
189 	pid_t pid = 0;
190 
191 	ASSERT(lockname != NULL);
192 
193 	DEB((D_OUTBOUND, "out_bsy_unlinkfile: want unlink \"%s\"", lockname));
194 
195 	if( (pid = plock_read(lockname)) == 0 )
196 		return 1;
197 
198 	if( pid == getpid() && unlink(lockname) == -1 )
199 		return 1;
200 
201 	return 0;
202 }
203 
204