Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * file.c - file handling functions
4 : : *
5 : : * Copyright © 1994, 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 : : * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
7 : : *
8 : : * This is free software; you can redistribute it and/or modify
9 : : * it under the terms of the GNU General Public License as published by
10 : : * the Free Software Foundation; either version 2 of the License, or
11 : : * (at your option) any later version.
12 : : *
13 : : * This is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : * GNU General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU General Public License
19 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <config.h>
23 : : #include <compat.h>
24 : :
25 : : #include <sys/types.h>
26 : : #include <sys/stat.h>
27 : :
28 : : #include <errno.h>
29 : : #include <fcntl.h>
30 : : #include <unistd.h>
31 : :
32 : : #include <dpkg/dpkg.h>
33 : : #include <dpkg/i18n.h>
34 : : #include <dpkg/pager.h>
35 : : #include <dpkg/fdio.h>
36 : : #include <dpkg/buffer.h>
37 : : #include <dpkg/file.h>
38 : : #include <dpkg/execname.h>
39 : :
40 : : /**
41 : : * Get the current working directory.
42 : : *
43 : : */
44 : : void
45 : 9 : file_getcwd(struct varbuf *cwd)
46 : : {
47 : 9 : varbuf_reset(cwd);
48 : 9 : varbuf_grow(cwd, 64);
49 [ - + ]: 9 : while (getcwd(cwd->buf, cwd->size) == NULL)
50 : 0 : varbuf_grow(cwd, cwd->size * 2);
51 : 9 : varbuf_trunc(cwd, strlen(cwd->buf));
52 : 9 : }
53 : :
54 : : /**
55 : : * Read the symlink content into a varbuf.
56 : : *
57 : : */
58 : : ssize_t
59 : 9 : file_readlink(const char *slink, struct varbuf *content, size_t content_len)
60 : : {
61 : : ssize_t linksize;
62 : :
63 : 9 : varbuf_reset(content);
64 : 9 : varbuf_grow(content, content_len + 1);
65 : :
66 : 9 : linksize = readlink(slink, content->buf, content->size);
67 [ - + ]: 9 : if (linksize < 0)
68 : 0 : return linksize;
69 : :
70 : 9 : varbuf_trunc(content, linksize);
71 : :
72 : 9 : return linksize;
73 : : }
74 : :
75 : : /**
76 : : * Check whether a filename is executable.
77 : : *
78 : : * @param filename The filename to check.
79 : : */
80 : : bool
81 : 35 : file_is_exec(const char *filename)
82 : : {
83 : : struct stat st;
84 : :
85 [ + + ]: 35 : if (stat(filename, &st) < 0)
86 : 22 : return false;
87 : :
88 [ - + ]: 13 : if (!S_ISREG(st.st_mode))
89 : 0 : return false;
90 : :
91 : 13 : return st.st_mode & 0111;
92 : : }
93 : :
94 : : /**
95 : : * Copy file ownership and permissions from one file to another.
96 : : *
97 : : * @param src The source filename.
98 : : * @param dst The destination filename.
99 : : */
100 : : void
101 : 0 : file_copy_perms(const char *src, const char *dst)
102 : : {
103 : : struct stat stab;
104 : :
105 [ # # ]: 0 : if (stat(src, &stab) < 0) {
106 [ # # ]: 0 : if (errno == ENOENT)
107 : 0 : return;
108 : 0 : ohshite(_("unable to stat source file '%.250s'"), src);
109 : : }
110 : :
111 [ # # ]: 0 : if (chown(dst, stab.st_uid, stab.st_gid) < 0)
112 : 0 : ohshite(_("unable to change ownership of target file '%.250s'"),
113 : : dst);
114 : :
115 [ # # ]: 0 : if (chmod(dst, (stab.st_mode & ~S_IFMT)) < 0)
116 : 0 : ohshite(_("unable to set mode of target file '%.250s'"), dst);
117 : : }
118 : :
119 : : static int
120 : 4 : file_slurp_fd(int fd, const char *filename, struct varbuf *vb,
121 : : struct dpkg_error *err)
122 : : {
123 : : struct stat st;
124 : :
125 [ - + ]: 4 : if (fstat(fd, &st) < 0)
126 : 0 : return dpkg_put_errno(err, _("cannot stat %s"), filename);
127 : :
128 [ + + ]: 4 : if (!S_ISREG(st.st_mode))
129 : 1 : return dpkg_put_error(err, _("%s is not a regular file"),
130 : : filename);
131 : :
132 [ + + ]: 3 : if (st.st_size == 0)
133 : 1 : return 0;
134 : :
135 : 2 : varbuf_init(vb, st.st_size + 1);
136 [ - + ]: 2 : if (fd_read(fd, vb->buf, st.st_size) < 0)
137 : 0 : return dpkg_put_errno(err, _("cannot read %s"), filename);
138 : 2 : varbuf_trunc(vb, st.st_size);
139 : :
140 : 2 : return 0;
141 : : }
142 : :
143 : : int
144 : 5 : file_slurp(const char *filename, struct varbuf *vb, struct dpkg_error *err)
145 : : {
146 : : int fd;
147 : : int rc;
148 : :
149 : 5 : varbuf_init(vb, 0);
150 : :
151 : 5 : fd = open(filename, O_RDONLY);
152 [ + + ]: 5 : if (fd < 0)
153 : 1 : return dpkg_put_errno(err, _("cannot open %s"), filename);
154 : :
155 : 4 : rc = file_slurp_fd(fd, filename, vb, err);
156 : :
157 : 4 : (void)close(fd);
158 : :
159 : 4 : return rc;
160 : : }
161 : :
162 : : static void
163 : 14 : file_lock_setup(struct flock *fl, short type)
164 : : {
165 : 14 : fl->l_type = type;
166 : 14 : fl->l_whence = SEEK_SET;
167 : 14 : fl->l_start = 0;
168 : 14 : fl->l_len = 0;
169 : 14 : fl->l_pid = 0;
170 : 14 : }
171 : :
172 : : /**
173 : : * Unlock a previously locked file.
174 : : */
175 : : void
176 : 7 : file_unlock(int lockfd, const char *lockfile, const char *lockdesc)
177 : : {
178 : : struct flock fl;
179 : :
180 [ - + ]: 7 : if (lockfd < 0)
181 : 0 : internerr("%s (%s) fd is %d < 0", lockdesc, lockfile, lockfd);
182 : :
183 : 7 : file_lock_setup(&fl, F_UNLCK);
184 : :
185 [ - + ]: 7 : if (fcntl(lockfd, F_SETLK, &fl) < 0)
186 : 0 : ohshite(_("unable to unlock %s"), lockdesc);
187 : 7 : }
188 : :
189 : : static void
190 : 7 : file_unlock_cleanup(int argc, void **argv)
191 : : {
192 : 7 : int lockfd = *(int *)argv[0];
193 : 7 : const char *lockfile = argv[1];
194 : 7 : const char *lockdesc = argv[2];
195 : :
196 : 7 : file_unlock(lockfd, lockfile, lockdesc);
197 : 7 : }
198 : :
199 : : /**
200 : : * Check if a file has a lock acquired.
201 : : *
202 : : * @param lockfd The file descriptor for the lock.
203 : : * @param filename The file name associated to the file descriptor.
204 : : */
205 : : bool
206 : 0 : file_is_locked(int lockfd, const char *filename)
207 : : {
208 : : struct flock fl;
209 : :
210 : 0 : file_lock_setup(&fl, F_WRLCK);
211 : :
212 [ # # ]: 0 : if (fcntl(lockfd, F_GETLK, &fl) < 0)
213 : 0 : ohshit(_("unable to check file '%s' lock status"), filename);
214 : :
215 [ # # # # ]: 0 : if (fl.l_type == F_WRLCK && fl.l_pid != getpid())
216 : 0 : return true;
217 : : else
218 : 0 : return false;
219 : : }
220 : :
221 : : /**
222 : : * Lock a file.
223 : : *
224 : : * @param lockfd The pointer to the lock file descriptor. It must be allocated
225 : : * statically as its addresses is passed to a cleanup handler.
226 : : * @param flags The lock flags specifying what type of locking to perform.
227 : : * @param filename The name of the file to lock.
228 : : * @param desc The description of the file to lock.
229 : : */
230 : : void
231 : 7 : file_lock(int *lockfd, enum file_lock_flags flags, const char *filename,
232 : : const char *desc)
233 : : {
234 : : struct flock fl;
235 : : int lock_cmd;
236 : :
237 : 7 : setcloexec(*lockfd, filename);
238 : :
239 : 7 : file_lock_setup(&fl, F_WRLCK);
240 : :
241 [ + - ]: 7 : if (flags == FILE_LOCK_WAIT)
242 : 7 : lock_cmd = F_SETLKW;
243 : : else
244 : 0 : lock_cmd = F_SETLK;
245 : :
246 [ - + ]: 7 : if (fcntl(*lockfd, lock_cmd, &fl) < 0) {
247 : : const char *warnmsg;
248 : : char *execname;
249 : :
250 [ # # # # ]: 0 : if (errno != EACCES && errno != EAGAIN)
251 : 0 : ohshite(_("unable to lock %s"), desc);
252 : :
253 : 0 : warnmsg = _("Note: removing the lock file is always wrong, "
254 : : "can damage the locked area\n"
255 : : "and the entire system. "
256 : : "See <https://wiki.debian.org/Teams/Dpkg/FAQ#db-lock>.");
257 : :
258 : 0 : file_lock_setup(&fl, F_WRLCK);
259 [ # # ]: 0 : if (fcntl(*lockfd, F_GETLK, &fl) < 0)
260 : 0 : ohshit(_("%s was locked by another process\n%s"),
261 : : desc, warnmsg);
262 : :
263 : 0 : execname = dpkg_get_pid_execname(fl.l_pid);
264 : :
265 [ # # ]: 0 : ohshit(_("%s was locked by %s process with pid %d\n%s"),
266 : 0 : desc, execname ? execname : C_("process", "<unknown>"),
267 : : fl.l_pid, warnmsg);
268 : : }
269 : :
270 : 7 : push_cleanup(file_unlock_cleanup, ~0, 3, lockfd, filename, desc);
271 : 7 : }
272 : :
273 : : void
274 : 0 : file_show(const char *filename)
275 : : {
276 : : struct pager *pager;
277 : : struct dpkg_error err;
278 : : int fd, rc;
279 : :
280 [ # # ]: 0 : if (filename == NULL)
281 : 0 : internerr("filename is NULL");
282 : :
283 : 0 : fd = open(filename, O_RDONLY);
284 [ # # ]: 0 : if (fd < 0)
285 : 0 : ohshite(_("cannot open file %s"), filename);
286 : :
287 : 0 : pager = pager_spawn(_("pager to show file"));
288 : 0 : rc = fd_fd_copy(fd, STDOUT_FILENO, -1, &err);
289 : 0 : pager_reap(pager);
290 : :
291 : 0 : close(fd);
292 : :
293 [ # # # # ]: 0 : if (rc < 0 && err.syserrno != EPIPE) {
294 : 0 : errno = err.syserrno;
295 : 0 : ohshite(_("cannot write file %s into the pager"), filename);
296 : : }
297 : 0 : }
|