use static variable, not define, for lock file path.
[platform/upstream/rpm.git] / lib / rpmlock.c
1
2 #include "system.h"
3
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <string.h>
9
10 #include <rpmlib.h>
11
12 #include "rpmts.h"
13
14 #include "rpmlock.h"
15
16 /* Internal interface */
17
18 #define RPMLOCK_FILE "/var/lib/rpm/transaction.lock"
19
20 /*@observer@*/ /*@unchecked@*/
21 static const char * _rpmlock_file = RPMLOCK_FILE;
22
23 enum {
24         RPMLOCK_READ   = 1 << 0,
25         RPMLOCK_WRITE  = 1 << 1,
26         RPMLOCK_WAIT   = 1 << 2,
27 };
28
29 typedef struct {
30         int fd;
31         int openmode;
32 } * rpmlock;
33
34 /*@null@*/
35 static rpmlock rpmlock_new(const char *rootdir)
36         /*@globals fileSystem @*/
37         /*@modifies fileSystem @*/
38 {
39         rpmlock lock = (rpmlock) malloc(sizeof(*lock));
40         if (lock) {
41                 mode_t oldmask = umask(022);
42                 char *path = (char *)malloc(strlen(rootdir)+
43                                             strlen(RPMLOCK_FILE)+2);
44                 if (!path) {
45                         free(lock);
46                         return NULL;
47                 }
48                 sprintf(path, "%s/%s", rootdir, RPMLOCK_FILE);
49                 lock->fd = open(RPMLOCK_FILE, O_RDWR|O_CREAT, 0644);
50                 (void) umask(oldmask);
51
52 /*@-branchstate@*/
53                 if (lock->fd == -1) {
54                         lock->fd = open(RPMLOCK_FILE, O_RDONLY);
55                         if (lock->fd == -1) {
56                                 free(lock);
57                                 lock = NULL;
58                         } else {
59                                 lock->openmode = RPMLOCK_READ;
60                         }
61                 } else {
62                         lock->openmode = RPMLOCK_WRITE | RPMLOCK_READ;
63                 }
64 /*@=branchstate@*/
65         }
66 /*@-compdef@*/
67         return lock;
68 /*@=compdef@*/
69 }
70
71 static void rpmlock_free(/*@only@*/ /*@null@*/ rpmlock lock)
72         /*@globals fileSystem, internalState @*/
73         /*@modifies lock, fileSystem, internalState @*/
74 {
75         if (lock) {
76                 (void) close(lock->fd);
77                 free(lock);
78         }
79 }
80
81 static int rpmlock_acquire(/*@null@*/ rpmlock lock, int mode)
82         /*@*/
83 {
84         int res = 0;
85         if (lock && (mode & lock->openmode)) {
86                 struct flock info;
87                 int cmd;
88                 if (mode & RPMLOCK_WAIT)
89                         cmd = F_SETLKW;
90                 else
91                         cmd = F_SETLK;
92                 if (mode & RPMLOCK_READ)
93                         info.l_type = F_RDLCK;
94                 else
95                         info.l_type = F_WRLCK;
96                 info.l_whence = SEEK_SET;
97                 info.l_start = 0;
98                 info.l_len = 0;
99                 info.l_pid = 0;
100                 if (fcntl(lock->fd, cmd, &info) != -1)
101                         res = 1;
102         }
103         return res;
104 }
105
106 static void rpmlock_release(/*@null@*/ rpmlock lock)
107         /*@globals internalState @*/
108         /*@modifies internalState @*/
109 {
110         if (lock) {
111                 struct flock info;
112                 info.l_type = F_UNLCK;
113                 info.l_whence = SEEK_SET;
114                 info.l_start = 0;
115                 info.l_len = 0;
116                 info.l_pid = 0;
117                 (void) fcntl(lock->fd, F_SETLK, &info);
118         }
119 }
120
121
122 /* External interface */
123
124 void *rpmtsAcquireLock(rpmts ts)
125 {
126         const char *rootDir = rpmtsRootDir(ts);
127         rpmlock lock;
128
129         if (!rootDir)
130                 rootDir = "/";
131         lock = rpmlock_new(rootDir);
132 /*@-branchstate@*/
133         if (!lock) {
134                 rpmMessage(RPMMESS_ERROR, _("can't create transaction lock\n"));
135         } else if (!rpmlock_acquire(lock, RPMLOCK_WRITE)) {
136                 if (lock->openmode & RPMLOCK_WRITE)
137                         rpmMessage(RPMMESS_WARNING,
138                                    _("waiting for transaction lock\n"));
139                 if (!rpmlock_acquire(lock, RPMLOCK_WRITE|RPMLOCK_WAIT)) {
140                         rpmMessage(RPMMESS_ERROR,
141                                    _("can't create transaction lock\n"));
142                         rpmlock_free(lock);
143                         lock = NULL;
144                 }
145         }
146 /*@=branchstate@*/
147         return lock;
148 }
149
150 void rpmtsFreeLock(void *lock)
151 {
152         rpmlock_release((rpmlock)lock); /* Not really needed here. */
153         rpmlock_free((rpmlock)lock);
154 }
155
156