3 * $Id: key-file.c,v 1.3 2004/04/08 01:36:15 mdw Exp $
5 * System-dependent key filing operations
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Header files ------------------------------------------------------*/
37 #include <sys/types.h>
43 #include <mLib/dstr.h>
44 #include <mLib/lock.h>
48 /*----- Main code ---------------------------------------------------------*/
52 * Arguments: @int source@ = source file descriptor
53 * @int dest@ = destination file descriptor
55 * Returns: Zero if OK, nonzero otherwise.
57 * Use: Copies data from one file descriptor to another.
60 static int fdcopy(int source
, int dest
)
64 if (lseek(source
, 0, SEEK_SET
) < 0||
65 lseek(dest
, 0, SEEK_SET
) < 0 ||
66 ftruncate(dest
, 0) < 0)
69 int n
= read(source
, buf
, sizeof(buf
));
74 else if (write(dest
, buf
, n
) < 0)
80 /* --- @key_save@ --- *
82 * Arguments: @key_file *f@ = pointer to key file block
84 * Returns: A @KWRITE_@ code indicating how well it worked.
86 * Use: Writes a key file's data back to the actual file. This code
87 * is extremely careful about error handling. It should usually
88 * be able to back out somewhere sensible, but it can tell when
89 * it's got itself into a real pickle and starts leaving well
92 * Callers, please make sure that you ring alarm bells when this
93 * function returns @KWRITE_BROKEN@.
96 int key_save(key_file
*f
)
98 dstr n_older
= DSTR_INIT
, n_old
= DSTR_INIT
, n_new
= DSTR_INIT
;
101 if (!(f
->f
& KF_MODIFIED
))
104 return (KWRITE_FAIL
);
106 /* --- Write a new key file out --- *
108 * Check for an error after each key line. This ought to be enough.
109 * Checking after each individual byte write and @fprintf@ isn't much fun.
112 dstr_putf(&n_new
, "%s.new", f
->name
);
119 if ((fp
= fopen(n_new
.buf
, "w")) == 0)
122 for (key_mkiter(&i
, f
); (k
= key_next(&i
)) != 0; ) {
123 if (key_extract(f
, k
, fp
, 0)) {
133 /* --- Set up the other filenames --- */
135 dstr_putf(&n_older
, "%s.older", f
->name
);
136 dstr_putf(&n_old
, "%s.old", f
->name
);
138 /* --- Move the current backup on one --- *
140 * If the `older' file exists, then we're in need of attention.
145 if (stat(n_older
.buf
, &st
) == 0 || errno
!= ENOENT
) {
150 if (rename(n_old
.buf
, n_older
.buf
) && errno
!= ENOENT
)
154 /* --- Copy the current file to the backup --- */
158 if ((fd
= open(n_old
.buf
, O_WRONLY
| O_CREAT
| O_EXCL
, 0600)) < 0)
160 if (fdcopy(fileno(f
->fp
), fd
)) {
168 /* --- Copy the newly created file to the current one --- *
170 * This is the dangerous bit.
175 if ((fd
= open(n_new
.buf
, O_RDONLY
)) < 0)
177 if (fdcopy(fd
, fileno(f
->fp
))) {
182 if (fsync(fileno(f
->fp
)))
186 /* --- Clean up --- *
188 * Remove the `new' file and the `older' backup. Then we're done.
195 /* --- Failure while writing the new key file --- *
197 * I need to copy the backup back. If that fails then I'm really stuffed.
198 * If not, then I might as well try to get the backups sorted back out
207 if ((fd
= open(n_old
.buf
, O_RDONLY
)) < 0)
209 else if (fdcopy(fd
, fileno(f
->fp
))) {
214 if (fsync(fileno(f
->fp
)))
219 if (rc
== KWRITE_BROKEN
)
222 /* Now drop through */
224 /* --- Failure while writing the new backup --- *
226 * The new backup isn't any use. Try to recover the old one.
233 if (rename(n_older
.buf
, n_old
.buf
) && errno
!= ENOENT
)
237 /* Now drop through */
239 /* --- Failure while demoting the current backup --- *
241 * Leave the completed output file there for the operator in case he wants
246 dstr_destroy(&n_new
);
247 dstr_destroy(&n_old
);
248 dstr_destroy(&n_older
);
251 /* --- Failure during write of new data --- *
253 * Clean up the new file and return. These errors can never cause
260 dstr_destroy(&n_new
);
264 /* --- @key_lockfile@ --- *
266 * Arguments: @key_file *f@ = pointer to file structure to initialize
267 * @const char *file@ = pointer to the file name
268 * @unsigned how@ = opening options (@KOPEN_*@).
270 * Returns: Zero if it worked, nonzero otherwise.
272 * Use: Opens a keyfile and stores the information needed for
273 * continued access in the structure.
275 * If the file is opened with @KOPEN_WRITE@, it's created if
276 * necessary with read and write permissions for owner only, and
277 * locked for update while it's open.
279 * This is a system-dependent routine, and only really intended
280 * for the private use of @key_open@.
283 int key_lockfile(key_file
*f
, const char *file
, unsigned how
)
289 /* --- Handle the magic no-file option --- */
291 if (how
& KOPEN_NOFILE
) {
296 /* --- Lots of things depend on whether we're writing --- */
298 switch (how
& KOPEN_MASK
) {
305 of
= O_RDWR
| O_CREAT
;
314 /* --- Open and lock the file --- */
316 if ((fd
= open(file
, of
, 0600)) < 0)
318 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) < 0 ||
319 lock_file(fd
, lf
) < 0 ||
320 (f
->fp
= fdopen(fd
, ff
)) == 0) {
328 /*----- That's all, folks -------------------------------------------------*/