Another pile of read-only constants marked as such..
[platform/upstream/rpm.git] / lib / rpmlock.c
1
2 #include "system.h"
3
4 #include <rpm/rpmlog.h>
5 #include <rpm/rpmmacro.h>
6 #include <rpm/rpmfileutil.h>
7 #include <rpm/rpmts.h>
8
9 #include "lib/rpmlock.h"
10
11 #include "debug.h"
12
13 /* Internal interface */
14
15 #define RPMLOCK_PATH LOCALSTATEDIR "/lock/rpm/transaction"
16 static const char * const rpmlock_path_default = "%{?_rpmlock_path}";
17 static const char * rpmlock_path = NULL;
18
19 enum {
20         RPMLOCK_READ   = 1 << 0,
21         RPMLOCK_WRITE  = 1 << 1,
22         RPMLOCK_WAIT   = 1 << 2,
23 };
24
25 typedef struct {
26         int fd;
27         int openmode;
28 } * rpmlock;
29
30 static rpmlock rpmlock_new(const char *rootdir)
31 {
32         rpmlock lock = (rpmlock) malloc(sizeof(*lock));
33
34         /* XXX oneshot to determine path for fcntl lock. */
35         if (rpmlock_path == NULL) {
36             char * t = rpmGenPath(rootdir, rpmlock_path_default, NULL);
37             if (t == NULL || *t == '\0' || *t == '%')
38                 t = strdup(RPMLOCK_PATH);
39             rpmlock_path = xstrdup(t);
40             t = _free(t);
41         }
42         if (lock != NULL) {
43                 mode_t oldmask = umask(022);
44                 lock->fd = open(rpmlock_path, O_RDWR|O_CREAT, 0644);
45                 (void) umask(oldmask);
46
47                 if (lock->fd == -1) {
48                         lock->fd = open(rpmlock_path, O_RDONLY);
49                         if (lock->fd == -1) {
50                                 free(lock);
51                                 lock = NULL;
52                         } else {
53                                 lock->openmode = RPMLOCK_READ;
54                         }
55                 } else {
56                         lock->openmode = RPMLOCK_WRITE | RPMLOCK_READ;
57                 }
58         }
59         return lock;
60 }
61
62 static void rpmlock_free(rpmlock lock)
63 {
64         if (lock) {
65                 (void) close(lock->fd);
66                 free(lock);
67         }
68 }
69
70 static int rpmlock_acquire(rpmlock lock, int mode)
71 {
72         int res = 0;
73         if (lock && (mode & lock->openmode)) {
74                 struct flock info;
75                 int cmd;
76                 if (mode & RPMLOCK_WAIT)
77                         cmd = F_SETLKW;
78                 else
79                         cmd = F_SETLK;
80                 if (mode & RPMLOCK_READ)
81                         info.l_type = F_RDLCK;
82                 else
83                         info.l_type = F_WRLCK;
84                 info.l_whence = SEEK_SET;
85                 info.l_start = 0;
86                 info.l_len = 0;
87                 info.l_pid = 0;
88                 if (fcntl(lock->fd, cmd, &info) != -1)
89                         res = 1;
90         }
91         return res;
92 }
93
94 static void rpmlock_release(rpmlock lock)
95 {
96         if (lock) {
97                 struct flock info;
98                 info.l_type = F_UNLCK;
99                 info.l_whence = SEEK_SET;
100                 info.l_start = 0;
101                 info.l_len = 0;
102                 info.l_pid = 0;
103                 (void) fcntl(lock->fd, F_SETLK, &info);
104         }
105 }
106
107
108 /* External interface */
109
110 void *rpmtsAcquireLock(rpmts ts)
111 {
112         const char *rootDir = rpmtsRootDir(ts);
113         rpmlock lock;
114
115         if (!rootDir || rpmtsChrootDone(ts))
116                 rootDir = "/";
117         lock = rpmlock_new(rootDir);
118         if (!lock) {
119                 rpmlog(RPMLOG_ERR, _("can't create transaction lock on %s\n"), rpmlock_path);
120         } else if (!rpmlock_acquire(lock, RPMLOCK_WRITE)) {
121                 if (lock->openmode & RPMLOCK_WRITE)
122                         rpmlog(RPMLOG_WARNING,
123                                    _("waiting for transaction lock on %s\n"), rpmlock_path);
124                 if (!rpmlock_acquire(lock, RPMLOCK_WRITE|RPMLOCK_WAIT)) {
125                         rpmlog(RPMLOG_ERR,
126                                    _("can't create transaction lock on %s\n"), rpmlock_path);
127                         rpmlock_free(lock);
128                         lock = NULL;
129                 }
130         }
131         return lock;
132 }
133
134 void rpmtsFreeLock(void *lock)
135 {
136         rpmlock_release((rpmlock)lock); /* Not really needed here. */
137         rpmlock_free((rpmlock)lock);
138 }
139
140