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