1
2 #include "system.h"
3
4 #include <errno.h>
5 #include <fcntl.h>
6
7 #include <rpm/rpmlog.h>
8 #include <rpm/rpmfileutil.h>
9
10 #include "lib/rpmlock.h"
11
12 #include "debug.h"
13
14 /* Internal interface */
15
16 struct rpmlock_s {
17 int fd;
18 int openmode;
19 char *path;
20 char *descr;
21 int fdrefs;
22 };
23
rpmlock_new(const char * lock_path,const char * descr)24 static rpmlock rpmlock_new(const char *lock_path, const char *descr)
25 {
26 rpmlock lock = (rpmlock) malloc(sizeof(*lock));
27
28 if (lock != NULL) {
29 mode_t oldmask = umask(022);
30 lock->fd = open(lock_path, O_RDWR|O_CREAT, 0644);
31 (void) umask(oldmask);
32
33 if (lock->fd == -1) {
34 if (errno == EACCES)
35 lock->fd = open(lock_path, O_RDONLY);
36 if (lock->fd == -1) {
37 free(lock);
38 lock = NULL;
39 } else {
40 lock->openmode = RPMLOCK_READ;
41 }
42 } else {
43 lock->openmode = RPMLOCK_WRITE | RPMLOCK_READ;
44 }
45 if (lock) {
46 lock->path = xstrdup(lock_path);
47 lock->descr = xstrdup(descr);
48 lock->fdrefs = 1;
49 }
50 }
51 return lock;
52 }
53
rpmlock_free(rpmlock lock)54 static void rpmlock_free(rpmlock lock)
55 {
56 if (--lock->fdrefs == 0) {
57 free(lock->path);
58 free(lock->descr);
59 (void) close(lock->fd);
60 free(lock);
61 }
62 }
63
rpmlock_acquire(rpmlock lock,int mode)64 static int rpmlock_acquire(rpmlock lock, int mode)
65 {
66 int res = 0;
67
68 if (!(mode & lock->openmode))
69 return res;
70
71 if (lock->fdrefs > 1) {
72 res = 1;
73 } else {
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
92 lock->fdrefs += res;
93
94 return res;
95 }
96
rpmlock_release(rpmlock lock)97 static void rpmlock_release(rpmlock lock)
98 {
99 /* if not locked then we must not release */
100 if (lock->fdrefs <= 1)
101 return;
102
103 if (--lock->fdrefs == 1) {
104 struct flock info;
105 info.l_type = F_UNLCK;
106 info.l_whence = SEEK_SET;
107 info.l_start = 0;
108 info.l_len = 0;
109 info.l_pid = 0;
110 (void) fcntl(lock->fd, F_SETLK, &info);
111 }
112 }
113
114
115 /* External interface */
rpmlockNew(const char * lock_path,const char * descr)116 rpmlock rpmlockNew(const char *lock_path, const char *descr)
117 {
118 rpmlock lock = rpmlock_new(lock_path, descr);
119 if (!lock) {
120 rpmlog(RPMLOG_ERR, _("can't create %s lock on %s (%s)\n"),
121 descr, lock_path, strerror(errno));
122 }
123 return lock;
124 }
125
rpmlockAcquire(rpmlock lock)126 int rpmlockAcquire(rpmlock lock)
127 {
128 int locked = 0; /* assume failure */
129 int myerrno = errno;
130 int maywait = isatty(STDIN_FILENO); /* dont wait within scriptlets */
131 errno = myerrno;
132
133 if (lock) {
134 locked = rpmlock_acquire(lock, RPMLOCK_WRITE);
135 if (!locked && (lock->openmode & RPMLOCK_WRITE) && maywait) {
136 rpmlog(RPMLOG_WARNING, _("waiting for %s lock on %s\n"),
137 lock->descr, lock->path);
138 locked = rpmlock_acquire(lock, (RPMLOCK_WRITE|RPMLOCK_WAIT));
139 }
140 if (!locked) {
141 rpmlog(RPMLOG_ERR, _("can't create %s lock on %s (%s)\n"),
142 lock->descr, lock->path, strerror(errno));
143 }
144 }
145 return locked;
146 }
147
rpmlockRelease(rpmlock lock)148 void rpmlockRelease(rpmlock lock)
149 {
150 if (lock)
151 rpmlock_release(lock);
152 }
153
rpmlockNewAcquire(const char * lock_path,const char * descr)154 rpmlock rpmlockNewAcquire(const char *lock_path, const char *descr)
155 {
156 rpmlock lock = rpmlockNew(lock_path, descr);
157 if (!rpmlockAcquire(lock))
158 lock = rpmlockFree(lock);
159 return lock;
160 }
161
rpmlockFree(rpmlock lock)162 rpmlock rpmlockFree(rpmlock lock)
163 {
164 if (lock) {
165 rpmlock_release(lock);
166 rpmlock_free(lock);
167 }
168 return NULL;
169 }
170
171
172