projects/pwm

changeset 29:00d782cb45fa

Read configuration file on startup
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Thu Sep 28 10:06:59 2017 +0200 (2017-09-28)
parents e3db02d7f1f4
children 2552eec9b913
files Makefile pwm.1.xml pwm.c pwmrc.c pwmrc.h
line diff
     1.1 --- a/Makefile	Wed Sep 27 19:44:05 2017 +0200
     1.2 +++ b/Makefile	Thu Sep 28 10:06:59 2017 +0200
     1.3 @@ -168,6 +168,7 @@
     1.4  			pw.o \
     1.5  			pwfile.o \
     1.6  			pwm.o \
     1.7 +			pwmrc.o \
     1.8  			tok.o
     1.9  PWM_BIN =		$(PACKAGE)
    1.10  PWM_MAN1 =		pwm.1
     2.1 --- a/pwm.1.xml	Wed Sep 27 19:44:05 2017 +0200
     2.2 +++ b/pwm.1.xml	Thu Sep 28 10:06:59 2017 +0200
     2.3 @@ -125,18 +125,27 @@
     2.4    </refsect1>
     2.5    <refsect1>
     2.6      <title>Usage</title>
     2.7 -    <para>If stdin is connected to a terminal pwm will run in interactive mode
     2.8 -    and prompt the user for the master password unless
     2.9 -    <replaceable>password_file</replaceable> is specified via the
    2.10 -    <option>-P</option> option. After successfully opening the password
    2.11 -    database the user will be prompted for a command.</para>
    2.12 -    <para>When running in non-interactive mode a file containing the master
    2.13 -    pasword must be specified via the <option>-P</option> option and after
    2.14 -    successfully opening the password database, pwm will execute commands read
    2.15 -    from stdin until either an error occurrs or end-of-file is reached.</para>
    2.16 -    <para><command>pwm</command> operates on a copy of the password database
    2.17 -    in memory, any changes must be explicitly written back to the database
    2.18 -    using the write command.</para>
    2.19 +    <refsect2>
    2.20 +      <title>Start-up</title>
    2.21 +      <para>If stdin is connected to a terminal pwm will run in interactive mode
    2.22 +      and prompt the user for the master password unless
    2.23 +      <replaceable>password_file</replaceable> is specified via the
    2.24 +      <option>-P</option> option. After successfully opening the password
    2.25 +      database the user will be prompted for a command.</para>
    2.26 +      <para>When running in non-interactive mode a file containing the master
    2.27 +      pasword must be specified via the <option>-P</option> option and after
    2.28 +      successfully opening the password database, pwm will execute commands
    2.29 +      read from stdin until either an error occurrs or end-of-file is
    2.30 +      reached.</para>
    2.31 +      <para><command>pwm</command> operates on a copy of the password database
    2.32 +      in memory, any changes must be explicitly written back to the database
    2.33 +      using the write command.</para>
    2.34 +      <para>When starting up, before prompting the user for a master password
    2.35 +      or reading the master password from a specified file
    2.36 +      <command>pwm</command> will read the file
    2.37 +      <filename>~/.pwm/pwmrc</filename> and execute any <command>set</command>
    2.38 +      and <command>define</command> commands specified therein.</para>
    2.39 +    </refsect2>
    2.40      <refsect2>
    2.41        <title>Configuration Variables</title>
    2.42        <para><command>pwm</command> can be configured through configuration
    2.43 @@ -732,6 +741,12 @@
    2.44      <title>Files</title>
    2.45      <variablelist>
    2.46        <varlistentry>
    2.47 +        <term><filename>~/.pwm/pwmrc</filename></term>
    2.48 +        <listitem>
    2.49 +          <para>configuration file</para>
    2.50 +        </listitem>
    2.51 +      </varlistentry>
    2.52 +      <varlistentry>
    2.53          <term><filename>~/.pwm/pwm.psafe3</filename></term>
    2.54          <listitem>
    2.55            <para>default password database</para>
     3.1 --- a/pwm.c	Wed Sep 27 19:44:05 2017 +0200
     3.2 +++ b/pwm.c	Thu Sep 28 10:06:59 2017 +0200
     3.3 @@ -44,6 +44,7 @@
     3.4  #include "io.h"
     3.5  #include "macro.h"
     3.6  #include "pwfile.h"
     3.7 +#include "pwmrc.h"
     3.8  #include "tok.h"
     3.9  #include "util.h"
    3.10  
    3.11 @@ -365,6 +366,8 @@
    3.12  
    3.13  	ctx.is_interactive = isatty(STDIN_FILENO);
    3.14  
    3.15 +	macro_init(&ctx.macro_head);
    3.16 +
    3.17  	while (!errflag && (c = getopt(argc, argv, "P:Rh")) != -1) {
    3.18  		switch (c) {
    3.19  		case 'P':
    3.20 @@ -417,9 +420,12 @@
    3.21  		goto out;
    3.22  	}
    3.23  
    3.24 +	/* read ~/.pwm/pwmrc */
    3.25 +	if (pwmrc_read(&ctx) != 0) {
    3.26 +		goto out;
    3.27 +	}
    3.28 +
    3.29  	pwfile_init(&ctx);
    3.30 -	macro_init(&ctx.macro_head);
    3.31 -
    3.32  	fp = fopen(ctx.filename, "r");
    3.33  	if ((fp == NULL) && (errno != ENOENT)) {
    3.34  		warn("failed to open password database");
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/pwmrc.c	Thu Sep 28 10:06:59 2017 +0200
     4.3 @@ -0,0 +1,180 @@
     4.4 +/*
     4.5 + * Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name>
     4.6 + *
     4.7 + * Permission is hereby granted, free of charge, to any person obtaining
     4.8 + * a copy of this software and associated documentation files (the
     4.9 + * "Software"), to deal in the Software without restriction, including
    4.10 + * without limitation the rights to use, copy, modify, merge, publish,
    4.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    4.12 + * permit persons to whom the Software is furnished to do so, subject to
    4.13 + * the following conditions:
    4.14 + *
    4.15 + * The above copyright notice and this permission notice shall be included
    4.16 + * in all copies or substantial portions of the Software.
    4.17 + *
    4.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    4.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    4.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    4.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    4.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    4.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    4.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    4.25 + */
    4.26 +
    4.27 +#include "compat.h"
    4.28 +
    4.29 +#include <errno.h>
    4.30 +#include <fcntl.h>
    4.31 +#ifdef	HAVE_ERR_H
    4.32 +#include <err.h>
    4.33 +#endif /* HAVE_ERR_H */
    4.34 +#include <stdio.h>
    4.35 +#include <stdlib.h>
    4.36 +#include <string.h>
    4.37 +#include <sys/stat.h>
    4.38 +#include <unistd.h>
    4.39 +
    4.40 +#include "pwm.h"
    4.41 +#include "cmd.h"
    4.42 +#include "io.h"
    4.43 +#include "macro.h"
    4.44 +#include "tok.h"
    4.45 +#include "util.h"
    4.46 +
    4.47 +static const char *config_cmds[] = {
    4.48 +    "set",
    4.49 +    "define"
    4.50 +};
    4.51 +
    4.52 +int
    4.53 +pwmrc_read(struct pwm_ctx *ctx)
    4.54 +{
    4.55 +	int	retval = -1;
    4.56 +	char	*filename = NULL;
    4.57 +	FILE	*fp = NULL;
    4.58 +	int	lineno;
    4.59 +	char	buf[PWM_LINE_MAX] = { '\0' };
    4.60 +	size_t	tokenc = 0;
    4.61 +	union tok **tokenv = NULL;
    4.62 +	int	argc = 0;
    4.63 +	char	**argv = NULL;
    4.64 +	struct cmd *cmd;
    4.65 +	size_t	i;
    4.66 +	int	is_config_cmd;
    4.67 +	int	j;
    4.68 +
    4.69 +	xasprintf(&filename, "%s/pwmrc", ctx->dirname);
    4.70 +
    4.71 +	fp = fopen(filename, "r");
    4.72 +	if (fp == NULL) {
    4.73 +		if (errno == ENOENT) {
    4.74 +			retval = 0;
    4.75 +		} else {
    4.76 +			warn("failed to open configuration file \"%s\"",
    4.77 +			    filename);
    4.78 +		}
    4.79 +		goto out;
    4.80 +	}
    4.81 +
    4.82 +	for (lineno = 1;; lineno++) {
    4.83 +		/* read next line */
    4.84 +		is_config_cmd = 0;
    4.85 +		if (fgets(buf, sizeof (buf), fp) == NULL) {
    4.86 +			if (feof(fp)) {
    4.87 +				goto done;
    4.88 +			}
    4.89 +			warn("failed to read from configuration file \"%s\"",
    4.90 +			    filename);
    4.91 +			goto out;
    4.92 +		}
    4.93 +		if (strchr(buf, '\n') == NULL) {
    4.94 +			fprintf(stderr, "line %d too long\n", lineno);
    4.95 +			goto out;
    4.96 +		}
    4.97 +
    4.98 +		/* tokenize line */
    4.99 +		switch (tok_tokenize(buf, &tokenc, &tokenv)) {
   4.100 +		case TOK_ERR_UNTERMINATED_QUOTE:
   4.101 +			fprintf(stderr, "unterminated quote in line %d\n",
   4.102 +			    lineno);
   4.103 +			if (!ctx->is_interactive) {
   4.104 +				goto out;
   4.105 +			}
   4.106 +			goto next;
   4.107 +		case TOK_ERR_TRAILING_BACKSLASH:
   4.108 +			fprintf(stderr, "trailing backslash in line %d\n",
   4.109 +			    lineno);
   4.110 +			if (!ctx->is_interactive) {
   4.111 +				goto out;
   4.112 +			}
   4.113 +			goto next;
   4.114 +		case TOK_ERR_INVALID_MACRO_NAME:
   4.115 +			fprintf(stderr, "invalid macro name in line %d\n",
   4.116 +			    lineno);
   4.117 +			if (!ctx->is_interactive) {
   4.118 +				goto out;
   4.119 +			}
   4.120 +			goto next;
   4.121 +		}
   4.122 +
   4.123 +		/* expand macros */
   4.124 +		if (macro_expand_macros(ctx->macro_head, tokenc, tokenv, &argc,
   4.125 +		    &argv) != 0) {
   4.126 +			fprintf(stderr, "undefined macro in line %d\n", lineno);
   4.127 +			if (!ctx->is_interactive) {
   4.128 +				goto out;
   4.129 +			}
   4.130 +			goto next;
   4.131 +		}
   4.132 +
   4.133 +		if (argc == 0) {
   4.134 +			/* empty line */
   4.135 +			goto next;
   4.136 +		}
   4.137 +
   4.138 +		/* find and execute the command */
   4.139 +		cmd = cmd_match(argv[0]);
   4.140 +		for (i = 0; (cmd != NULL) && (i < COUNTOF(config_cmds)); i++) {
   4.141 +			if (strcmp(cmd->full_cmd, config_cmds[i]) == 0) {
   4.142 +				is_config_cmd = 1;
   4.143 +				break;
   4.144 +			}
   4.145 +		}
   4.146 +		if (!is_config_cmd) {
   4.147 +			fprintf(stderr, "unknown configuration command \"%s\""
   4.148 +			    " in line %d\n", argv[0], lineno);
   4.149 +			goto out;
   4.150 +		}
   4.151 +		if (cmd->cmd_func(ctx, argc, argv) != CMD_OK) {
   4.152 +			fprintf(stderr, "syntax error in line %d\n", lineno);
   4.153 +			goto out;
   4.154 +		}
   4.155 +
   4.156 +next:
   4.157 +		for (j = 0; j < argc; j++) {
   4.158 +			free(argv[j]);
   4.159 +		}
   4.160 +		free(argv);
   4.161 +		argc = 0;
   4.162 +		argv = NULL;
   4.163 +		tok_free(tokenv);
   4.164 +		tokenc = 0;
   4.165 +		tokenv = NULL;
   4.166 +	}
   4.167 +
   4.168 +done:
   4.169 +	retval = 0;
   4.170 +
   4.171 +out:
   4.172 +	for (j = 0; j < argc; j++) {
   4.173 +		free(argv[j]);
   4.174 +	}
   4.175 +	free(argv);
   4.176 +	tok_free(tokenv);
   4.177 +	if (fp != NULL) {
   4.178 +		fclose(fp);
   4.179 +	}
   4.180 +	free(filename);
   4.181 +
   4.182 +	return (retval);
   4.183 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/pwmrc.h	Thu Sep 28 10:06:59 2017 +0200
     5.3 @@ -0,0 +1,29 @@
     5.4 +/*
     5.5 + * Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name>
     5.6 + *
     5.7 + * Permission is hereby granted, free of charge, to any person obtaining
     5.8 + * a copy of this software and associated documentation files (the
     5.9 + * "Software"), to deal in the Software without restriction, including
    5.10 + * without limitation the rights to use, copy, modify, merge, publish,
    5.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    5.12 + * permit persons to whom the Software is furnished to do so, subject to
    5.13 + * the following conditions:
    5.14 + *
    5.15 + * The above copyright notice and this permission notice shall be included
    5.16 + * in all copies or substantial portions of the Software.
    5.17 + *
    5.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    5.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    5.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    5.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    5.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    5.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    5.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    5.25 + */
    5.26 +
    5.27 +#ifndef	PWMRC_H
    5.28 +#define	PWMRC_H
    5.29 +
    5.30 +int	pwmrc_read(struct pwm_ctx *);
    5.31 +
    5.32 +#endif /* PWMRC_H */