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 "config.h" 14 #include <stdio.h> 15 #include <string.h> 16 #include <stdlib.h> 17 #include <unistd.h> 18 #include <sys/types.h> 19 #ifdef HAVE_SYS_STAT_H 20 #include <sys/stat.h> 21 #endif 22 #ifdef HAVE_SYS_MKDEV_H 23 #include <sys/mkdev.h> 24 #endif 25 #ifdef HAVE_ERRNO_H 26 #include <errno.h> 27 #endif 28 #include "blkidP.h" 29 30 #ifdef _WIN32 31 #include "windows.h" 32 #endif 33 34 static int save_dev(blkid_dev dev, FILE *file) 35 { 36 struct list_head *p; 37 38 if (!dev || dev->bid_name[0] != '/') 39 return 0; 40 41 DBG(DEBUG_SAVE, 42 printf("device %s, type %s\n", dev->bid_name, dev->bid_type ? 43 dev->bid_type : "(null)")); 44 45 fprintf(file, 46 "<device DEVNO=\"0x%04lx\" TIME=\"%ld\"", 47 (unsigned long) dev->bid_devno, (long) dev->bid_time); 48 if (dev->bid_pri) 49 fprintf(file, " PRI=\"%d\"", dev->bid_pri); 50 list_for_each(p, &dev->bid_tags) { 51 blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); 52 fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val); 53 } 54 fprintf(file, ">%s</device>\n", dev->bid_name); 55 56 return 0; 57 } 58 59 /* 60 * Write out the cache struct to the cache file on disk. 61 */ 62 int blkid_flush_cache(blkid_cache cache) 63 { 64 struct list_head *p; 65 char *tmp = NULL; 66 const char *opened = NULL; 67 const char *filename; 68 FILE *file = NULL; 69 int fd, ret = 0; 70 struct stat st; 71 72 if (!cache) 73 return -BLKID_ERR_PARAM; 74 75 if (list_empty(&cache->bic_devs) || 76 !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { 77 DBG(DEBUG_SAVE, printf("skipping cache file write\n")); 78 return 0; 79 } 80 81 filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE; 82 83 /* If we can't write to the cache file, then don't even try */ 84 if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || 85 (ret == 0 && access(filename, W_OK) < 0)) { 86 DBG(DEBUG_SAVE, 87 printf("can't write to cache file %s\n", filename)); 88 return 0; 89 } 90 91 /* 92 * Try and create a temporary file in the same directory so 93 * that in case of error we don't overwrite the cache file. 94 * If the cache file doesn't yet exist, it isn't a regular 95 * file (e.g. /dev/null or a socket), or we couldn't create 96 * a temporary file then we open it directly. 97 */ 98 if (ret == 0 && S_ISREG(st.st_mode)) { 99 tmp = malloc(strlen(filename) + 8); 100 if (tmp) { 101 mode_t save_umask = umask(022); 102 sprintf(tmp, "%s-XXXXXX", filename); 103 fd = mkstemp(tmp); 104 umask(save_umask); 105 if (fd >= 0) { 106 file = fdopen(fd, "w"); 107 opened = tmp; 108 } 109 #ifndef _WIN32 110 fchmod(fd, 0644); 111 #else 112 chmod(tmp, 0644); 113 #endif 114 } 115 } 116 117 if (!file) { 118 file = fopen(filename, "w"); 119 opened = filename; 120 } 121 122 DBG(DEBUG_SAVE, 123 printf("writing cache file %s (really %s)\n", 124 filename, opened)); 125 126 if (!file) { 127 ret = errno; 128 goto errout; 129 } 130 131 list_for_each(p, &cache->bic_devs) { 132 blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); 133 if (!dev->bid_type) 134 continue; 135 if ((ret = save_dev(dev, file)) < 0) 136 break; 137 } 138 139 if (ret >= 0) { 140 cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; 141 ret = 1; 142 } 143 144 fclose(file); 145 if (opened != filename) { 146 if (ret < 0) { 147 (void) unlink(opened); 148 DBG(DEBUG_SAVE, 149 printf("unlinked temp cache %s\n", opened)); 150 } else { 151 char *backup; 152 153 backup = malloc(strlen(filename) + 5); 154 if (backup) { 155 sprintf(backup, "%s.old", filename); 156 unlink(backup); 157 (void) link(filename, backup); 158 free(backup); 159 } 160 if (rename(opened, filename) < 0) 161 (void) unlink(opened); 162 DBG(DEBUG_SAVE, 163 printf("moved temp cache %s\n", opened)); 164 } 165 } 166 167 errout: 168 free(tmp); 169 return ret; 170 } 171 172 #ifdef TEST_PROGRAM 173 int main(int argc, char **argv) 174 { 175 blkid_cache cache = NULL; 176 int ret; 177 178 blkid_debug_mask = DEBUG_ALL; 179 if (argc > 2) { 180 fprintf(stderr, "Usage: %s [filename]\n" 181 "Test loading/saving a cache (filename)\n", argv[0]); 182 exit(1); 183 } 184 185 if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { 186 fprintf(stderr, "%s: error creating cache (%d)\n", 187 argv[0], ret); 188 exit(1); 189 } 190 if ((ret = blkid_probe_all(cache)) < 0) { 191 fprintf(stderr, "error (%d) probing devices\n", ret); 192 exit(1); 193 } 194 cache->bic_filename = blkid_strdup(argv[1]); 195 196 if ((ret = blkid_flush_cache(cache)) < 0) { 197 fprintf(stderr, "error (%d) saving cache\n", ret); 198 exit(1); 199 } 200 201 blkid_put_cache(cache); 202 203 return ret; 204 } 205 #endif