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