changeset 20:efef93e54c5f

Automatically save the database when receiving a fatal signal
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Wed, 06 Sep 2017 13:56:11 +0200
parents 5c6155c8e9b6
children ee4d36c85287
files pwfile.c pwfile.h pwm.1.xml pwm.c pwm.h
diffstat 5 files changed, 81 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/pwfile.c	Fri Sep 01 22:33:41 2017 +0200
+++ b/pwfile.c	Wed Sep 06 13:56:11 2017 +0200
@@ -381,8 +381,8 @@
 	pws3_file_set_header_field(file, save_host_field);
 }
 
-int
-pwfile_write_file(struct pwm_ctx *ctx)
+static int
+write_file(struct pwm_ctx *ctx, const char *filename)
 {
 	int	retval = -1;
 	char	*tmpfilename = NULL;
@@ -390,15 +390,7 @@
 	int	fd = -1;
 	FILE	*fp = NULL;
 
-	/* update password file metadata */
-	update_file_metadata(ctx->file);
-
-	/* make a backup copy of the existing password file */
-	if (make_backup_copy(ctx->filename) != 0) {
-		goto out;
-	}
-
-	xasprintf(&tmpfilename, "%s.XXXXXX", ctx->filename);
+	xasprintf(&tmpfilename, "%s.XXXXXX", filename);
 
 	/* create temporary file */
 	old_mode = umask(S_IRWXG | S_IRWXO);
@@ -440,7 +432,7 @@
 	}
 	if (retval == 0) {
 		/* rename temporary file and overwrite existing file */
-		if (rename(tmpfilename, ctx->filename) != 0) {
+		if (rename(tmpfilename, filename) != 0) {
 			warn("rename");
 			retval = -1;
 		}
@@ -450,6 +442,39 @@
 	}
 	free(tmpfilename);
 
+	return (retval);
+}
+
+int
+pwfile_write_autosave_file(struct pwm_ctx *ctx)
+{
+	int	retval;
+	char	*autosave_filename;
+
+	xasprintf(&autosave_filename, "%s/autosave.psafe3", ctx->dirname);
+
+	retval = write_file(ctx, autosave_filename);
+
+	free(autosave_filename);
+
+	return (retval);
+}
+
+int
+pwfile_write_file(struct pwm_ctx *ctx)
+{
+	int	retval;
+
+	/* update password file metadata */
+	update_file_metadata(ctx->file);
+
+	/* make a backup copy of the existing password file */
+	if (make_backup_copy(ctx->filename) != 0) {
+		return (-1);
+	}
+
+	retval = write_file(ctx, ctx->filename);
+
 	ctx->unsaved_changes = !!retval;
 
 	return (retval);
--- a/pwfile.h	Fri Sep 01 22:33:41 2017 +0200
+++ b/pwfile.h	Wed Sep 06 13:56:11 2017 +0200
@@ -74,6 +74,7 @@
 void		pwfile_destroy(struct pwm_ctx *);
 int		pwfile_read_file(struct pwm_ctx *, FILE *);
 int		pwfile_write_file(struct pwm_ctx *);
+int		pwfile_write_autosave_file(struct pwm_ctx *);
 union list_item ** pwfile_create_list(struct pwm_ctx *);
 void		pwfile_destroy_list(union list_item **);
 struct metadata * pwfile_get_metadata(struct pwm_ctx *);
--- a/pwm.1.xml	Fri Sep 01 22:33:41 2017 +0200
+++ b/pwm.1.xml	Wed Sep 06 13:56:11 2017 +0200
@@ -34,7 +34,7 @@
       <email>guido+pwm@berhoerster.name</email>
       <personblurb/>
     </author>
-    <date>12 August, 2017</date>
+    <date>6 September, 2017</date>
   </info>
   <refmeta>
     <refentrytitle>pwm</refentrytitle>
@@ -611,6 +611,23 @@
     </variablelist>
   </refsect1>
   <refsect1>
+    <title>Asynchronous Events</title>
+    <variablelist>
+      <varlistentry>
+        <term><literal>SIGINT</literal></term>
+        <term><literal>SIGHUP</literal></term>
+        <term><literal>SIGTERM</literal></term>
+        <listitem>
+          <para>If there are changes since the database was last written and
+          <command>pwm</command> is running in interactive mode, it
+          automatically writes a copy of the current database to the file
+          <filename>~/.pwm/autosave.psafe3</filename> which may be used for
+          recovery later.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
     <title>Files</title>
     <variablelist>
       <varlistentry>
@@ -619,6 +636,13 @@
           <para>default password database</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><filename>~/.pwm/autosave.psafe3</filename></term>
+        <listitem>
+          <para>automatic copy of the password database after receiving a fatal
+          signal in interactive mode</para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
   <refsect1>
--- a/pwm.c	Fri Sep 01 22:33:41 2017 +0200
+++ b/pwm.c	Wed Sep 06 13:56:11 2017 +0200
@@ -142,6 +142,9 @@
 			goto out;
 		case IO_EOF:	/* FALLTHROUGH */
 		case IO_SIGNAL:
+			if (ctx->unsaved_changes) {
+				pwfile_write_autosave_file(ctx);
+			}
 			goto quit;
 		default:
 			fprintf(stderr, "unknown error\n");
@@ -306,7 +309,6 @@
 	const char	*master_password_filename = NULL;
 	struct pwm_ctx	ctx = { 0 };
 	struct passwd	*passwd;
-	char		*pwm_dirname = NULL;
 	FILE		*fp = NULL;
 
 	setprogname(argv[0]);
@@ -355,19 +357,20 @@
 		goto out;
 	}
 
+	passwd = getpwuid(getuid());
+	if (passwd == NULL) {
+		err(1, "getpwuid");
+	}
+	xasprintf(&ctx.dirname, "%s/.pwm", passwd->pw_dir);
+
+	/* create ~/.pwm directory if necessary */
+	if ((mkdir(ctx.dirname, S_IRWXU) != 0) && (errno != EEXIST)) {
+		warn("failed to create directory \"%s\"", ctx.dirname);
+		goto out;
+	}
+
 	if (optind == argc) {
-		passwd = getpwuid(getuid());
-		if (passwd == NULL) {
-			err(1, "getpwuid");
-		}
-		xasprintf(&pwm_dirname, "%s/.pwm", passwd->pw_dir);
-		xasprintf(&ctx.filename, "%s/pwm.psafe3", pwm_dirname);
-
-		/* create ~/.pwm directory if necessary */
-		if ((mkdir(pwm_dirname, S_IRWXU) != 0) && (errno != EEXIST)) {
-			warn("failed to create directory \"%s\"", pwm_dirname);
-			goto out;
-		}
+		xasprintf(&ctx.filename, "%s/pwm.psafe3", ctx.dirname);
 	} else if (optind + 1 == argc) {
 		ctx.filename = xstrdup(argv[optind++]);
 	} else {
@@ -417,8 +420,8 @@
 		fclose(fp);
 	}
 	free(ctx.filename);
+	free(ctx.dirname);
 	free(ctx.errmsg);
-	free(pwm_dirname);
 
 	exit(status);
 }
--- a/pwm.h	Fri Sep 01 22:33:41 2017 +0200
+++ b/pwm.h	Wed Sep 06 13:56:11 2017 +0200
@@ -46,6 +46,7 @@
 struct pwm_ctx {
 	const char	*prev_cmd;
 	char		*errmsg;
+	char		*dirname;
 	char		*filename;
 	struct pws3_file *file;
 	struct record_id_tree *record_id_tree;