func main() { flag.Usage = usage version := flag.Bool("version", false, "Display version information.") flag.Parse() if *version { fmt.Printf("Buckytools version: %s\n", buckytools.Version) os.Exit(0) } if flag.NArg() != 2 { usage() os.Exit(1) } err := fill.All(flag.Arg(0), flag.Arg(1)) if err != nil { fmt.Fprintf(os.Stderr, "An error occured:\n\t%s\n", err) os.Exit(2) } }
// healMetric will use the Whisper DB in the body of the request to // backfill the metric found at the given filesystem path. If the metric // doesn't exist it will be created as an identical copy of the DB found // in the request. func healMetric(w http.ResponseWriter, r *http.Request, path string) { // Does this request look sane? if r.Header.Get("Content-Type") != "application/octet-stream" { http.Error(w, "Content-Type must be application/octet-stream.", http.StatusBadRequest) log.Printf("Got send a content-type of %s, abort!", r.Header.Get("Content-Type")) return } i, err := strconv.Atoi(r.Header.Get("Content-Length")) if err != nil || i <= 28 { // Whisper file headers are 28 bytes and we need data too. // Something is wrong here log.Printf("Whisper data in request too small: %d bytes", i) http.Error(w, "Whisper data in request too small.", http.StatusBadRequest) } // Does the destination path on dist exist? dstExists := true if _, err := os.Stat(path); err != nil { if !os.IsNotExist(err) { log.Printf("Error stat'ing file %s: %s", path, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } err := os.MkdirAll(filepath.Dir(path), 0755) if err != nil { log.Printf("Error creating %s: %s", filepath.Dir(path), err) http.Error(w, err.Error(), http.StatusInternalServerError) return } dstExists = false } // Write request body to a tmpfile fd, err := ioutil.TempFile(tmpDir, "buckyd") if err != nil { log.Printf("Error creating temp file: %s", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } _, err = io.Copy(fd, r.Body) if err != nil { log.Printf("Error writing to temp file: %s", err) http.Error(w, err.Error(), http.StatusInternalServerError) fd.Close() os.Remove(fd.Name()) return } srcName := fd.Name() fd.Sync() fd.Close() defer os.Remove(srcName) // not concerned with errors here // XXX: How can we check the tmpfile for sanity? if dstExists { err := fill.All(srcName, path) if err != nil { log.Printf("Error backfilling %s => %s: %s", srcName, path, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } else { src, err := os.Open(srcName) if err != nil { log.Printf("Error opening tmp file %s: %s", srcName, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer src.Close() if err = syscall.Flock(int(src.Fd()), syscall.LOCK_EX); err != nil { log.Printf("Error locking file %s: %s", srcName, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } dst, err := os.Create(path) if err != nil { log.Printf("Error opening metric file %s: %s", path, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer dst.Close() if err = syscall.Flock(int(dst.Fd()), syscall.LOCK_EX); err != nil { log.Printf("Error locking file %s: %s", path, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } _, err = io.Copy(dst, src) if err != nil { log.Printf("Error copying %s => %s: %s", srcName, path, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } } }