http://www.azstarnet.com/~ymg/files/slsnif-0.4.0.tar.gz
[slsnif.git] / src / devlck.c
1 /*  devlck.c
2  *  Copyright (C) 2001 Yan "Warrior" Gurtovoy (ymg@azstarnet.com)
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 #include "devlck.h"
20
21 int dev_getstat(char *dev, devrec *dptr) {
22 /* validates device name, retreives stat structure for it,
23  * and generates names for the lock files.
24  * input: device name in *dev,
25  *        pointer to the devrec structure in *dptr
26  * returns: 0 on success, -1 on error.
27  */
28  
29     char buffer[256];
30     char *ptr;
31     int  tmp = 0;
32
33     /* check if device name looks good */
34     if (!(ptr = strrchr(dev, '/')) || ptr - dev >= strlen(dev)) {
35            fprintf(stderr, "\n%s %s\n", DINVNAME, dev);
36            return -1;
37     }
38     /* check if device exists and get major and minor numbers */
39     if (stat(dev, &(dptr->strec)) == -1) {
40            sprintf(buffer, "%s %s", DACCFAIL, dev);
41            perror(buffer);
42            return -1;
43     }
44     /* generate FSSTND-1.2 lock file name */
45     sprintf(dptr->fsstnd, "%s/LCK..%s", LOCK_PATH, ++ptr);
46     /* generate SVr4 lock file name */
47     if ((dptr->strec).st_rdev >= TTYAUX_MAJOR * 256 + 64 &&
48                         (dptr->strec).st_rdev <= TTYAUX_MAJOR * 256 + 127) {
49            tmp = (TTY_MAJOR - TTYAUX_MAJOR) * 256;
50     }
51     sprintf(dptr->svr4, "%s/LCK.%03d.%03d", LOCK_PATH,
52                 (int) MAJOR(tmp + (dptr->strec).st_rdev),
53                 (int) MINOR(tmp + (dptr->strec).st_rdev));    
54     return 0;
55 }
56
57 pid_t dev_readpid(const char *fname) {
58 /* reads pid from a specified lock file
59  * input: name of the file in fname
60  * returns: pid on success, -1 on error
61  */
62     
63     FILE *fd;
64     int  pid, tmp;
65
66     if (!(fd = fopen(fname, "r"))) {
67         return -1;
68     } else {
69         /* get owner's pid from the file */
70         tmp = fscanf(fd, "%d", &pid);
71         /* close file */
72         fclose(fd);
73         return tmp == 1 ? pid : -1;
74     }
75 }
76 pid_t dev_checklock(char *dev, devrec *drec) {
77 /* performs actual check of the locks, called
78  * internally from dev_getlock() and dev_unlock
79  * returns: 0 if device is not locked, -1 on error,
80  *          pid of the process that owns device otherwise.
81  */
82     char        buffer[256];
83     char        *lckname;
84     pid_t       pid;
85     int         j;
86
87     for (j = 0; j < 2; j++) {
88         if (!j)
89             /* check for FSSTND-1.2 lock */
90             lckname = drec->fsstnd;
91         else
92             /* check for a SVr4 style lock */
93             lckname = drec->svr4;
94         /* try to open the lock file */
95         if ((pid = dev_readpid(lckname)) == -1) {
96             /* don't bail out if file doesn't exist */
97             if (errno != ENOENT) {
98                 sprintf(buffer, "Failed to open lock file %s", lckname);
99                 perror(buffer);
100                 return -1;
101             }
102         } else {
103             /* check if we got a valid pid */
104             if (!kill(pid, 0)) {
105                 return pid;
106             }
107             /* it's a stale lock, let's remove it */
108             if (unlink(lckname) == -1) {
109                 sprintf(buffer, "Failed to remove stale lock %s", lckname);
110                 perror(buffer);
111                 return -1;
112             }
113         }
114     } /* end for */
115     return 0; /* no valid lock found */
116 }
117
118 pid_t dev_getlock(char *dev) {
119 /* 
120  * checks if device is locked
121  * input: device name in *dev, i.e. "/dev/ttyS0" 
122  * returns: 0 if device is not locked, -1 on error,
123  *          pid of the process that owns device otherwise.
124  */
125
126     pid_t       pid;
127     devrec      *drec;
128     
129     /* allocate memory for drec */
130     if (!(drec = malloc(sizeof(devrec)))) {
131         fprintf(stderr, "\nMemory allocation failed! \n");
132         return -1;
133     }
134     /* get drec for the device */
135     if (dev_getstat(dev, drec) == -1) {
136         free(drec);
137         return -1;
138     }
139     pid = dev_checklock(dev, drec);
140     free(drec);
141     return pid;
142 }
143
144 pid_t dev_setlock(char *dev) {
145 /* locks specified device
146  * input: device name in *dev, i.e. "/dev/ttyS0" 
147  * returns: lock owner's pid on success, -1 on error
148  */
149  
150     mode_t      oldmask;
151     devrec  *drec;
152     pid_t   ourpid, pid1, pid2 = 0;
153     char        buffer[256];
154     char    lckname[256];
155     FILE    *fd;
156
157     /* allocate memory for drec */
158     if (!(drec = malloc(sizeof(devrec)))) {
159         fprintf(stderr, "\nMemory allocation failed! \n");
160         return -1;
161     }   
162     /* give rw permissions to lock files created */
163     oldmask = umask(0);
164     /* get drec for the device */
165     if (dev_getstat(dev, drec) == -1) {
166         free(drec);
167         return -1;
168     }
169     /* get our own pid */
170     ourpid = getpid();
171     /* check if device is already locked */
172     if ((pid1 = dev_checklock(dev, drec)) == -1) {
173         /* something went wrong while checking the lock - bail out */
174         free(drec);
175         return -1;
176     } else if (pid1) {
177         /* it's locked already */
178         if (pid1 == ourpid) {
179             /* we own this device, do nothing */
180             free(drec);
181             return ourpid;
182         } else {
183             /* it's locked by someone else */
184             fprintf(stderr, "Unable to obtain lock. Device %s is locked by pid %li\n",
185                               dev, (long int) pid1);
186             free(drec);
187             return -1;
188         }
189     } else {
190         /* create a file with our pid in the name - should be unique */
191         sprintf(lckname, "%s/LCK...%d", LOCK_PATH, (int) ourpid);
192         if (!(fd = fopen(lckname, "w"))) {
193             sprintf(buffer, "Failed to create lock file %s", lckname);
194             perror(buffer);
195             free(drec);
196             return -1;
197         } else {
198             fprintf(fd, "%d\n", (int) ourpid);
199             fclose(fd);
200         }
201         /* create SVr4 lock */
202         if (link(lckname, drec->svr4) == -1) {
203             sprintf(buffer, "Failed to create lock file %s", drec->svr4);
204             perror(buffer);
205             free(drec);
206             unlink(lckname);
207             return -1;
208         }
209         /* create FSSTND-1.2 lock */
210         if (link(lckname, drec->fsstnd) == -1) {
211             sprintf(buffer, "Failed to create lock file %s", drec->fsstnd);
212             perror(buffer);
213             unlink(drec->svr4);
214             unlink(lckname);
215             free(drec);
216             return -1;
217         }
218         /* both locks created succesfully, let's make sure nothing went wrong */
219         if ((pid1 = dev_readpid(drec->fsstnd)) != ourpid ||
220                         (pid2 = dev_readpid(drec->svr4)) != ourpid) {
221             /* something went wrong, we don't own at least one of the locks */
222             /* unlink files we own and bail out */
223             unlink(lckname);
224             if (pid1 == ourpid)
225                 unlink(drec->fsstnd);
226             else if (pid2 == ourpid)
227                 unlink(drec->svr4);
228             if (pid1 != ourpid) {
229                 sprintf(buffer,"%s %li", RACECOND, (long int) pid1);
230                 perror(buffer);
231             } 
232             if (pid2 != ourpid && pid2 != pid1) {
233                 sprintf(buffer, "%s %li", RACECOND, (long int) pid2);
234                 perror(buffer);
235             }
236             free(drec);
237             return -1;
238         }
239         /* we own the lock */
240         unlink(lckname);
241         free(drec);
242         return ourpid;    
243     }
244 }
245
246 int dev_unlock(char *dev) {
247 /* unlocks specified device
248  * input: device name in *dev, i.e. "/dev/ttyS0"
249  * returns: 0 on success, -1 on error
250  */
251
252     pid_t   ourpid, pid1;
253     devrec  *drec;
254     char        buffer[256];
255
256     /* allocate memory for drec */
257     if (!(drec = malloc(sizeof(devrec)))) {
258         fprintf(stderr, "\nMemory allocation failed! \n");
259         return -1;
260     }   
261     /* get drec for the device */
262     if (dev_getstat(dev, drec) == -1) {
263         free(drec);
264         return -1;
265     }
266     /* get our own pid */
267     ourpid = getpid();
268     /* check if device is already locked */
269     if ((pid1 = dev_checklock(dev, drec)) == -1) {
270         /* something went wrong while checking the lock - bail out */
271         free(drec);
272         return -1;
273     } else if (!pid1) {
274         /* it's not locked, so we have nothing to do */
275         free(drec);
276         return 0;
277     } else {
278         /* it's locked */
279         if (pid1 == ourpid) {
280             /* we own this device, remove lock */
281             if (unlink(drec->fsstnd) == -1) {
282                 sprintf(buffer, "%s %s", REMFAIL, drec->fsstnd);
283                 perror(buffer);
284             }
285             if (unlink(drec->svr4) == -1) {
286                 sprintf(buffer, "%s %s", REMFAIL, drec->svr4);
287                 perror(buffer);
288             }                
289             free(drec);
290             return 0;
291         } else {
292             /* it's locked by someone else */
293             fprintf(stderr, "Unable to remove lock. Device %s is locked by pid %li\n",
294                               dev, (long int) pid1);
295             free(drec);
296             return -1;
297         }
298     }    
299 }