Dpkg::Vendor::Debian: Add support for new hardening branch feature
[dpkg.git] / lib / dpkg / file.c
blob4d02520d8e9cd6dbff6920b129b3eed9c181b0f1
1 /*
2 * libdpkg - Debian packaging suite library routines
3 * file.c - file handling functions
5 * Copyright © 1994, 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
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.
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.
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/>.
22 #include <config.h>
23 #include <compat.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
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>
39 /**
40 * Check whether a filename is executable.
42 * @param filename The filename to check.
44 bool
45 file_is_exec(const char *filename)
47 struct stat st;
49 if (stat(filename, &st) < 0)
50 return false;
52 if (!S_ISREG(st.st_mode))
53 return false;
55 return st.st_mode & 0111;
58 /**
59 * Copy file ownership and permissions from one file to another.
61 * @param src The source filename.
62 * @param dst The destination filename.
64 void
65 file_copy_perms(const char *src, const char *dst)
67 struct stat stab;
69 if (stat(src, &stab) == -1) {
70 if (errno == ENOENT)
71 return;
72 ohshite(_("unable to stat source file '%.250s'"), src);
75 if (chown(dst, stab.st_uid, stab.st_gid) == -1)
76 ohshite(_("unable to change ownership of target file '%.250s'"),
77 dst);
79 if (chmod(dst, (stab.st_mode & ~S_IFMT)) == -1)
80 ohshite(_("unable to set mode of target file '%.250s'"), dst);
83 static int
84 file_slurp_fd(int fd, const char *filename, struct varbuf *vb,
85 struct dpkg_error *err)
87 struct stat st;
89 if (fstat(fd, &st) < 0)
90 return dpkg_put_errno(err, _("cannot stat %s"), filename);
92 if (!S_ISREG(st.st_mode))
93 return dpkg_put_error(err, _("%s is not a regular file"),
94 filename);
96 if (st.st_size == 0)
97 return 0;
99 varbuf_init(vb, st.st_size);
100 if (fd_read(fd, vb->buf, st.st_size) < 0)
101 return dpkg_put_errno(err, _("cannot read %s"), filename);
102 vb->used = st.st_size;
104 return 0;
108 file_slurp(const char *filename, struct varbuf *vb, struct dpkg_error *err)
110 int fd;
111 int rc;
113 varbuf_init(vb, 0);
115 fd = open(filename, O_RDONLY);
116 if (fd < 0)
117 return dpkg_put_errno(err, _("cannot open %s"), filename);
119 rc = file_slurp_fd(fd, filename, vb, err);
121 (void)close(fd);
123 return rc;
126 static void
127 file_lock_setup(struct flock *fl, short type)
129 fl->l_type = type;
130 fl->l_whence = SEEK_SET;
131 fl->l_start = 0;
132 fl->l_len = 0;
133 fl->l_pid = 0;
137 * Unlock a previously locked file.
139 void
140 file_unlock(int lockfd, const char *lockfile, const char *lockdesc)
142 struct flock fl;
144 if (lockfd < 0)
145 internerr("%s (%s) fd is %d < 0", lockdesc, lockfile, lockfd);
147 file_lock_setup(&fl, F_UNLCK);
149 if (fcntl(lockfd, F_SETLK, &fl) == -1)
150 ohshite(_("unable to unlock %s"), lockdesc);
153 static void
154 file_unlock_cleanup(int argc, void **argv)
156 int lockfd = *(int *)argv[0];
157 const char *lockfile = argv[1];
158 const char *lockdesc = argv[2];
160 file_unlock(lockfd, lockfile, lockdesc);
164 * Check if a file has a lock acquired.
166 * @param lockfd The file descriptor for the lock.
167 * @param filename The file name associated to the file descriptor.
169 bool
170 file_is_locked(int lockfd, const char *filename)
172 struct flock fl;
174 file_lock_setup(&fl, F_WRLCK);
176 if (fcntl(lockfd, F_GETLK, &fl) == -1)
177 ohshit(_("unable to check file '%s' lock status"), filename);
179 if (fl.l_type == F_WRLCK && fl.l_pid != getpid())
180 return true;
181 else
182 return false;
186 * Lock a file.
188 * @param lockfd The pointer to the lock file descriptor. It must be allocated
189 * statically as its addresses is passed to a cleanup handler.
190 * @param flags The lock flags specifying what type of locking to perform.
191 * @param filename The name of the file to lock.
192 * @param desc The description of the file to lock.
194 void
195 file_lock(int *lockfd, enum file_lock_flags flags, const char *filename,
196 const char *desc)
198 struct flock fl;
199 int lock_cmd;
201 setcloexec(*lockfd, filename);
203 file_lock_setup(&fl, F_WRLCK);
205 if (flags == FILE_LOCK_WAIT)
206 lock_cmd = F_SETLKW;
207 else
208 lock_cmd = F_SETLK;
210 if (fcntl(*lockfd, lock_cmd, &fl) == -1) {
211 const char *warnmsg;
213 if (errno != EACCES && errno != EAGAIN)
214 ohshite(_("unable to lock %s"), desc);
216 warnmsg = _("Note: removing the lock file is always wrong, "
217 "can damage the locked area\n"
218 "and the entire system. "
219 "See <https://wiki.debian.org/Teams/Dpkg/FAQ#db-lock>.");
221 file_lock_setup(&fl, F_WRLCK);
222 if (fcntl(*lockfd, F_GETLK, &fl) == -1)
223 ohshit(_("%s was locked by another process\n%s"),
224 desc, warnmsg);
226 ohshit(_("%s was locked by another process with pid %d\n%s"),
227 desc, fl.l_pid, warnmsg);
230 push_cleanup(file_unlock_cleanup, ~0, 3, lockfd, filename, desc);
233 void
234 file_show(const char *filename)
236 struct pager *pager;
237 struct dpkg_error err;
238 int fd, rc;
240 if (filename == NULL)
241 internerr("filename is NULL");
243 fd = open(filename, O_RDONLY);
244 if (fd < 0)
245 ohshite(_("cannot open file %s"), filename);
247 pager = pager_spawn(_("pager to show file"));
248 rc = fd_fd_copy(fd, STDOUT_FILENO, -1, &err);
249 pager_reap(pager);
251 close(fd);
253 if (rc < 0 && err.syserrno != EPIPE) {
254 errno = err.syserrno;
255 ohshite(_("cannot write file %s into the pager"), filename);