14daef0ddSTomohiro Kusumi /*
24daef0ddSTomohiro Kusumi * Copyright (c) 2008 The DragonFly Project. All rights reserved.
34daef0ddSTomohiro Kusumi *
44daef0ddSTomohiro Kusumi * This code is derived from software contributed to The DragonFly Project
54daef0ddSTomohiro Kusumi * by Matthew Dillon <dillon@backplane.com>
64daef0ddSTomohiro Kusumi *
74daef0ddSTomohiro Kusumi * Redistribution and use in source and binary forms, with or without
84daef0ddSTomohiro Kusumi * modification, are permitted provided that the following conditions
94daef0ddSTomohiro Kusumi * are met:
104daef0ddSTomohiro Kusumi *
114daef0ddSTomohiro Kusumi * 1. Redistributions of source code must retain the above copyright
124daef0ddSTomohiro Kusumi * notice, this list of conditions and the following disclaimer.
134daef0ddSTomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright
144daef0ddSTomohiro Kusumi * notice, this list of conditions and the following disclaimer in
154daef0ddSTomohiro Kusumi * the documentation and/or other materials provided with the
164daef0ddSTomohiro Kusumi * distribution.
174daef0ddSTomohiro Kusumi * 3. Neither the name of The DragonFly Project nor the names of its
184daef0ddSTomohiro Kusumi * contributors may be used to endorse or promote products derived
194daef0ddSTomohiro Kusumi * from this software without specific, prior written permission.
204daef0ddSTomohiro Kusumi *
214daef0ddSTomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
224daef0ddSTomohiro Kusumi * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
234daef0ddSTomohiro Kusumi * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
244daef0ddSTomohiro Kusumi * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
254daef0ddSTomohiro Kusumi * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
264daef0ddSTomohiro Kusumi * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
274daef0ddSTomohiro Kusumi * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
284daef0ddSTomohiro Kusumi * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
294daef0ddSTomohiro Kusumi * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
304daef0ddSTomohiro Kusumi * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
314daef0ddSTomohiro Kusumi * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
324daef0ddSTomohiro Kusumi * SUCH DAMAGE.
334daef0ddSTomohiro Kusumi *
344daef0ddSTomohiro Kusumi * $DragonFly: src/sbin/hammer/cmd_pseudofs.c,v 1.12 2008/10/08 21:01:54 thomas Exp $
354daef0ddSTomohiro Kusumi */
364daef0ddSTomohiro Kusumi
374daef0ddSTomohiro Kusumi #include "hammer.h"
384daef0ddSTomohiro Kusumi
394daef0ddSTomohiro Kusumi static int scanpfsid(struct hammer_ioc_pseudofs_rw *pfs, const char *path);
404daef0ddSTomohiro Kusumi static void parse_pfsd_options(char **av, int ac, hammer_pseudofs_data_t pfsd);
414daef0ddSTomohiro Kusumi static void init_pfsd(hammer_pseudofs_data_t pfsd, int is_slave);
424daef0ddSTomohiro Kusumi static void pseudofs_usage(int code);
434daef0ddSTomohiro Kusumi static int timetosecs(char *str);
444daef0ddSTomohiro Kusumi
451b23fc22STomohiro Kusumi void
clrpfs(struct hammer_ioc_pseudofs_rw * pfs,hammer_pseudofs_data_t pfsd,int pfs_id)461b23fc22STomohiro Kusumi clrpfs(struct hammer_ioc_pseudofs_rw *pfs, hammer_pseudofs_data_t pfsd,
471b23fc22STomohiro Kusumi int pfs_id)
481b23fc22STomohiro Kusumi {
491b23fc22STomohiro Kusumi bzero(pfs, sizeof(*pfs));
501b23fc22STomohiro Kusumi
511b23fc22STomohiro Kusumi if (pfsd)
521b23fc22STomohiro Kusumi pfs->ondisk = pfsd;
531b23fc22STomohiro Kusumi else
541b23fc22STomohiro Kusumi pfs->ondisk = malloc(sizeof(*pfs->ondisk));
551b23fc22STomohiro Kusumi bzero(pfs->ondisk, sizeof(*pfs->ondisk));
561b23fc22STomohiro Kusumi
571b23fc22STomohiro Kusumi pfs->pfs_id = pfs_id;
581b23fc22STomohiro Kusumi pfs->bytes = sizeof(*pfs->ondisk);
591b23fc22STomohiro Kusumi pfs->version = HAMMER_IOC_PSEUDOFS_VERSION;
601b23fc22STomohiro Kusumi }
611b23fc22STomohiro Kusumi
624daef0ddSTomohiro Kusumi /*
63578f0d56STomohiro Kusumi * If path is a symlink, return strdup'd path.
64578f0d56STomohiro Kusumi * If it's a directory via symlink, strip trailing /
65578f0d56STomohiro Kusumi * from strdup'd path and return the symlink.
66578f0d56STomohiro Kusumi */
67005a4da7STomohiro Kusumi static
68005a4da7STomohiro Kusumi char*
getlink(const char * path)69578f0d56STomohiro Kusumi getlink(const char *path)
70578f0d56STomohiro Kusumi {
71578f0d56STomohiro Kusumi int i;
72578f0d56STomohiro Kusumi char *linkpath;
73578f0d56STomohiro Kusumi struct stat st;
74578f0d56STomohiro Kusumi
75578f0d56STomohiro Kusumi if (lstat(path, &st))
76578f0d56STomohiro Kusumi return(NULL);
77578f0d56STomohiro Kusumi linkpath = strdup(path);
78578f0d56STomohiro Kusumi
79578f0d56STomohiro Kusumi if (S_ISDIR(st.st_mode)) {
80578f0d56STomohiro Kusumi i = strlen(linkpath) - 1;
81578f0d56STomohiro Kusumi while (i > 0 && linkpath[i] == '/')
82578f0d56STomohiro Kusumi linkpath[i--] = 0;
83578f0d56STomohiro Kusumi lstat(linkpath, &st);
84578f0d56STomohiro Kusumi }
8552e2f1b5STomohiro Kusumi if (S_ISLNK(st.st_mode))
86578f0d56STomohiro Kusumi return(linkpath);
87578f0d56STomohiro Kusumi
88578f0d56STomohiro Kusumi free(linkpath);
89578f0d56STomohiro Kusumi return(NULL);
90578f0d56STomohiro Kusumi }
91578f0d56STomohiro Kusumi
92578f0d56STomohiro Kusumi /*
9314331391STomohiro Kusumi * Calculate the PFS id given a path to a file/directory or
9414331391STomohiro Kusumi * a @@%llx:%d softlink.
954daef0ddSTomohiro Kusumi */
964daef0ddSTomohiro Kusumi int
getpfs(struct hammer_ioc_pseudofs_rw * pfs,const char * path)97578f0d56STomohiro Kusumi getpfs(struct hammer_ioc_pseudofs_rw *pfs, const char *path)
984daef0ddSTomohiro Kusumi {
99*207ba670SMatthew Dillon char *tmpbuf;
1004daef0ddSTomohiro Kusumi int fd;
1014daef0ddSTomohiro Kusumi
1021b23fc22STomohiro Kusumi clrpfs(pfs, NULL, -1);
1034daef0ddSTomohiro Kusumi
1044daef0ddSTomohiro Kusumi /*
105445b5ba6STomohiro Kusumi * Extract the PFS id.
106a5ff7917STomohiro Kusumi * dirname(path) is supposed to be a directory in root PFS.
107*207ba670SMatthew Dillon *
108*207ba670SMatthew Dillon * strips trailing / first if any.
109445b5ba6STomohiro Kusumi */
110*207ba670SMatthew Dillon tmpbuf = strdup(path);
11152e2f1b5STomohiro Kusumi if (scanpfsid(pfs, path) == 0)
112*207ba670SMatthew Dillon path = dirname(tmpbuf);
113445b5ba6STomohiro Kusumi
114445b5ba6STomohiro Kusumi /*
115445b5ba6STomohiro Kusumi * Open the path regardless of scanpfsid() result, since some
116445b5ba6STomohiro Kusumi * commands can take a regular file/directory (e.g. pfs-status).
1174daef0ddSTomohiro Kusumi */
1184daef0ddSTomohiro Kusumi fd = open(path, O_RDONLY);
119052fd72bSTomohiro Kusumi if (fd < 0) {
12002318f07STomohiro Kusumi err(1, "Failed to open %s", path);
121052fd72bSTomohiro Kusumi /* not reached */
122052fd72bSTomohiro Kusumi }
1234daef0ddSTomohiro Kusumi
1244daef0ddSTomohiro Kusumi /*
125ec206eb9STomohiro Kusumi * If pfs.pfs_id has been set to non -1, the file descriptor fd
1264daef0ddSTomohiro Kusumi * could be any fd of HAMMER inodes since HAMMERIOC_GET_PSEUDOFS
1274daef0ddSTomohiro Kusumi * doesn't depend on inode attributes if it's set to a valid id.
1284daef0ddSTomohiro Kusumi */
129052fd72bSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, pfs) < 0) {
13002318f07STomohiro Kusumi err(1, "Cannot access %s", path);
131052fd72bSTomohiro Kusumi /* not reached */
132052fd72bSTomohiro Kusumi }
13302318f07STomohiro Kusumi
134*207ba670SMatthew Dillon free(tmpbuf);
135*207ba670SMatthew Dillon
1364daef0ddSTomohiro Kusumi return(fd);
1374daef0ddSTomohiro Kusumi }
1384daef0ddSTomohiro Kusumi
1394daef0ddSTomohiro Kusumi /*
140445b5ba6STomohiro Kusumi * Extract the PFS id from path.
1414daef0ddSTomohiro Kusumi */
142005a4da7STomohiro Kusumi static
143005a4da7STomohiro Kusumi int
scanpfsid(struct hammer_ioc_pseudofs_rw * pfs,const char * path)1444daef0ddSTomohiro Kusumi scanpfsid(struct hammer_ioc_pseudofs_rw *pfs, const char *path)
1454daef0ddSTomohiro Kusumi {
146578f0d56STomohiro Kusumi char *linkpath;
147*207ba670SMatthew Dillon char *tmpbuf;
1484daef0ddSTomohiro Kusumi char buf[64];
1494daef0ddSTomohiro Kusumi uintmax_t dummy_tid;
1504daef0ddSTomohiro Kusumi struct stat st;
1514daef0ddSTomohiro Kusumi
15252e2f1b5STomohiro Kusumi if (stat(path, &st))
15352e2f1b5STomohiro Kusumi ; /* possibly slave PFS */
15452e2f1b5STomohiro Kusumi else if (S_ISDIR(st.st_mode))
15552e2f1b5STomohiro Kusumi ; /* possibly master or slave PFS */
15652e2f1b5STomohiro Kusumi else
15740649c3eSTomohiro Kusumi return(-1); /* neither */
1584daef0ddSTomohiro Kusumi
159578f0d56STomohiro Kusumi linkpath = getlink(path);
160578f0d56STomohiro Kusumi if (linkpath) {
1614daef0ddSTomohiro Kusumi /*
162578f0d56STomohiro Kusumi * Read the symlink assuming it's a link to PFS.
1634daef0ddSTomohiro Kusumi */
16440649c3eSTomohiro Kusumi bzero(buf, sizeof(buf));
165578f0d56STomohiro Kusumi if (readlink(linkpath, buf, sizeof(buf) - 1) < 0) {
166578f0d56STomohiro Kusumi free(linkpath);
16740649c3eSTomohiro Kusumi return(-1);
168578f0d56STomohiro Kusumi }
169578f0d56STomohiro Kusumi free(linkpath);
170445b5ba6STomohiro Kusumi path = buf;
1714daef0ddSTomohiro Kusumi }
1724daef0ddSTomohiro Kusumi
1734daef0ddSTomohiro Kusumi /*
1744daef0ddSTomohiro Kusumi * The symlink created by pfs-master|slave is just a symlink.
1754daef0ddSTomohiro Kusumi * One could happen to remove a symlink and relink PFS as
1764daef0ddSTomohiro Kusumi * # ln -s ./@@-1:00001 ./link
1774daef0ddSTomohiro Kusumi * which results PFS having something extra before @@.
1784daef0ddSTomohiro Kusumi * One could also directly use the PFS and results the same.
1794daef0ddSTomohiro Kusumi * Get rid of it before we extract the PFS id.
1804daef0ddSTomohiro Kusumi */
181*207ba670SMatthew Dillon tmpbuf = strdup(path);
182445b5ba6STomohiro Kusumi if (strchr(path, '/')) {
183*207ba670SMatthew Dillon path = basename(tmpbuf); /* strips trailing / first if any */
184052fd72bSTomohiro Kusumi if (path == NULL) {
1854daef0ddSTomohiro Kusumi err(1, "basename");
186052fd72bSTomohiro Kusumi /* not reached */
187052fd72bSTomohiro Kusumi }
1884daef0ddSTomohiro Kusumi }
1894daef0ddSTomohiro Kusumi
1904daef0ddSTomohiro Kusumi /*
191445b5ba6STomohiro Kusumi * Test and extract the PFS id from the link.
1925dce36edSTomohiro Kusumi * "@@%jx:%d" covers both "@@-1:%05d" format for master PFS
19314331391STomohiro Kusumi * and "@@0x%016jx:%05d" format for slave PFS.
1944daef0ddSTomohiro Kusumi */
195445b5ba6STomohiro Kusumi if (sscanf(path, "@@%jx:%d", &dummy_tid, &pfs->pfs_id) == 2) {
196*207ba670SMatthew Dillon free(tmpbuf);
197445b5ba6STomohiro Kusumi assert(pfs->pfs_id > 0);
198445b5ba6STomohiro Kusumi return(0);
199dc17a1e0STomohiro Kusumi }
200*207ba670SMatthew Dillon free(tmpbuf);
20114331391STomohiro Kusumi
202445b5ba6STomohiro Kusumi return(-1);
2034daef0ddSTomohiro Kusumi }
2044daef0ddSTomohiro Kusumi
2054daef0ddSTomohiro Kusumi void
relpfs(int fd,struct hammer_ioc_pseudofs_rw * pfs)2064daef0ddSTomohiro Kusumi relpfs(int fd, struct hammer_ioc_pseudofs_rw *pfs)
2074daef0ddSTomohiro Kusumi {
2084daef0ddSTomohiro Kusumi if (fd >= 0)
2094daef0ddSTomohiro Kusumi close(fd);
2104daef0ddSTomohiro Kusumi if (pfs->ondisk) {
2114daef0ddSTomohiro Kusumi free(pfs->ondisk);
2124daef0ddSTomohiro Kusumi pfs->ondisk = NULL;
2134daef0ddSTomohiro Kusumi }
2144daef0ddSTomohiro Kusumi }
2154daef0ddSTomohiro Kusumi
216005a4da7STomohiro Kusumi static
217005a4da7STomohiro Kusumi void
print_pfs_status(char * path)218fdba9548STomohiro Kusumi print_pfs_status(char *path)
2194daef0ddSTomohiro Kusumi {
2204daef0ddSTomohiro Kusumi struct hammer_ioc_pseudofs_rw pfs;
2214daef0ddSTomohiro Kusumi int fd;
2224daef0ddSTomohiro Kusumi
223fdba9548STomohiro Kusumi fd = getpfs(&pfs, path);
224fdba9548STomohiro Kusumi printf("%s\t", path);
2254daef0ddSTomohiro Kusumi if (fd < 0 || ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) < 0) {
226fdba9548STomohiro Kusumi printf("Invalid PFS path %s\n", path);
2274daef0ddSTomohiro Kusumi } else {
2284daef0ddSTomohiro Kusumi printf("PFS#%d {\n", pfs.pfs_id);
2294daef0ddSTomohiro Kusumi dump_pfsd(pfs.ondisk, fd);
2304daef0ddSTomohiro Kusumi printf("}\n");
2314daef0ddSTomohiro Kusumi }
2324daef0ddSTomohiro Kusumi if (fd >= 0)
2334daef0ddSTomohiro Kusumi close(fd);
2344daef0ddSTomohiro Kusumi if (pfs.ondisk)
2354daef0ddSTomohiro Kusumi free(pfs.ondisk);
2364daef0ddSTomohiro Kusumi relpfs(fd, &pfs);
2374daef0ddSTomohiro Kusumi }
238fdba9548STomohiro Kusumi
239fdba9548STomohiro Kusumi void
hammer_cmd_pseudofs_status(char ** av,int ac)240fdba9548STomohiro Kusumi hammer_cmd_pseudofs_status(char **av, int ac)
241fdba9548STomohiro Kusumi {
242fdba9548STomohiro Kusumi int i;
243fdba9548STomohiro Kusumi
244fdba9548STomohiro Kusumi if (ac == 0) {
245fdba9548STomohiro Kusumi char buf[2] = "."; /* can't be readonly string */
246fdba9548STomohiro Kusumi print_pfs_status(buf);
247fdba9548STomohiro Kusumi return;
248fdba9548STomohiro Kusumi }
249fdba9548STomohiro Kusumi
250fdba9548STomohiro Kusumi for (i = 0; i < ac; ++i)
251fdba9548STomohiro Kusumi print_pfs_status(av[i]);
2524daef0ddSTomohiro Kusumi }
2534daef0ddSTomohiro Kusumi
2544daef0ddSTomohiro Kusumi void
hammer_cmd_pseudofs_create(char ** av,int ac,int is_slave)2554daef0ddSTomohiro Kusumi hammer_cmd_pseudofs_create(char **av, int ac, int is_slave)
2564daef0ddSTomohiro Kusumi {
2574daef0ddSTomohiro Kusumi struct hammer_ioc_pseudofs_rw pfs;
2584daef0ddSTomohiro Kusumi struct hammer_pseudofs_data pfsd;
2594daef0ddSTomohiro Kusumi struct stat st;
2604daef0ddSTomohiro Kusumi const char *path;
261*207ba670SMatthew Dillon char *tmpbuf;
2624daef0ddSTomohiro Kusumi char *dirpath;
2634daef0ddSTomohiro Kusumi char *linkpath;
2644daef0ddSTomohiro Kusumi int pfs_id;
2654daef0ddSTomohiro Kusumi int fd;
2664daef0ddSTomohiro Kusumi
26788cdee70STomohiro Kusumi if (ac == 0) {
2684daef0ddSTomohiro Kusumi pseudofs_usage(1);
26988cdee70STomohiro Kusumi /* not reached */
27088cdee70STomohiro Kusumi }
2714daef0ddSTomohiro Kusumi path = av[0];
272052fd72bSTomohiro Kusumi if (lstat(path, &st) == 0) {
27302318f07STomohiro Kusumi errx(1, "Cannot create %s, file exists!", path);
274052fd72bSTomohiro Kusumi /* not reached */
275052fd72bSTomohiro Kusumi } else if (path[strlen(path) - 1] == '/') {
27602318f07STomohiro Kusumi errx(1, "Invalid PFS path %s with trailing /", path);
277052fd72bSTomohiro Kusumi /* not reached */
278052fd72bSTomohiro Kusumi }
2794daef0ddSTomohiro Kusumi
2804daef0ddSTomohiro Kusumi /*
2814daef0ddSTomohiro Kusumi * Figure out the directory prefix, taking care of degenerate
2824daef0ddSTomohiro Kusumi * cases.
2834daef0ddSTomohiro Kusumi */
284*207ba670SMatthew Dillon tmpbuf = strdup(path);
285*207ba670SMatthew Dillon dirpath = dirname(tmpbuf);
2864daef0ddSTomohiro Kusumi fd = open(dirpath, O_RDONLY);
287052fd72bSTomohiro Kusumi if (fd < 0) {
28802318f07STomohiro Kusumi err(1, "Cannot open directory %s", dirpath);
289052fd72bSTomohiro Kusumi /* not reached */
290052fd72bSTomohiro Kusumi }
2914daef0ddSTomohiro Kusumi
2924daef0ddSTomohiro Kusumi /*
2934daef0ddSTomohiro Kusumi * Avoid foot-shooting. Don't let the user create a PFS
2944daef0ddSTomohiro Kusumi * softlink via a PFS. PFS softlinks may only be accessed
2954daef0ddSTomohiro Kusumi * via the master filesystem. Checking it here ensures
2964daef0ddSTomohiro Kusumi * other PFS commands access PFS under the master filesystem.
2974daef0ddSTomohiro Kusumi */
2981b23fc22STomohiro Kusumi clrpfs(&pfs, &pfsd, -1);
2994daef0ddSTomohiro Kusumi
3004daef0ddSTomohiro Kusumi ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs);
301753daa18STomohiro Kusumi if (pfs.pfs_id != HAMMER_ROOT_PFSID) {
3024daef0ddSTomohiro Kusumi fprintf(stderr,
3034daef0ddSTomohiro Kusumi "You are attempting to access a PFS softlink "
3044daef0ddSTomohiro Kusumi "from a PFS. It may not represent the PFS\n"
3054daef0ddSTomohiro Kusumi "on the main filesystem mount that you "
3064daef0ddSTomohiro Kusumi "expect! You may only access PFS softlinks\n"
3074daef0ddSTomohiro Kusumi "via the main filesystem mount!\n");
3084daef0ddSTomohiro Kusumi exit(1);
3094daef0ddSTomohiro Kusumi }
3104daef0ddSTomohiro Kusumi
3114daef0ddSTomohiro Kusumi for (pfs_id = 0; pfs_id < HAMMER_MAX_PFS; ++pfs_id) {
3121b23fc22STomohiro Kusumi clrpfs(&pfs, &pfsd, pfs_id);
3134daef0ddSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) < 0) {
314052fd72bSTomohiro Kusumi if (errno != ENOENT) {
31502318f07STomohiro Kusumi err(1, "Cannot create %s", path);
316052fd72bSTomohiro Kusumi /* not reached */
317052fd72bSTomohiro Kusumi }
3184daef0ddSTomohiro Kusumi break;
3194daef0ddSTomohiro Kusumi }
3204daef0ddSTomohiro Kusumi }
321052fd72bSTomohiro Kusumi if (pfs_id == HAMMER_MAX_PFS) {
32202318f07STomohiro Kusumi errx(1, "Cannot create %s, all PFSs in use", path);
323052fd72bSTomohiro Kusumi /* not reached */
324052fd72bSTomohiro Kusumi } else if (pfs_id == HAMMER_ROOT_PFSID) {
32502318f07STomohiro Kusumi errx(1, "Fatal error: PFS#%d must exist", HAMMER_ROOT_PFSID);
326052fd72bSTomohiro Kusumi /* not reached */
327052fd72bSTomohiro Kusumi }
328e1c333cbSTomohiro Kusumi
3294daef0ddSTomohiro Kusumi /*
3304daef0ddSTomohiro Kusumi * Create the new PFS
3314daef0ddSTomohiro Kusumi */
3324daef0ddSTomohiro Kusumi printf("Creating PFS#%d\t", pfs_id);
3331b23fc22STomohiro Kusumi clrpfs(&pfs, &pfsd, pfs_id);
3344daef0ddSTomohiro Kusumi init_pfsd(&pfsd, is_slave);
3354daef0ddSTomohiro Kusumi
3364daef0ddSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_SET_PSEUDOFS, &pfs) < 0) {
3374daef0ddSTomohiro Kusumi printf("failed: %s\n", strerror(errno));
3384daef0ddSTomohiro Kusumi } else {
3394daef0ddSTomohiro Kusumi /* special symlink, must be exactly 10 characters */
3404daef0ddSTomohiro Kusumi asprintf(&linkpath, "@@PFS%05d", pfs_id);
3414daef0ddSTomohiro Kusumi if (symlink(linkpath, path) < 0) {
3424daef0ddSTomohiro Kusumi printf("failed: cannot create symlink: %s\n",
3434daef0ddSTomohiro Kusumi strerror(errno));
3444daef0ddSTomohiro Kusumi } else {
3454daef0ddSTomohiro Kusumi printf("succeeded!\n");
3464daef0ddSTomohiro Kusumi hammer_cmd_pseudofs_update(av, ac);
3474daef0ddSTomohiro Kusumi }
3484daef0ddSTomohiro Kusumi }
349*207ba670SMatthew Dillon free(tmpbuf);
350*207ba670SMatthew Dillon
3514daef0ddSTomohiro Kusumi close(fd);
3524daef0ddSTomohiro Kusumi }
3534daef0ddSTomohiro Kusumi
3544daef0ddSTomohiro Kusumi void
hammer_cmd_pseudofs_destroy(char ** av,int ac)3554daef0ddSTomohiro Kusumi hammer_cmd_pseudofs_destroy(char **av, int ac)
3564daef0ddSTomohiro Kusumi {
3574daef0ddSTomohiro Kusumi struct hammer_ioc_pseudofs_rw pfs;
358578f0d56STomohiro Kusumi char *linkpath;
3594daef0ddSTomohiro Kusumi int fd;
3604daef0ddSTomohiro Kusumi int i;
3614daef0ddSTomohiro Kusumi
36288cdee70STomohiro Kusumi if (ac == 0) {
3634daef0ddSTomohiro Kusumi pseudofs_usage(1);
36488cdee70STomohiro Kusumi /* not reached */
36588cdee70STomohiro Kusumi }
3664daef0ddSTomohiro Kusumi fd = getpfs(&pfs, av[0]);
3674daef0ddSTomohiro Kusumi
368052fd72bSTomohiro Kusumi if (pfs.pfs_id == HAMMER_ROOT_PFSID) {
369a5ff7917STomohiro Kusumi errx(1, "You cannot destroy PFS#%d", HAMMER_ROOT_PFSID);
370052fd72bSTomohiro Kusumi /* not reached */
371052fd72bSTomohiro Kusumi }
37202318f07STomohiro Kusumi
3734daef0ddSTomohiro Kusumi printf("You have requested that PFS#%d (%s) be destroyed\n",
3744daef0ddSTomohiro Kusumi pfs.pfs_id, pfs.ondisk->label);
3754daef0ddSTomohiro Kusumi printf("This will irrevocably destroy all data on this PFS!!!!!\n");
376fa9d9a9cSTomohiro Kusumi printf("Do you really want to do this? [y/n] ");
3774daef0ddSTomohiro Kusumi fflush(stdout);
378052fd72bSTomohiro Kusumi if (getyn() == 0) {
37902318f07STomohiro Kusumi errx(1, "No action taken on PFS#%d", pfs.pfs_id);
380052fd72bSTomohiro Kusumi /* not reached */
381052fd72bSTomohiro Kusumi }
3824daef0ddSTomohiro Kusumi
3832bacc088STomohiro Kusumi if (hammer_is_pfs_master(pfs.ondisk)) {
3844daef0ddSTomohiro Kusumi printf("This PFS is currently setup as a MASTER!\n");
385fa9d9a9cSTomohiro Kusumi printf("Are you absolutely sure you want to destroy it? [y/n] ");
3864daef0ddSTomohiro Kusumi fflush(stdout);
387052fd72bSTomohiro Kusumi if (getyn() == 0) {
38802318f07STomohiro Kusumi errx(1, "No action taken on PFS#%d", pfs.pfs_id);
389052fd72bSTomohiro Kusumi /* not reached */
390052fd72bSTomohiro Kusumi }
3914daef0ddSTomohiro Kusumi }
3924daef0ddSTomohiro Kusumi
393fd102df4STomohiro Kusumi printf("Destroying PFS#%d (%s)", pfs.pfs_id, pfs.ondisk->label);
394fd102df4STomohiro Kusumi if (DebugOpt) {
395fd102df4STomohiro Kusumi printf("\n");
396fd102df4STomohiro Kusumi } else {
397fd102df4STomohiro Kusumi printf(" in");
3984daef0ddSTomohiro Kusumi for (i = 5; i; --i) {
3994daef0ddSTomohiro Kusumi printf(" %d", i);
4004daef0ddSTomohiro Kusumi fflush(stdout);
4014daef0ddSTomohiro Kusumi sleep(1);
4024daef0ddSTomohiro Kusumi }
4034daef0ddSTomohiro Kusumi printf(".. starting destruction pass\n");
404fd102df4STomohiro Kusumi }
4054daef0ddSTomohiro Kusumi
4064daef0ddSTomohiro Kusumi /*
4079376f71bSTomohiro Kusumi * Remove the softlink on success.
4084daef0ddSTomohiro Kusumi */
4094daef0ddSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_RMR_PSEUDOFS, &pfs) == 0) {
4104daef0ddSTomohiro Kusumi printf("pfs-destroy of PFS#%d succeeded!\n", pfs.pfs_id);
411578f0d56STomohiro Kusumi linkpath = getlink(av[0]);
412578f0d56STomohiro Kusumi if (linkpath) {
413052fd72bSTomohiro Kusumi if (remove(linkpath) < 0) {
414f4bb1f26STomohiro Kusumi err(1, "Unable to remove softlink %s", linkpath);
415052fd72bSTomohiro Kusumi /* not reached */
416052fd72bSTomohiro Kusumi }
417578f0d56STomohiro Kusumi free(linkpath);
4184daef0ddSTomohiro Kusumi }
4194daef0ddSTomohiro Kusumi } else {
4204daef0ddSTomohiro Kusumi printf("pfs-destroy of PFS#%d failed: %s\n",
4214daef0ddSTomohiro Kusumi pfs.pfs_id, strerror(errno));
4224daef0ddSTomohiro Kusumi }
4234daef0ddSTomohiro Kusumi relpfs(fd, &pfs);
4244daef0ddSTomohiro Kusumi }
4254daef0ddSTomohiro Kusumi
4264daef0ddSTomohiro Kusumi void
hammer_cmd_pseudofs_upgrade(char ** av,int ac)4274daef0ddSTomohiro Kusumi hammer_cmd_pseudofs_upgrade(char **av, int ac)
4284daef0ddSTomohiro Kusumi {
4294daef0ddSTomohiro Kusumi struct hammer_ioc_pseudofs_rw pfs;
4304daef0ddSTomohiro Kusumi int fd;
4314daef0ddSTomohiro Kusumi
43288cdee70STomohiro Kusumi if (ac == 0) {
4334daef0ddSTomohiro Kusumi pseudofs_usage(1);
43488cdee70STomohiro Kusumi /* not reached */
43588cdee70STomohiro Kusumi }
4364daef0ddSTomohiro Kusumi fd = getpfs(&pfs, av[0]);
4374daef0ddSTomohiro Kusumi
438f254e677STomohiro Kusumi if (pfs.pfs_id == HAMMER_ROOT_PFSID) {
439a5ff7917STomohiro Kusumi errx(1, "You cannot upgrade PFS#%d"
440a5ff7917STomohiro Kusumi " (It should already be a master)",
441a5ff7917STomohiro Kusumi HAMMER_ROOT_PFSID);
442052fd72bSTomohiro Kusumi /* not reached */
443f254e677STomohiro Kusumi } else if (hammer_is_pfs_master(pfs.ondisk)) {
44402318f07STomohiro Kusumi errx(1, "It is already a master");
445052fd72bSTomohiro Kusumi /* not reached */
446f254e677STomohiro Kusumi }
4474daef0ddSTomohiro Kusumi
448f254e677STomohiro Kusumi if (ioctl(fd, HAMMERIOC_UPG_PSEUDOFS, &pfs) == 0) {
4494daef0ddSTomohiro Kusumi printf("pfs-upgrade of PFS#%d (%s) succeeded\n",
4504daef0ddSTomohiro Kusumi pfs.pfs_id, pfs.ondisk->label);
451f254e677STomohiro Kusumi } else {
452f4bb1f26STomohiro Kusumi err(1, "pfs-upgrade of PFS#%d (%s) failed",
453f4bb1f26STomohiro Kusumi pfs.pfs_id, pfs.ondisk->label);
454052fd72bSTomohiro Kusumi /* not reached */
455f254e677STomohiro Kusumi }
4564daef0ddSTomohiro Kusumi relpfs(fd, &pfs);
4574daef0ddSTomohiro Kusumi }
4584daef0ddSTomohiro Kusumi
4594daef0ddSTomohiro Kusumi void
hammer_cmd_pseudofs_downgrade(char ** av,int ac)4604daef0ddSTomohiro Kusumi hammer_cmd_pseudofs_downgrade(char **av, int ac)
4614daef0ddSTomohiro Kusumi {
4624daef0ddSTomohiro Kusumi struct hammer_ioc_pseudofs_rw pfs;
4634daef0ddSTomohiro Kusumi int fd;
4644daef0ddSTomohiro Kusumi
46588cdee70STomohiro Kusumi if (ac == 0) {
4664daef0ddSTomohiro Kusumi pseudofs_usage(1);
46788cdee70STomohiro Kusumi /* not reached */
46888cdee70STomohiro Kusumi }
4694daef0ddSTomohiro Kusumi fd = getpfs(&pfs, av[0]);
4704daef0ddSTomohiro Kusumi
471052fd72bSTomohiro Kusumi if (pfs.pfs_id == HAMMER_ROOT_PFSID) {
472a5ff7917STomohiro Kusumi errx(1, "You cannot downgrade PFS#%d", HAMMER_ROOT_PFSID);
473052fd72bSTomohiro Kusumi /* not reached */
474052fd72bSTomohiro Kusumi } else if (hammer_is_pfs_slave(pfs.ondisk)) {
47502318f07STomohiro Kusumi errx(1, "It is already a slave");
476052fd72bSTomohiro Kusumi /* not reached */
477052fd72bSTomohiro Kusumi }
4784daef0ddSTomohiro Kusumi
479f254e677STomohiro Kusumi if (ioctl(fd, HAMMERIOC_DGD_PSEUDOFS, &pfs) == 0) {
4804daef0ddSTomohiro Kusumi printf("pfs-downgrade of PFS#%d (%s) succeeded\n",
4814daef0ddSTomohiro Kusumi pfs.pfs_id, pfs.ondisk->label);
482f254e677STomohiro Kusumi } else {
483f4bb1f26STomohiro Kusumi err(1, "pfs-downgrade of PFS#%d (%s) failed",
484f4bb1f26STomohiro Kusumi pfs.pfs_id, pfs.ondisk->label);
485052fd72bSTomohiro Kusumi /* not reached */
486f254e677STomohiro Kusumi }
4874daef0ddSTomohiro Kusumi relpfs(fd, &pfs);
4884daef0ddSTomohiro Kusumi }
4894daef0ddSTomohiro Kusumi
4904daef0ddSTomohiro Kusumi void
hammer_cmd_pseudofs_update(char ** av,int ac)4914daef0ddSTomohiro Kusumi hammer_cmd_pseudofs_update(char **av, int ac)
4924daef0ddSTomohiro Kusumi {
4934daef0ddSTomohiro Kusumi struct hammer_ioc_pseudofs_rw pfs;
4944daef0ddSTomohiro Kusumi int fd;
4954daef0ddSTomohiro Kusumi
49688cdee70STomohiro Kusumi if (ac == 0) {
4974daef0ddSTomohiro Kusumi pseudofs_usage(1);
49888cdee70STomohiro Kusumi /* not reached */
49988cdee70STomohiro Kusumi }
5004daef0ddSTomohiro Kusumi fd = getpfs(&pfs, av[0]);
5014daef0ddSTomohiro Kusumi
5024daef0ddSTomohiro Kusumi printf("%s\n", av[0]);
5034daef0ddSTomohiro Kusumi fflush(stdout);
5044daef0ddSTomohiro Kusumi
5054daef0ddSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) == 0) {
5064daef0ddSTomohiro Kusumi parse_pfsd_options(av + 1, ac - 1, pfs.ondisk);
5072bacc088STomohiro Kusumi if (hammer_is_pfs_slave(pfs.ondisk) &&
508f254e677STomohiro Kusumi pfs.pfs_id == HAMMER_ROOT_PFSID) {
50902318f07STomohiro Kusumi errx(1, "The real mount point cannot be made a PFS "
5104daef0ddSTomohiro Kusumi "slave, only PFS sub-directories can be made "
51102318f07STomohiro Kusumi "slaves");
512052fd72bSTomohiro Kusumi /* not reached */
513f254e677STomohiro Kusumi }
5144daef0ddSTomohiro Kusumi pfs.bytes = sizeof(*pfs.ondisk);
5154daef0ddSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_SET_PSEUDOFS, &pfs) == 0) {
516f254e677STomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) == 0) {
5174daef0ddSTomohiro Kusumi dump_pfsd(pfs.ondisk, fd);
518f254e677STomohiro Kusumi } else {
51902318f07STomohiro Kusumi err(1, "Unable to retrieve PFS configuration "
52002318f07STomohiro Kusumi "after successful update");
521052fd72bSTomohiro Kusumi /* not reached */
522f254e677STomohiro Kusumi }
5234daef0ddSTomohiro Kusumi } else {
52402318f07STomohiro Kusumi err(1, "Unable to adjust PFS configuration");
525052fd72bSTomohiro Kusumi /* not reached */
5264daef0ddSTomohiro Kusumi }
5274daef0ddSTomohiro Kusumi }
5284daef0ddSTomohiro Kusumi relpfs(fd, &pfs);
5294daef0ddSTomohiro Kusumi }
5304daef0ddSTomohiro Kusumi
531005a4da7STomohiro Kusumi static
532005a4da7STomohiro Kusumi void
init_pfsd(hammer_pseudofs_data_t pfsd,int is_slave)5334daef0ddSTomohiro Kusumi init_pfsd(hammer_pseudofs_data_t pfsd, int is_slave)
5344daef0ddSTomohiro Kusumi {
5354daef0ddSTomohiro Kusumi bzero(pfsd, sizeof(*pfsd));
5364daef0ddSTomohiro Kusumi pfsd->sync_beg_tid = 1;
5374daef0ddSTomohiro Kusumi pfsd->sync_end_tid = 1;
5384daef0ddSTomohiro Kusumi pfsd->sync_beg_ts = 0;
5394daef0ddSTomohiro Kusumi pfsd->sync_end_ts = 0;
5403cd578edSTomohiro Kusumi hammer_uuid_create(&pfsd->shared_uuid);
5413cd578edSTomohiro Kusumi hammer_uuid_create(&pfsd->unique_uuid);
5424daef0ddSTomohiro Kusumi if (is_slave)
5434daef0ddSTomohiro Kusumi pfsd->mirror_flags |= HAMMER_PFSD_SLAVE;
5444daef0ddSTomohiro Kusumi }
5454daef0ddSTomohiro Kusumi
5464daef0ddSTomohiro Kusumi void
dump_pfsd(hammer_pseudofs_data_t pfsd,int fd)5474daef0ddSTomohiro Kusumi dump_pfsd(hammer_pseudofs_data_t pfsd, int fd)
5484daef0ddSTomohiro Kusumi {
5494daef0ddSTomohiro Kusumi struct hammer_ioc_version version;
5504daef0ddSTomohiro Kusumi char *str = NULL;
5514daef0ddSTomohiro Kusumi
5524daef0ddSTomohiro Kusumi printf(" sync-beg-tid=0x%016jx\n", (uintmax_t)pfsd->sync_beg_tid);
5534daef0ddSTomohiro Kusumi printf(" sync-end-tid=0x%016jx\n", (uintmax_t)pfsd->sync_end_tid);
5543cd578edSTomohiro Kusumi hammer_uuid_to_string(&pfsd->shared_uuid, &str);
5554daef0ddSTomohiro Kusumi printf(" shared-uuid=%s\n", str);
5564daef0ddSTomohiro Kusumi free(str);
5573cd578edSTomohiro Kusumi hammer_uuid_to_string(&pfsd->unique_uuid, &str);
5584daef0ddSTomohiro Kusumi printf(" unique-uuid=%s\n", str);
5594daef0ddSTomohiro Kusumi free(str);
5604daef0ddSTomohiro Kusumi printf(" label=\"%s\"\n", pfsd->label);
5614daef0ddSTomohiro Kusumi if (pfsd->snapshots[0])
5624daef0ddSTomohiro Kusumi printf(" snapshots=\"%s\"\n", pfsd->snapshots);
563f254e677STomohiro Kusumi if (pfsd->prune_min < (60 * 60 * 24)) {
5644daef0ddSTomohiro Kusumi printf(" prune-min=%02d:%02d:%02d\n",
5654daef0ddSTomohiro Kusumi pfsd->prune_min / 60 / 60 % 24,
5664daef0ddSTomohiro Kusumi pfsd->prune_min / 60 % 60,
5674daef0ddSTomohiro Kusumi pfsd->prune_min % 60);
568f254e677STomohiro Kusumi } else if (pfsd->prune_min % (60 * 60 * 24)) {
5694daef0ddSTomohiro Kusumi printf(" prune-min=%dd/%02d:%02d:%02d\n",
5704daef0ddSTomohiro Kusumi pfsd->prune_min / 60 / 60 / 24,
5714daef0ddSTomohiro Kusumi pfsd->prune_min / 60 / 60 % 24,
5724daef0ddSTomohiro Kusumi pfsd->prune_min / 60 % 60,
5734daef0ddSTomohiro Kusumi pfsd->prune_min % 60);
574f254e677STomohiro Kusumi } else {
5754daef0ddSTomohiro Kusumi printf(" prune-min=%dd\n", pfsd->prune_min / 60 / 60 / 24);
576f254e677STomohiro Kusumi }
5774daef0ddSTomohiro Kusumi
57852e2f1b5STomohiro Kusumi if (hammer_is_pfs_slave(pfsd))
5794daef0ddSTomohiro Kusumi printf(" operating as a SLAVE\n");
58052e2f1b5STomohiro Kusumi else
5814daef0ddSTomohiro Kusumi printf(" operating as a MASTER\n");
5824daef0ddSTomohiro Kusumi
5834daef0ddSTomohiro Kusumi /*
5844daef0ddSTomohiro Kusumi * Snapshots directory cannot be shown when there is no fd since
5854daef0ddSTomohiro Kusumi * hammer version can't be retrieved. mirror-dump passes -1 because
5864daef0ddSTomohiro Kusumi * its input came from mirror-read output thus no path is available
5874daef0ddSTomohiro Kusumi * to open(2).
5884daef0ddSTomohiro Kusumi */
5894daef0ddSTomohiro Kusumi if (fd >= 0 && pfsd->snapshots[0] == 0) {
5904daef0ddSTomohiro Kusumi bzero(&version, sizeof(version));
5914daef0ddSTomohiro Kusumi if (ioctl(fd, HAMMERIOC_GET_VERSION, &version) < 0)
5924daef0ddSTomohiro Kusumi return;
5934c09d9c4SMatthew Dillon HammerVersion = version.cur_version;
5944daef0ddSTomohiro Kusumi if (version.cur_version < 3) {
595f254e677STomohiro Kusumi if (hammer_is_pfs_slave(pfsd)) {
5964daef0ddSTomohiro Kusumi printf(" snapshots directory not set for "
5974daef0ddSTomohiro Kusumi "slave\n");
598f254e677STomohiro Kusumi } else {
5994daef0ddSTomohiro Kusumi printf(" snapshots directory for master "
6004daef0ddSTomohiro Kusumi "defaults to <pfs>/snapshots\n");
601f254e677STomohiro Kusumi }
6024daef0ddSTomohiro Kusumi } else {
6034daef0ddSTomohiro Kusumi printf(" snapshots directory defaults to "
6044daef0ddSTomohiro Kusumi "/var/hammer/<pfs>\n");
6054daef0ddSTomohiro Kusumi }
6064daef0ddSTomohiro Kusumi }
6074daef0ddSTomohiro Kusumi }
6084daef0ddSTomohiro Kusumi
609005a4da7STomohiro Kusumi static
610005a4da7STomohiro Kusumi void
parse_pfsd_options(char ** av,int ac,hammer_pseudofs_data_t pfsd)6114daef0ddSTomohiro Kusumi parse_pfsd_options(char **av, int ac, hammer_pseudofs_data_t pfsd)
6124daef0ddSTomohiro Kusumi {
6134daef0ddSTomohiro Kusumi char *cmd;
6144daef0ddSTomohiro Kusumi char *ptr;
6154daef0ddSTomohiro Kusumi int len;
6164daef0ddSTomohiro Kusumi
6174daef0ddSTomohiro Kusumi while (ac) {
6184daef0ddSTomohiro Kusumi cmd = *av;
6194daef0ddSTomohiro Kusumi if ((ptr = strchr(cmd, '=')) != NULL)
6204daef0ddSTomohiro Kusumi *ptr++ = 0;
6214daef0ddSTomohiro Kusumi
6224daef0ddSTomohiro Kusumi /*
6234daef0ddSTomohiro Kusumi * Basic assignment value test
6244daef0ddSTomohiro Kusumi */
625052fd72bSTomohiro Kusumi if (ptr == NULL) {
62602318f07STomohiro Kusumi errx(1, "option %s requires an assignment", cmd);
627052fd72bSTomohiro Kusumi /* not reached */
628052fd72bSTomohiro Kusumi }
6294daef0ddSTomohiro Kusumi
6304daef0ddSTomohiro Kusumi if (strcmp(cmd, "sync-beg-tid") == 0) {
6314daef0ddSTomohiro Kusumi pfsd->sync_beg_tid = strtoull(ptr, NULL, 16);
6324daef0ddSTomohiro Kusumi } else if (strcmp(cmd, "sync-end-tid") == 0) {
6334daef0ddSTomohiro Kusumi pfsd->sync_end_tid = strtoull(ptr, NULL, 16);
6344daef0ddSTomohiro Kusumi } else if (strcmp(cmd, "shared-uuid") == 0) {
6353cd578edSTomohiro Kusumi if (hammer_uuid_from_string(ptr, &pfsd->shared_uuid)) {
6363cd578edSTomohiro Kusumi errx(1, "option %s: error parsing uuid %s",
6373cd578edSTomohiro Kusumi cmd, ptr);
6383cd578edSTomohiro Kusumi /* not reached */
6393cd578edSTomohiro Kusumi }
6404daef0ddSTomohiro Kusumi } else if (strcmp(cmd, "unique-uuid") == 0) {
6413cd578edSTomohiro Kusumi if (hammer_uuid_from_string(ptr, &pfsd->unique_uuid)) {
6423cd578edSTomohiro Kusumi errx(1, "option %s: error parsing uuid %s",
6433cd578edSTomohiro Kusumi cmd, ptr);
6443cd578edSTomohiro Kusumi /* not reached */
6453cd578edSTomohiro Kusumi }
6464daef0ddSTomohiro Kusumi } else if (strcmp(cmd, "label") == 0) {
6474daef0ddSTomohiro Kusumi len = strlen(ptr);
6484daef0ddSTomohiro Kusumi if (ptr[0] == '"' && ptr[len-1] == '"') {
6494daef0ddSTomohiro Kusumi ptr[len-1] = 0;
6504daef0ddSTomohiro Kusumi ++ptr;
6514daef0ddSTomohiro Kusumi } else if (ptr[0] == '"') {
65202318f07STomohiro Kusumi errx(1, "option %s: malformed string", cmd);
653052fd72bSTomohiro Kusumi /* not reached */
6544daef0ddSTomohiro Kusumi }
6554daef0ddSTomohiro Kusumi snprintf(pfsd->label, sizeof(pfsd->label), "%s", ptr);
6564daef0ddSTomohiro Kusumi } else if (strcmp(cmd, "snapshots") == 0) {
6574daef0ddSTomohiro Kusumi len = strlen(ptr);
6584daef0ddSTomohiro Kusumi if (ptr[0] != '/') {
6594daef0ddSTomohiro Kusumi fprintf(stderr,
6604daef0ddSTomohiro Kusumi "option %s: '%s' must be an "
6614daef0ddSTomohiro Kusumi "absolute path\n", cmd, ptr);
662f254e677STomohiro Kusumi if (ptr[0] == 0) {
6634daef0ddSTomohiro Kusumi fprintf(stderr,
6644daef0ddSTomohiro Kusumi "use 'snapshots-clear' "
6654daef0ddSTomohiro Kusumi "to unset snapshots dir\n");
666f254e677STomohiro Kusumi }
6674daef0ddSTomohiro Kusumi exit(1);
6684daef0ddSTomohiro Kusumi }
669f254e677STomohiro Kusumi if (len >= (int)sizeof(pfsd->snapshots)) {
67002318f07STomohiro Kusumi errx(1, "option %s: path too long, %d "
67102318f07STomohiro Kusumi "character limit", cmd, len);
672052fd72bSTomohiro Kusumi /* not reached */
673f254e677STomohiro Kusumi }
6744daef0ddSTomohiro Kusumi snprintf(pfsd->snapshots, sizeof(pfsd->snapshots),
6754daef0ddSTomohiro Kusumi "%s", ptr);
6764daef0ddSTomohiro Kusumi } else if (strcmp(cmd, "snapshots-clear") == 0) {
6774daef0ddSTomohiro Kusumi pfsd->snapshots[0] = 0;
6784daef0ddSTomohiro Kusumi } else if (strcmp(cmd, "prune-min") == 0) {
6794daef0ddSTomohiro Kusumi pfsd->prune_min = timetosecs(ptr);
680f254e677STomohiro Kusumi if (pfsd->prune_min < 0) {
68102318f07STomohiro Kusumi errx(1, "option %s: illegal time spec, "
68202318f07STomohiro Kusumi "use Nd or [Nd/]hh[:mm[:ss]]", ptr);
683052fd72bSTomohiro Kusumi /* not reached */
684f254e677STomohiro Kusumi }
6854daef0ddSTomohiro Kusumi } else {
68602318f07STomohiro Kusumi errx(1, "invalid option: %s", cmd);
687052fd72bSTomohiro Kusumi /* not reached */
6884daef0ddSTomohiro Kusumi }
6894daef0ddSTomohiro Kusumi --ac;
6904daef0ddSTomohiro Kusumi ++av;
6914daef0ddSTomohiro Kusumi }
6924daef0ddSTomohiro Kusumi }
6934daef0ddSTomohiro Kusumi
6944daef0ddSTomohiro Kusumi static
6954daef0ddSTomohiro Kusumi void
pseudofs_usage(int code)6964daef0ddSTomohiro Kusumi pseudofs_usage(int code)
6974daef0ddSTomohiro Kusumi {
6984daef0ddSTomohiro Kusumi fprintf(stderr,
6994daef0ddSTomohiro Kusumi "hammer pfs-status <dirpath> ...\n"
7004daef0ddSTomohiro Kusumi "hammer pfs-master <dirpath> [options]\n"
7014daef0ddSTomohiro Kusumi "hammer pfs-slave <dirpath> [options]\n"
7024daef0ddSTomohiro Kusumi "hammer pfs-update <dirpath> [options]\n"
7034daef0ddSTomohiro Kusumi "hammer pfs-upgrade <dirpath>\n"
7044daef0ddSTomohiro Kusumi "hammer pfs-downgrade <dirpath>\n"
7054daef0ddSTomohiro Kusumi "hammer pfs-destroy <dirpath>\n"
7064daef0ddSTomohiro Kusumi "\n"
7074daef0ddSTomohiro Kusumi "options:\n"
7084daef0ddSTomohiro Kusumi " sync-beg-tid=0x16llx\n"
7094daef0ddSTomohiro Kusumi " sync-end-tid=0x16llx\n"
7104daef0ddSTomohiro Kusumi " shared-uuid=0x16llx\n"
7114daef0ddSTomohiro Kusumi " unique-uuid=0x16llx\n"
7124daef0ddSTomohiro Kusumi " label=\"string\"\n"
7134daef0ddSTomohiro Kusumi " snapshots=\"/path\"\n"
7144daef0ddSTomohiro Kusumi " snapshots-clear\n"
7154daef0ddSTomohiro Kusumi " prune-min=Nd\n"
7164daef0ddSTomohiro Kusumi " prune-min=[Nd/]hh[:mm[:ss]]\n"
7174daef0ddSTomohiro Kusumi );
7184daef0ddSTomohiro Kusumi exit(code);
7194daef0ddSTomohiro Kusumi }
7204daef0ddSTomohiro Kusumi
7214daef0ddSTomohiro Kusumi /*
7224daef0ddSTomohiro Kusumi * Convert time in the form [Nd/]hh[:mm[:ss]] to seconds.
7234daef0ddSTomohiro Kusumi *
7244daef0ddSTomohiro Kusumi * Return -1 if a parse error occurs.
7254daef0ddSTomohiro Kusumi * Return 0x7FFFFFFF if the time exceeds the maximum allowed.
7264daef0ddSTomohiro Kusumi */
7274daef0ddSTomohiro Kusumi static
7284daef0ddSTomohiro Kusumi int
timetosecs(char * str)7294daef0ddSTomohiro Kusumi timetosecs(char *str)
7304daef0ddSTomohiro Kusumi {
7314daef0ddSTomohiro Kusumi int days = 0;
7324daef0ddSTomohiro Kusumi int hrs = 0;
7334daef0ddSTomohiro Kusumi int mins = 0;
7344daef0ddSTomohiro Kusumi int secs = 0;
7354daef0ddSTomohiro Kusumi int n;
7364daef0ddSTomohiro Kusumi long long v;
7374daef0ddSTomohiro Kusumi char *ptr;
7384daef0ddSTomohiro Kusumi
7394daef0ddSTomohiro Kusumi n = strtol(str, &ptr, 10);
7404daef0ddSTomohiro Kusumi if (n < 0)
7414daef0ddSTomohiro Kusumi return(-1);
7424daef0ddSTomohiro Kusumi if (*ptr == 'd') {
7434daef0ddSTomohiro Kusumi days = n;
7444daef0ddSTomohiro Kusumi ++ptr;
7454daef0ddSTomohiro Kusumi if (*ptr == '/')
7464daef0ddSTomohiro Kusumi n = strtol(ptr + 1, &ptr, 10);
7474daef0ddSTomohiro Kusumi else
7484daef0ddSTomohiro Kusumi n = 0;
7494daef0ddSTomohiro Kusumi }
7504daef0ddSTomohiro Kusumi if (n < 0)
7514daef0ddSTomohiro Kusumi return(-1);
7524daef0ddSTomohiro Kusumi hrs = n;
7534daef0ddSTomohiro Kusumi if (*ptr == ':') {
7544daef0ddSTomohiro Kusumi n = strtol(ptr + 1, &ptr, 10);
7554daef0ddSTomohiro Kusumi if (n < 0)
7564daef0ddSTomohiro Kusumi return(-1);
7574daef0ddSTomohiro Kusumi mins = n;
7584daef0ddSTomohiro Kusumi if (*ptr == ':') {
7594daef0ddSTomohiro Kusumi n = strtol(ptr + 1, &ptr, 10);
7604daef0ddSTomohiro Kusumi if (n < 0)
7614daef0ddSTomohiro Kusumi return(-1);
7624daef0ddSTomohiro Kusumi secs = n;
7634daef0ddSTomohiro Kusumi }
7644daef0ddSTomohiro Kusumi }
7654daef0ddSTomohiro Kusumi if (*ptr)
7664daef0ddSTomohiro Kusumi return(-1);
7674daef0ddSTomohiro Kusumi v = days * 24 * 60 * 60 + hrs * 60 * 60 + mins * 60 + secs;
7684daef0ddSTomohiro Kusumi if (v > 0x7FFFFFFF)
7694daef0ddSTomohiro Kusumi v = 0x7FFFFFFF;
7704daef0ddSTomohiro Kusumi return((int)v);
7714daef0ddSTomohiro Kusumi }
772