]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libblkid/src/save.c
Merge branch 'spelling' of https://github.com/jwilk-forks/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
3fbeb9ee 55 fprintf(file, "<device DEVNO=\"0x%04lx\" TIME=\"%lld.%lld\"",
6c2f2b9d 56 (unsigned long) dev->bid_devno,
3fbeb9ee
SN
57 (long long) dev->bid_time,
58 (long long) dev->bid_utime);
6c2f2b9d 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)) {
82232495
KZ
131 size_t len = strlen(filename) + 8;
132 tmp = malloc(len);
a0948ffe 133 if (tmp) {
82232495 134 snprintf(tmp, len, "%s-XXXXXX", filename);
4d751c00 135 fd = mkstemp_cloexec(tmp);
a0948ffe 136 if (fd >= 0) {
ceaff03b 137 if (fchmod(fd, 0644) != 0)
c62a6311 138 DBG(SAVE, ul_debug("%s: fchmod failed", filename));
4000fc12 139 else if ((file = fdopen(fd, "w" UL_CLOEXECSTR)))
ceaff03b
KZ
140 opened = tmp;
141 if (!file)
142 close(fd);
a0948ffe 143 }
a0948ffe
KZ
144 }
145 }
146
147 if (!file) {
4000fc12 148 file = fopen(filename, "w" UL_CLOEXECSTR);
a0948ffe
KZ
149 opened = filename;
150 }
151
c62a6311 152 DBG(SAVE, ul_debug("writing cache file %s (really %s)",
a0948ffe
KZ
153 filename, opened));
154
155 if (!file) {
156 ret = errno;
157 goto errout;
158 }
159
160 list_for_each(p, &cache->bic_devs) {
161 blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
49361dc4 162 if (!dev->bid_type || (dev->bid_flags & BLKID_BID_FL_REMOVABLE))
a0948ffe
KZ
163 continue;
164 if ((ret = save_dev(dev, file)) < 0)
165 break;
166 }
167
168 if (ret >= 0) {
169 cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
170 ret = 1;
171 }
172
8d21d9ab 173 if (close_stream(file) != 0)
c62a6311 174 DBG(SAVE, ul_debug("write failed: %s", filename));
8d21d9ab 175
a0948ffe
KZ
176 if (opened != filename) {
177 if (ret < 0) {
178 unlink(opened);
c62a6311 179 DBG(SAVE, ul_debug("unlinked temp cache %s", opened));
a0948ffe
KZ
180 } else {
181 char *backup;
82232495 182 size_t len = strlen(filename) + 5;
a0948ffe 183
82232495 184 backup = malloc(len);
a0948ffe 185 if (backup) {
82232495 186 snprintf(backup, len, "%s.old", filename);
a0948ffe 187 unlink(backup);
5da42397 188 if (link(filename, backup)) {
c62a6311 189 DBG(SAVE, ul_debug("can't link %s to %s",
5da42397
KZ
190 filename, backup));
191 }
a0948ffe
KZ
192 free(backup);
193 }
c461b8d8
KZ
194 if (rename(opened, filename)) {
195 ret = errno;
c62a6311 196 DBG(SAVE, ul_debug("can't rename %s to %s",
c461b8d8
KZ
197 opened, filename));
198 } else {
c62a6311 199 DBG(SAVE, ul_debug("moved temp cache %s", opened));
c461b8d8 200 }
a0948ffe
KZ
201 }
202 }
203
204errout:
0e4ed1aa 205 free(tmp);
b82590ad
KZ
206 if (filename != cache->bic_filename)
207 free(filename);
a0948ffe
KZ
208 return ret;
209}
210
211#ifdef TEST_PROGRAM
212int main(int argc, char **argv)
213{
214 blkid_cache cache = NULL;
215 int ret;
216
0540ea54 217 blkid_init_debug(BLKID_DEBUG_ALL);
9175f390 218 if (argc != 2) {
a0948ffe
KZ
219 fprintf(stderr, "Usage: %s [filename]\n"
220 "Test loading/saving a cache (filename)\n", argv[0]);
221 exit(1);
222 }
223
224 if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
225 fprintf(stderr, "%s: error creating cache (%d)\n",
226 argv[0], ret);
227 exit(1);
228 }
229 if ((ret = blkid_probe_all(cache)) < 0) {
230 fprintf(stderr, "error (%d) probing devices\n", ret);
231 exit(1);
232 }
e0a9b8cf 233 cache->bic_filename = strdup(argv[1]);
a0948ffe
KZ
234
235 if ((ret = blkid_flush_cache(cache)) < 0) {
236 fprintf(stderr, "error (%d) saving cache\n", ret);
237 exit(1);
238 }
239
240 blkid_put_cache(cache);
241
242 return ret;
243}
244#endif