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