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 
39 /**
40  * Copy file ownership and permissions from one file to another.
41  *
42  * @param src The source filename.
43  * @param dst The destination filename.
44  */
45 void
file_copy_perms(const char * src,const char * dst)46 file_copy_perms(const char *src, const char *dst)
47 {
48 	struct stat stab;
49 
50 	if (stat(src, &stab) == -1) {
51 		if (errno == ENOENT)
52 			return;
53 		ohshite(_("unable to stat source file '%.250s'"), src);
54 	}
55 
56 	if (chown(dst, stab.st_uid, stab.st_gid) == -1)
57 		ohshite(_("unable to change ownership of target file '%.250s'"),
58 		        dst);
59 
60 	if (chmod(dst, (stab.st_mode & ~S_IFMT)) == -1)
61 		ohshite(_("unable to set mode of target file '%.250s'"), dst);
62 }
63 
64 static int
file_slurp_fd(int fd,const char * filename,struct varbuf * vb,struct dpkg_error * err)65 file_slurp_fd(int fd, const char *filename, struct varbuf *vb,
66               struct dpkg_error *err)
67 {
68 	struct stat st;
69 
70 	if (fstat(fd, &st) < 0)
71 		return dpkg_put_errno(err, _("cannot stat %s"), filename);
72 
73 	if (!S_ISREG(st.st_mode))
74 		return dpkg_put_error(err, _("%s is not a regular file"),
75 		                      filename);
76 
77 	if (st.st_size == 0)
78 		return 0;
79 
80 	varbuf_init(vb, st.st_size);
81 	if (fd_read(fd, vb->buf, st.st_size) < 0)
82 		return dpkg_put_errno(err, _("cannot read %s"), filename);
83 	vb->used = st.st_size;
84 
85 	return 0;
86 }
87 
88 int
file_slurp(const char * filename,struct varbuf * vb,struct dpkg_error * err)89 file_slurp(const char *filename, struct varbuf *vb, struct dpkg_error *err)
90 {
91 	int fd;
92 	int rc;
93 
94 	varbuf_init(vb, 0);
95 
96 	fd = open(filename, O_RDONLY);
97 	if (fd < 0)
98 		return dpkg_put_errno(err, _("cannot open %s"), filename);
99 
100 	rc = file_slurp_fd(fd, filename, vb, err);
101 
102 	(void)close(fd);
103 
104 	return rc;
105 }
106 
107 static void
file_lock_setup(struct flock * fl,short type)108 file_lock_setup(struct flock *fl, short type)
109 {
110 	fl->l_type = type;
111 	fl->l_whence = SEEK_SET;
112 	fl->l_start = 0;
113 	fl->l_len = 0;
114 	fl->l_pid = 0;
115 }
116 
117 /**
118  * Unlock a previously locked file.
119  */
120 void
file_unlock(int lockfd,const char * lockfile,const char * lockdesc)121 file_unlock(int lockfd, const char *lockfile, const char *lockdesc)
122 {
123 	struct flock fl;
124 
125 	if (lockfd < 0)
126 		internerr("%s (%s) fd is %d < 0", lockdesc, lockfile, lockfd);
127 
128 	file_lock_setup(&fl, F_UNLCK);
129 
130 	if (fcntl(lockfd, F_SETLK, &fl) == -1)
131 		ohshite(_("unable to unlock %s"), lockdesc);
132 }
133 
134 static void
file_unlock_cleanup(int argc,void ** argv)135 file_unlock_cleanup(int argc, void **argv)
136 {
137 	int lockfd = *(int *)argv[0];
138 	const char *lockfile = argv[1];
139 	const char *lockdesc = argv[2];
140 
141 	file_unlock(lockfd, lockfile, lockdesc);
142 }
143 
144 /**
145  * Check if a file has a lock acquired.
146  *
147  * @param lockfd The file descriptor for the lock.
148  * @param filename The file name associated to the file descriptor.
149  */
150 bool
file_is_locked(int lockfd,const char * filename)151 file_is_locked(int lockfd, const char *filename)
152 {
153 	struct flock fl;
154 
155 	file_lock_setup(&fl, F_WRLCK);
156 
157 	if (fcntl(lockfd, F_GETLK, &fl) == -1)
158 		ohshit(_("unable to check file '%s' lock status"), filename);
159 
160 	if (fl.l_type == F_WRLCK && fl.l_pid != getpid())
161 		return true;
162 	else
163 		return false;
164 }
165 
166 /**
167  * Lock a file.
168  *
169  * @param lockfd The pointer to the lock file descriptor. It must be allocated
170  *        statically as its addresses is passed to a cleanup handler.
171  * @param flags The lock flags specifying what type of locking to perform.
172  * @param filename The name of the file to lock.
173  * @param desc The description of the file to lock.
174  */
175 void
file_lock(int * lockfd,enum file_lock_flags flags,const char * filename,const char * desc)176 file_lock(int *lockfd, enum file_lock_flags flags, const char *filename,
177           const char *desc)
178 {
179 	struct flock fl;
180 	int lock_cmd;
181 
182 	setcloexec(*lockfd, filename);
183 
184 	file_lock_setup(&fl, F_WRLCK);
185 
186 	if (flags == FILE_LOCK_WAIT)
187 		lock_cmd = F_SETLKW;
188 	else
189 		lock_cmd = F_SETLK;
190 
191 	if (fcntl(*lockfd, lock_cmd, &fl) == -1) {
192 		if (errno == EACCES || errno == EAGAIN)
193 			ohshit(_("%s is locked by another process"), desc);
194 		else
195 			ohshite(_("unable to lock %s"), desc);
196 	}
197 
198 	push_cleanup(file_unlock_cleanup, ~0, 3, lockfd, filename, desc);
199 }
200 
201 void
file_show(const char * filename)202 file_show(const char *filename)
203 {
204 	struct pager *pager;
205 	struct dpkg_error err;
206 	int fd, rc;
207 
208 	if (filename == NULL)
209 		internerr("filename is NULL");
210 
211 	fd = open(filename, O_RDONLY);
212 	if (fd < 0)
213 		ohshite(_("cannot open file %s"), filename);
214 
215 	pager = pager_spawn(_("pager to show file"));
216 	rc = fd_fd_copy(fd, STDOUT_FILENO, -1, &err);
217 	pager_reap(pager);
218 
219 	close(fd);
220 
221 	if (rc < 0 && err.syserrno != EPIPE) {
222 		errno = err.syserrno;
223 		ohshite(_("cannot write file %s into the pager"), filename);
224 	}
225 }
226