183f2a3aaSMatthew Dillon /*
283f2a3aaSMatthew Dillon * Copyright (c) 2009 The DragonFly Project. All rights reserved.
383f2a3aaSMatthew Dillon *
483f2a3aaSMatthew Dillon * This code is derived from software contributed to The DragonFly Project
583f2a3aaSMatthew Dillon * by Matthew Dillon <dillon@backplane.com>
683f2a3aaSMatthew Dillon *
783f2a3aaSMatthew Dillon * Redistribution and use in source and binary forms, with or without
883f2a3aaSMatthew Dillon * modification, are permitted provided that the following conditions
983f2a3aaSMatthew Dillon * are met:
1083f2a3aaSMatthew Dillon *
1183f2a3aaSMatthew Dillon * 1. Redistributions of source code must retain the above copyright
1283f2a3aaSMatthew Dillon * notice, this list of conditions and the following disclaimer.
1383f2a3aaSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
1483f2a3aaSMatthew Dillon * notice, this list of conditions and the following disclaimer in
1583f2a3aaSMatthew Dillon * the documentation and/or other materials provided with the
1683f2a3aaSMatthew Dillon * distribution.
1783f2a3aaSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its
1883f2a3aaSMatthew Dillon * contributors may be used to endorse or promote products derived
1983f2a3aaSMatthew Dillon * from this software without specific, prior written permission.
2083f2a3aaSMatthew Dillon *
2183f2a3aaSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2283f2a3aaSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2383f2a3aaSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2483f2a3aaSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2583f2a3aaSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2683f2a3aaSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2783f2a3aaSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2883f2a3aaSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2983f2a3aaSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3083f2a3aaSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3183f2a3aaSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3283f2a3aaSMatthew Dillon * SUCH DAMAGE.
3383f2a3aaSMatthew Dillon */
3483f2a3aaSMatthew Dillon
35b45803e3STomohiro Kusumi #include "hammer.h"
36b45803e3STomohiro Kusumi
3783f2a3aaSMatthew Dillon static void config_get(const char *dirpath, struct hammer_ioc_config *config);
3883f2a3aaSMatthew Dillon static void config_set(const char *dirpath, struct hammer_ioc_config *config);
3983f2a3aaSMatthew Dillon static void config_remove_path(void);
4083f2a3aaSMatthew Dillon
41c6a47f25STomohiro Kusumi static char *ConfigPath;
4283f2a3aaSMatthew Dillon
4383f2a3aaSMatthew Dillon /*
4483f2a3aaSMatthew Dillon * hammer config [<fs> [configfile]]
4583f2a3aaSMatthew Dillon *
4683f2a3aaSMatthew Dillon * Prints out the hammer cleanup configuration for the specified HAMMER
4783f2a3aaSMatthew Dillon * filesystem(s) or the current filesystem.
4883f2a3aaSMatthew Dillon */
4983f2a3aaSMatthew Dillon void
hammer_cmd_config(char ** av,int ac)5083f2a3aaSMatthew Dillon hammer_cmd_config(char **av, int ac)
5183f2a3aaSMatthew Dillon {
5283f2a3aaSMatthew Dillon struct hammer_ioc_config config;
5383f2a3aaSMatthew Dillon char *dirpath;
5483f2a3aaSMatthew Dillon ssize_t n;
5583f2a3aaSMatthew Dillon int fd;
5683f2a3aaSMatthew Dillon
5783f2a3aaSMatthew Dillon bzero(&config, sizeof(config));
5883f2a3aaSMatthew Dillon if (ac == 0) {
5983f2a3aaSMatthew Dillon config_get(".", &config);
60f254e677STomohiro Kusumi if (config.head.error == 0) {
6183f2a3aaSMatthew Dillon printf("%s", config.config.text);
62f254e677STomohiro Kusumi } else {
6383f2a3aaSMatthew Dillon errx(2, "hammer config: no configuration found");
64f254e677STomohiro Kusumi /* not reached */
65f254e677STomohiro Kusumi }
6683f2a3aaSMatthew Dillon return;
6783f2a3aaSMatthew Dillon }
6883f2a3aaSMatthew Dillon dirpath = av[0];
6983f2a3aaSMatthew Dillon if (ac == 1) {
7083f2a3aaSMatthew Dillon config_get(dirpath, &config);
71f254e677STomohiro Kusumi if (config.head.error == 0) {
7283f2a3aaSMatthew Dillon printf("%s", config.config.text);
73f254e677STomohiro Kusumi } else {
7483f2a3aaSMatthew Dillon errx(2, "hammer config: no configuration found");
75f254e677STomohiro Kusumi /* not reached */
76f254e677STomohiro Kusumi }
7783f2a3aaSMatthew Dillon return;
7883f2a3aaSMatthew Dillon }
7983f2a3aaSMatthew Dillon config_get(dirpath, &config); /* ignore errors */
8083f2a3aaSMatthew Dillon config.head.error = 0;
8183f2a3aaSMatthew Dillon
8283f2a3aaSMatthew Dillon fd = open(av[1], O_RDONLY);
83f254e677STomohiro Kusumi if (fd < 0) {
84154eb1f4SStathis Kamperis err(2, "hammer config: %s", av[1]);
85f254e677STomohiro Kusumi /* not reached */
86f254e677STomohiro Kusumi }
8783f2a3aaSMatthew Dillon n = read(fd, config.config.text, sizeof(config.config.text) - 1);
88f254e677STomohiro Kusumi if (n == sizeof(config.config.text) - 1) {
8913a23276SMatthew Dillon err(2, "hammer config: config file too big, limit %zu bytes",
9083f2a3aaSMatthew Dillon sizeof(config.config.text) - 1);
91f254e677STomohiro Kusumi /* not reached */
92f254e677STomohiro Kusumi }
9383f2a3aaSMatthew Dillon bzero(config.config.text + n, sizeof(config.config.text) - n);
9483f2a3aaSMatthew Dillon config_set(dirpath, &config);
9583f2a3aaSMatthew Dillon close(fd);
9683f2a3aaSMatthew Dillon }
9783f2a3aaSMatthew Dillon
9883f2a3aaSMatthew Dillon /*
9983f2a3aaSMatthew Dillon * hammer viconfig [<fs>]
10083f2a3aaSMatthew Dillon */
10183f2a3aaSMatthew Dillon void
hammer_cmd_viconfig(char ** av,int ac)10283f2a3aaSMatthew Dillon hammer_cmd_viconfig(char **av, int ac)
10383f2a3aaSMatthew Dillon {
10483f2a3aaSMatthew Dillon struct hammer_ioc_config config;
10583f2a3aaSMatthew Dillon struct timeval times[2];
10683f2a3aaSMatthew Dillon const char *dirpath;
10783f2a3aaSMatthew Dillon struct stat st;
10893c6d6c7SAntonio Huete Jimenez char *runcmd, *editor, *tmp;
10983f2a3aaSMatthew Dillon char path[32];
11083f2a3aaSMatthew Dillon ssize_t n;
11183f2a3aaSMatthew Dillon int fd;
11283f2a3aaSMatthew Dillon
113f254e677STomohiro Kusumi if (ac > 1) {
11483f2a3aaSMatthew Dillon errx(1, "hammer viconfig: 0 or 1 argument (<fs>) only");
115f254e677STomohiro Kusumi /* not reached */
116f254e677STomohiro Kusumi }
11783f2a3aaSMatthew Dillon if (ac == 0)
11883f2a3aaSMatthew Dillon dirpath = ".";
11983f2a3aaSMatthew Dillon else
12083f2a3aaSMatthew Dillon dirpath = av[0];
12183f2a3aaSMatthew Dillon config_get(dirpath, &config);
12283f2a3aaSMatthew Dillon if (config.head.error == ENOENT) {
12383f2a3aaSMatthew Dillon snprintf(config.config.text, sizeof(config.config.text),
12483f2a3aaSMatthew Dillon "%s",
12583f2a3aaSMatthew Dillon "# No configuration present, here are some defaults\n"
12683f2a3aaSMatthew Dillon "# you can uncomment. Also remove these instructions\n"
12783f2a3aaSMatthew Dillon "#\n"
12883f2a3aaSMatthew Dillon "#snapshots 1d 60d\n"
12983f2a3aaSMatthew Dillon "#prune 1d 5m\n"
13083f2a3aaSMatthew Dillon "#rebalance 1d 5m\n"
131bb29b5d8SMatthew Dillon "#dedup 1d 5m\n"
13283f2a3aaSMatthew Dillon "#reblock 1d 5m\n"
13342fd37d3SThomas Nikolajsen "#recopy 30d 10m\n");
13483f2a3aaSMatthew Dillon config.head.error = 0;
13583f2a3aaSMatthew Dillon }
136f254e677STomohiro Kusumi if (config.head.error) {
13783f2a3aaSMatthew Dillon errx(2, "hammer viconfig: read config failed error: %s",
13883f2a3aaSMatthew Dillon strerror(config.head.error));
139f254e677STomohiro Kusumi /* not reached */
140f254e677STomohiro Kusumi }
14183f2a3aaSMatthew Dillon
14283f2a3aaSMatthew Dillon /*
14383f2a3aaSMatthew Dillon * Edit a temporary file and write back if it was modified.
14483f2a3aaSMatthew Dillon * Adjust the mtime back one second so a quick edit is not
14583f2a3aaSMatthew Dillon * improperly detected as not having been modified.
14683f2a3aaSMatthew Dillon */
14783f2a3aaSMatthew Dillon snprintf(path, sizeof(path), "/tmp/configXXXXXXXXXX");
14883f2a3aaSMatthew Dillon mkstemp(path);
14983f2a3aaSMatthew Dillon ConfigPath = path;
15083f2a3aaSMatthew Dillon atexit(config_remove_path);
15183f2a3aaSMatthew Dillon
15283f2a3aaSMatthew Dillon fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600);
153052fd72bSTomohiro Kusumi if (fd < 0) {
15483f2a3aaSMatthew Dillon err(2, "hammer viconfig: creating temporary file %s", path);
155052fd72bSTomohiro Kusumi /* not reached */
156052fd72bSTomohiro Kusumi }
15783f2a3aaSMatthew Dillon write(fd, config.config.text, strlen(config.config.text));
158052fd72bSTomohiro Kusumi if (fstat(fd, &st) < 0) {
15983f2a3aaSMatthew Dillon err(2, "hammer viconfig");
160052fd72bSTomohiro Kusumi /* not reached */
161052fd72bSTomohiro Kusumi }
16283f2a3aaSMatthew Dillon times[0].tv_sec = st.st_mtime - 1;
16383f2a3aaSMatthew Dillon times[0].tv_usec = 0;
16483f2a3aaSMatthew Dillon times[1] = times[0];
16583f2a3aaSMatthew Dillon close(fd);
16683f2a3aaSMatthew Dillon utimes(path, times);
16783f2a3aaSMatthew Dillon
16893c6d6c7SAntonio Huete Jimenez if ((tmp = getenv("EDITOR")) != NULL ||
169*9930da22STomohiro Kusumi (tmp = getenv("VISUAL")) != NULL) {
17093c6d6c7SAntonio Huete Jimenez editor = strdup(tmp);
171*9930da22STomohiro Kusumi } else {
17293c6d6c7SAntonio Huete Jimenez editor = strdup("vi");
173*9930da22STomohiro Kusumi }
17493c6d6c7SAntonio Huete Jimenez
17593c6d6c7SAntonio Huete Jimenez asprintf(&runcmd, "%s %s", editor, path);
17683f2a3aaSMatthew Dillon system(runcmd);
17783f2a3aaSMatthew Dillon
178052fd72bSTomohiro Kusumi if (stat(path, &st) < 0) {
17983f2a3aaSMatthew Dillon err(2, "hammer viconfig: unable to stat file after vi");
180052fd72bSTomohiro Kusumi /* not reached */
181052fd72bSTomohiro Kusumi }
18283f2a3aaSMatthew Dillon if (times[0].tv_sec == st.st_mtime) {
18383f2a3aaSMatthew Dillon printf("hammer viconfig: no changes were made\n");
18483f2a3aaSMatthew Dillon remove(path);
18583f2a3aaSMatthew Dillon return;
18683f2a3aaSMatthew Dillon }
18783f2a3aaSMatthew Dillon fd = open(path, O_RDONLY);
188052fd72bSTomohiro Kusumi if (fd < 0) {
18983f2a3aaSMatthew Dillon err(2, "hammer viconfig: unable to read %s", path);
190052fd72bSTomohiro Kusumi /* not reached */
191052fd72bSTomohiro Kusumi }
19283f2a3aaSMatthew Dillon remove(path);
19383f2a3aaSMatthew Dillon n = read(fd, config.config.text, sizeof(config.config.text) - 1);
194052fd72bSTomohiro Kusumi if (n < 0) {
19583f2a3aaSMatthew Dillon err(2, "hammer viconfig: unable to read %s", path);
196052fd72bSTomohiro Kusumi /* not reached */
197052fd72bSTomohiro Kusumi }
198f254e677STomohiro Kusumi if (n == sizeof(config.config.text) - 1) {
19913a23276SMatthew Dillon err(2, "hammer config: config file too big, limit %zu bytes",
20083f2a3aaSMatthew Dillon sizeof(config.config.text) - 1);
201f254e677STomohiro Kusumi /* not reached */
202f254e677STomohiro Kusumi }
20383f2a3aaSMatthew Dillon bzero(config.config.text + n, sizeof(config.config.text) - n);
20483f2a3aaSMatthew Dillon config_set(dirpath, &config);
20593c6d6c7SAntonio Huete Jimenez free(editor);
20693c6d6c7SAntonio Huete Jimenez free(runcmd);
20783f2a3aaSMatthew Dillon }
20883f2a3aaSMatthew Dillon
209005a4da7STomohiro Kusumi static
210005a4da7STomohiro Kusumi void
config_get(const char * dirpath,struct hammer_ioc_config * config)21183f2a3aaSMatthew Dillon config_get(const char *dirpath, struct hammer_ioc_config *config)
21283f2a3aaSMatthew Dillon {
21383f2a3aaSMatthew Dillon struct hammer_ioc_version version;
21483f2a3aaSMatthew Dillon int fd;
21583f2a3aaSMatthew Dillon
21683f2a3aaSMatthew Dillon bzero(&version, sizeof(version));
217052fd72bSTomohiro Kusumi if ((fd = open(dirpath, O_RDONLY)) < 0) {
21883f2a3aaSMatthew Dillon err(2, "hammer config: unable to open directory %s", dirpath);
219052fd72bSTomohiro Kusumi /* not reached */
220052fd72bSTomohiro Kusumi }
221052fd72bSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_VERSION, &version) < 0) {
22283f2a3aaSMatthew Dillon errx(2, "hammer config: not a HAMMER filesystem!");
223052fd72bSTomohiro Kusumi /* not reached */
224052fd72bSTomohiro Kusumi }
2254c09d9c4SMatthew Dillon HammerVersion = version.cur_version;
226052fd72bSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_CONFIG, config) < 0) {
22783f2a3aaSMatthew Dillon errx(2, "hammer config: config_get");
228052fd72bSTomohiro Kusumi /* not reached */
229052fd72bSTomohiro Kusumi }
23083f2a3aaSMatthew Dillon close(fd);
23183f2a3aaSMatthew Dillon }
23283f2a3aaSMatthew Dillon
233005a4da7STomohiro Kusumi static
234005a4da7STomohiro Kusumi void
config_set(const char * dirpath,struct hammer_ioc_config * config)23583f2a3aaSMatthew Dillon config_set(const char *dirpath, struct hammer_ioc_config *config)
23683f2a3aaSMatthew Dillon {
23783f2a3aaSMatthew Dillon struct hammer_ioc_version version;
23883f2a3aaSMatthew Dillon int fd;
23983f2a3aaSMatthew Dillon
24083f2a3aaSMatthew Dillon bzero(&version, sizeof(version));
241052fd72bSTomohiro Kusumi if ((fd = open(dirpath, O_RDONLY)) < 0) {
24283f2a3aaSMatthew Dillon errx(2, "hammer config: unable to open directory %s", dirpath);
243052fd72bSTomohiro Kusumi /* not reached */
244052fd72bSTomohiro Kusumi }
245052fd72bSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_VERSION, &version) < 0) {
24683f2a3aaSMatthew Dillon errx(2, "hammer config: not a HAMMER filesystem!");
247052fd72bSTomohiro Kusumi /* not reached */
248052fd72bSTomohiro Kusumi }
2494c09d9c4SMatthew Dillon HammerVersion = version.cur_version;
250052fd72bSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_SET_CONFIG, config) < 0) {
25193c6d6c7SAntonio Huete Jimenez err(2, "hammer config");
252052fd72bSTomohiro Kusumi /* not reached */
253052fd72bSTomohiro Kusumi }
25483f2a3aaSMatthew Dillon close(fd);
25583f2a3aaSMatthew Dillon }
25683f2a3aaSMatthew Dillon
257005a4da7STomohiro Kusumi static
258005a4da7STomohiro Kusumi void
config_remove_path(void)25983f2a3aaSMatthew Dillon config_remove_path(void)
26083f2a3aaSMatthew Dillon {
26183f2a3aaSMatthew Dillon remove(ConfigPath);
26283f2a3aaSMatthew Dillon }
263