]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libblkid/src/save.c
Merge branch 'eject-sparc' of https://github.com/mator/util-linux
[thirdparty/util-linux.git] / libblkid / src / save.c
CommitLineData
a0948ffe
KZ
1/*
2 * save.c - write the cache struct to disk
3 *
4 * Copyright (C) 2001 by Andreas Dilger
5 * Copyright (C) 2003 Theodore Ts'o
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the
9 * GNU Lesser General Public License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <sys/types.h>
18#ifdef HAVE_SYS_STAT_H
19#include <sys/stat.h>
20#endif
a0948ffe
KZ
21#ifdef HAVE_ERRNO_H
22#include <errno.h>
23#endif
8d21d9ab
SK
24
25#include "closestream.h"
4d751c00 26#include "fileutils.h"
8d21d9ab 27
a0948ffe
KZ
28#include "blkidP.h"
29
89e90ae7
KZ
30
31static void save_quoted(const char *data, FILE *file)
32{
33 const char *p;
34
35 fputc('"', file);
36 for (p = data; p && *p; p++) {
37 if ((unsigned char) *p == 0x22 || /* " */
38 (unsigned char) *p == 0x5c) /* \ */
39 fputc('\\', file);
40
41 fputc(*p, file);
42 }
43 fputc('"', file);
44}
a0948ffe
KZ
45static int save_dev(blkid_dev dev, FILE *file)
46{
47 struct list_head *p;
48
49 if (!dev || dev->bid_name[0] != '/')
50 return 0;
51
c62a6311 52 DBG(SAVE, ul_debug("device %s, type %s", dev->bid_name, dev->bid_type ?
a0948ffe
KZ
53 dev->bid_type : "(null)"));
54
6c2f2b9d
KZ
55 fprintf(file, "<device DEVNO=\"0x%04lx\" TIME=\"%ld.%ld\"",
56 (unsigned long) dev->bid_devno,
57 (long) dev->bid_time,
58 (long) dev->bid_utime);
59
a0948ffe
KZ
60 if (dev->bid_pri)
61 fprintf(file, " PRI=\"%d\"", dev->bid_pri);
89e90ae7 62
a0948ffe
KZ
63 list_for_each(p, &dev->bid_tags) {
64 blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
89e90ae7
KZ
65
66 fputc(' ', file); /* space between tags */
67 fputs(tag->bit_name, file); /* tag NAME */
68 fputc('=', file); /* separator between NAME and VALUE */
69 save_quoted(tag->bit_val, file); /* tag "VALUE" */
a0948ffe
KZ
70 }
71 fprintf(file, ">%s</device>\n", dev->bid_name);
72
73 return 0;
74}
75
76/*
77 * Write out the cache struct to the cache file on disk.
78 */
79int blkid_flush_cache(blkid_cache cache)
80{
81 struct list_head *p;
82 char *tmp = NULL;
b82590ad
KZ
83 char *opened = NULL;
84 char *filename;
a0948ffe
KZ
85 FILE *file = NULL;
86 int fd, ret = 0;
87 struct stat st;
88
a0948ffe
KZ
89 if (list_empty(&cache->bic_devs) ||
90 !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
c62a6311 91 DBG(SAVE, ul_debug("skipping cache file write"));
a0948ffe
KZ
92 return 0;
93 }
94
b82590ad
KZ
95 filename = cache->bic_filename ? cache->bic_filename :
96 blkid_get_cache_filename(NULL);
71107465
KZ
97 if (!filename)
98 return -BLKID_ERR_PARAM;
b82590ad 99
71107465
KZ
100 if (strncmp(filename,
101 BLKID_RUNTIME_DIR "/", sizeof(BLKID_RUNTIME_DIR)) == 0) {
b82590ad
KZ
102
103 /* default destination, create the directory if necessary */
7317ba6d
KZ
104 if (stat(BLKID_RUNTIME_DIR, &st)
105 && errno == ENOENT
106 && mkdir(BLKID_RUNTIME_DIR, S_IWUSR|
107 S_IRUSR|S_IRGRP|S_IROTH|
108 S_IXUSR|S_IXGRP|S_IXOTH) != 0
109 && errno != EEXIST) {
c62a6311 110 DBG(SAVE, ul_debug("can't create %s directory for cache file",
7317ba6d
KZ
111 BLKID_RUNTIME_DIR));
112 return 0;
b82590ad
KZ
113 }
114 }
a0948ffe
KZ
115
116 /* If we can't write to the cache file, then don't even try */
117 if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
118 (ret == 0 && access(filename, W_OK) < 0)) {
c62a6311 119 DBG(SAVE, ul_debug("can't write to cache file %s", filename));
a0948ffe
KZ
120 return 0;
121 }
122
123 /*
124 * Try and create a temporary file in the same directory so
125 * that in case of error we don't overwrite the cache file.
126 * If the cache file doesn't yet exist, it isn't a regular
127 * file (e.g. /dev/null or a socket), or we couldn't create
128 * a temporary file then we open it directly.
129 */
130 if (ret == 0 && S_ISREG(st.st_mode)) {
131 tmp = malloc(strlen(filename) + 8);
132 if (tmp) {
133 sprintf(tmp, "%s-XXXXXX", filename);
4d751c00 134 fd = mkstemp_cloexec(tmp);
a0948ffe 135 if (fd >= 0) {
ceaff03b 136 if (fchmod(fd, 0644) != 0)
c62a6311 137 DBG(SAVE, ul_debug("%s: fchmod failed", filename));
4000fc12 138 else if ((file = fdopen(fd, "w" UL_CLOEXECSTR)))
ceaff03b
KZ
139 opened = tmp;
140 if (!file)
141 close(fd);
a0948ffe 142 }
a0948ffe
KZ
143 }
144 }
145
146 if (!file) {
4000fc12 147 file = fopen(filename, "w" UL_CLOEXECSTR);
a0948ffe
KZ
148 opened = filename;
149 }
150
c62a6311 151 DBG(SAVE, ul_debug("writing cache file %s (really %s)",
a0948ffe
KZ
152 filename, opened));
153
154 if (!file) {
155 ret = errno;
156 goto errout;
157 }
158
159 list_for_each(p, &cache->bic_devs) {
160 blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
49361dc4 161 if (!dev->bid_type || (dev->bid_flags & BLKID_BID_FL_REMOVABLE))
a0948ffe
KZ
162 continue;
163 if ((ret = save_dev(dev, file)) < 0)
164 break;
165 }
166
167 if (ret >= 0) {
168 cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
169 ret = 1;
170 }
171
8d21d9ab 172 if (close_stream(file) != 0)
c62a6311 173 DBG(SAVE, ul_debug("write failed: %s", filename));
8d21d9ab 174
a0948ffe
KZ
175 if (opened != filename) {
176 if (ret < 0) {
177 unlink(opened);
c62a6311 178 DBG(SAVE, ul_debug("unlinked temp cache %s", opened));
a0948ffe
KZ
179 } else {
180 char *backup;
181
182 backup = malloc(strlen(filename) + 5);
183 if (backup) {
184 sprintf(backup, "%s.old", filename);
185 unlink(backup);
5da42397 186 if (link(filename, backup)) {
c62a6311 187 DBG(SAVE, ul_debug("can't link %s to %s",
5da42397
KZ
188 filename, backup));
189 }
a0948ffe
KZ
190 free(backup);
191 }
c461b8d8
KZ
192 if (rename(opened, filename)) {
193 ret = errno;
c62a6311 194 DBG(SAVE, ul_debug("can't rename %s to %s",
c461b8d8
KZ
195 opened, filename));
196 } else {
c62a6311 197 DBG(SAVE, ul_debug("moved temp cache %s", opened));
c461b8d8 198 }
a0948ffe
KZ
199 }
200 }
201
202errout:
0e4ed1aa 203 free(tmp);
b82590ad
KZ
204 if (filename != cache->bic_filename)
205 free(filename);
a0948ffe
KZ
206 return ret;
207}
208
209#ifdef TEST_PROGRAM
210int main(int argc, char **argv)
211{
212 blkid_cache cache = NULL;
213 int ret;
214
0540ea54 215 blkid_init_debug(BLKID_DEBUG_ALL);
9175f390 216 if (argc != 2) {
a0948ffe
KZ
217 fprintf(stderr, "Usage: %s [filename]\n"
218 "Test loading/saving a cache (filename)\n", argv[0]);
219 exit(1);
220 }
221
222 if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
223 fprintf(stderr, "%s: error creating cache (%d)\n",
224 argv[0], ret);
225 exit(1);
226 }
227 if ((ret = blkid_probe_all(cache)) < 0) {
228 fprintf(stderr, "error (%d) probing devices\n", ret);
229 exit(1);
230 }
e0a9b8cf 231 cache->bic_filename = strdup(argv[1]);
a0948ffe
KZ
232
233 if ((ret = blkid_flush_cache(cache)) < 0) {
234 fprintf(stderr, "error (%d) saving cache\n", ret);
235 exit(1);
236 }
237
238 blkid_put_cache(cache);
239
240 return ret;
241}
242#endif