+void carefully_write(int fd, const void *buf, size_t sz)
+{
+ const unsigned char *p = buf;
+ ssize_t n;
+
+ if (fd < 0) return;
+ while (sz) {
+ n = write(fd, p, sz);
+ if (n < 0) {
+ if (errno == EINTR) continue;
+ bail_syserr(errno, "failed to write to output file");
+ }
+ if (!n) bail("unexpected short write to output file");
+ p += n; sz -= n;
+ }
+}
+
+void open_file_on_demand(const char *file, FILE **fp_inout, const char *what)
+{
+ FILE *fp;
+
+ if (!*fp_inout) {
+ fp = fopen(file, "w");
+ if (!fp) bail_syserr(errno, "failed to open %s file `%s'", what, file);
+ fprintf(fp, "## %s\n\n", what);
+ *fp_inout = fp;
+ }
+}
+
+void check_write(FILE *fp, const char *what)
+{
+ fflush(fp);
+ if (ferror(fp)) bail_syserr(errno, "error writing %s file", what);
+}
+
+void carefully_fclose(FILE *fp, const char *what)
+{
+ if (fp && (ferror(fp) || fclose(fp)))
+ bail_syserr(errno, "error writing %s file", what);
+}
+
+off_t device_size(int fd, const char *file, int *blksz_out)
+{
+ struct stat st;
+ uint64_t volsz;
+
+ if (fstat(fd, &st))
+ bail_syserr(errno, "failed to obtain status for `%s'", file);
+ if (S_ISREG(st.st_mode))
+ volsz = st.st_size;
+ else if (S_ISBLK(st.st_mode)) {
+ if (ioctl(fd, BLKGETSIZE64, &volsz))
+ bail_syserr(errno, "failed to get volume size for `%s'", file);
+ if (ioctl(fd, BLKSSZGET, blksz_out))
+ bail_syserr(errno, "failed to get block size for `%s'", file);
+ } else
+ bail("can't read size for `%s': expected file or block device", file);
+ return ((off_t)volsz);
+}
+