1e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/* 2e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * save.c - write the cache struct to disk 3e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * 4e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Copyright (C) 2001 by Andreas Dilger 550b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o * Copyright (C) 2003 Theodore Ts'o 6e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * 7e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * %Begin-Header% 8e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * This file may be redistributed under the terms of the 9e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * GNU Lesser General Public License. 10e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * %End-Header% 11e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */ 12e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 13e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <stdio.h> 14e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <string.h> 15e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <stdlib.h> 16e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <unistd.h> 17e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <sys/types.h> 18e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#ifdef HAVE_SYS_STAT_H 19e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <sys/stat.h> 20e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif 21e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#ifdef HAVE_SYS_MKDEV_H 22e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <sys/mkdev.h> 23e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif 24e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#ifdef HAVE_ERRNO_H 25e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <errno.h> 26e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif 277a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'o#include "blkidP.h" 28e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 297a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'ostatic int save_dev(blkid_dev dev, FILE *file) 30e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{ 31e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o struct list_head *p; 32e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 332e6a9febb48ea0e57d32cacb5e67220443c0e059Theodore Ts'o if (!dev || dev->bid_name[0] != '/') 34e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o return 0; 35e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 36f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o DBG(DEBUG_SAVE, 37bb47c2a4aff6ec6b9be7f30cd04cf7c858a84de4Theodore Ts'o printf("device %s, type %s\n", dev->bid_name, dev->bid_type ? 38bb47c2a4aff6ec6b9be7f30cd04cf7c858a84de4Theodore Ts'o dev->bid_type : "(null)")); 39e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 40e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o fprintf(file, 41e324b250593a32680309015eba7c6c5db7851227Theodore Ts'o "<device DEVNO=\"0x%04lx\" TIME=\"%ld\"", 4221261a0ea2af78512cb3c2e578569d0421d3bdbeMatthias Andree (unsigned long) dev->bid_devno, (long) dev->bid_time); 43ce72b862c59da24ba16b354d687549276a24f908Theodore Ts'o if (dev->bid_pri) 44ce72b862c59da24ba16b354d687549276a24f908Theodore Ts'o fprintf(file, " PRI=\"%d\"", dev->bid_pri); 45e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o list_for_each(p, &dev->bid_tags) { 467a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'o blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); 4779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val); 48e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 49e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o fprintf(file, ">%s</device>\n", dev->bid_name); 50e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 51e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o return 0; 52e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o} 53e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 54e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/* 55e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Write out the cache struct to the cache file on disk. 56e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */ 5750b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'oint blkid_flush_cache(blkid_cache cache) 58e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{ 5950b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o struct list_head *p; 60d3f917989badf78d1f97654e46d60d1f3d25cd17Theodore Ts'o char *tmp = NULL; 61d3f917989badf78d1f97654e46d60d1f3d25cd17Theodore Ts'o const char *opened = NULL; 6250b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o const char *filename; 63e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o FILE *file = NULL; 6450b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o int fd, ret = 0; 6579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o struct stat st; 66e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 67e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o if (!cache) 68e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o return -BLKID_ERR_PARAM; 69e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 70e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o if (list_empty(&cache->bic_devs) || 71e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { 7279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o DBG(DEBUG_SAVE, printf("skipping cache file write\n")); 73e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o return 0; 74e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 75e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 7650b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE; 77e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 7879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o /* If we can't write to the cache file, then don't even try */ 7979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || 8079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o (ret == 0 && access(filename, W_OK) < 0)) { 8179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o DBG(DEBUG_SAVE, 8279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o printf("can't write to cache file %s\n", filename)); 8379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o return 0; 8479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o } 85e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 8679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o /* 8779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o * Try and create a temporary file in the same directory so 8879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o * that in case of error we don't overwrite the cache file. 8979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o * If the cache file doesn't yet exist, it isn't a regular 9079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o * file (e.g. /dev/null or a socket), or we couldn't create 9179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o * a temporary file then we open it directly. 9279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o */ 9379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (ret == 0 && S_ISREG(st.st_mode)) { 9479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o tmp = malloc(strlen(filename) + 8); 9579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (tmp) { 9679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o sprintf(tmp, "%s-XXXXXX", filename); 9779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o fd = mkstemp(tmp); 9879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (fd >= 0) { 9979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o file = fdopen(fd, "w"); 10079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o opened = tmp; 101e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 10279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o fchmod(fd, 0644); 103e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 10479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o } 105e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 10679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (!file) { 10779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o file = fopen(filename, "w"); 10879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o opened = filename; 10979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o } 110e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 11179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o DBG(DEBUG_SAVE, 11279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o printf("writing cache file %s (really %s)\n", 11379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o filename, opened)); 114e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 11579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (!file) { 11679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o ret = errno; 11779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o goto errout; 118e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 119e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 12050b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o list_for_each(p, &cache->bic_devs) { 12150b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); 12250b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o if (!dev->bid_type) 12350b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o continue; 12450b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o if ((ret = save_dev(dev, file)) < 0) 12550b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o break; 12650b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o } 12750b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o 12850b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o if (ret >= 0) { 12950b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; 13050b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o ret = 1; 13150b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o } 132e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 13379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o fclose(file); 13479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (opened != filename) { 13579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (ret < 0) { 13679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o unlink(opened); 13779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o DBG(DEBUG_SAVE, 13879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o printf("unlinked temp cache %s\n", opened)); 13979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o } else { 14079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o char *backup; 14179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o 14279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o backup = malloc(strlen(filename) + 5); 14379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if (backup) { 14479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o sprintf(backup, "%s.old", filename); 14579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o unlink(backup); 14679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o link(filename, backup); 14779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o free(backup); 148e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 14979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o rename(opened, filename); 15079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o DBG(DEBUG_SAVE, 15179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o printf("moved temp cache %s\n", opened)); 152e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 153e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 154e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 15550b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'oerrout: 15645e338f5332a54295893dba2e32cc093d1316f60Jim Meyering free(tmp); 157e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o return ret; 158e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o} 159e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 160e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#ifdef TEST_PROGRAM 161e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'oint main(int argc, char **argv) 162e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{ 1637a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'o blkid_cache cache = NULL; 164e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o int ret; 165e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 166f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o blkid_debug_mask = DEBUG_ALL; 167e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o if (argc > 2) { 168e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o fprintf(stderr, "Usage: %s [filename]\n" 169e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o "Test loading/saving a cache (filename)\n", argv[0]); 170e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o exit(1); 171e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o } 172e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 17379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { 17479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o fprintf(stderr, "%s: error creating cache (%d)\n", 17579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o argv[0], ret); 17650b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o exit(1); 17750b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o } 17850b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o if ((ret = blkid_probe_all(cache)) < 0) { 17950b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o fprintf(stderr, "error (%d) probing devices\n", ret); 18050b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o exit(1); 18150b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o } 18250b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o cache->bic_filename = blkid_strdup(argv[1]); 183efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 18450b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o if ((ret = blkid_flush_cache(cache)) < 0) { 18550b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o fprintf(stderr, "error (%d) saving cache\n", ret); 18650b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o exit(1); 18750b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o } 18850b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o 18950b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o blkid_put_cache(cache); 190e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o 191e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o return ret; 192e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o} 193e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif 194