1ea8dc4beschrock/*
2ea8dc4beschrock * CDDL HEADER START
3ea8dc4beschrock *
4ea8dc4beschrock * The contents of this file are subject to the terms of the
5ea8dc4beschrock * Common Development and Distribution License (the "License").
6ea8dc4beschrock * You may not use this file except in compliance with the License.
7ea8dc4beschrock *
8ea8dc4beschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ea8dc4beschrock * or http://www.opensolaris.org/os/licensing.
10ea8dc4beschrock * See the License for the specific language governing permissions
11ea8dc4beschrock * and limitations under the License.
12ea8dc4beschrock *
13ea8dc4beschrock * When distributing Covered Code, include this CDDL HEADER in each
14ea8dc4beschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ea8dc4beschrock * If applicable, add the following below this CDDL HEADER, with the
16ea8dc4beschrock * fields enclosed by brackets "[]" replaced with your own identifying
17ea8dc4beschrock * information: Portions Copyright [yyyy] [name of copyright owner]
18ea8dc4beschrock *
19ea8dc4beschrock * CDDL HEADER END
20ea8dc4beschrock */
21ea8dc4beschrock/*
22f80ce22Chris Kirby * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23283b846George.Wilson * Copyright (c) 2012 by Delphix. All rights reserved.
24ea8dc4beschrock */
25ea8dc4beschrock
26ea8dc4beschrock#include <libzfs.h>
27ea8dc4beschrock
28ea8dc4beschrock#include <sys/zfs_context.h>
29ea8dc4beschrock
30ea8dc4beschrock#include <errno.h>
31ea8dc4beschrock#include <fcntl.h>
32ea8dc4beschrock#include <stdarg.h>
33ea8dc4beschrock#include <stddef.h>
34ea8dc4beschrock#include <stdio.h>
35ea8dc4beschrock#include <stdlib.h>
36ea8dc4beschrock#include <strings.h>
37ea8dc4beschrock#include <sys/file.h>
38ea8dc4beschrock#include <sys/mntent.h>
39ea8dc4beschrock#include <sys/mnttab.h>
40ea8dc4beschrock#include <sys/param.h>
41ea8dc4beschrock#include <sys/stat.h>
42ea8dc4beschrock
43ea8dc4beschrock#include <sys/dmu.h>
44ea8dc4beschrock#include <sys/dmu_objset.h>
45ea8dc4beschrock#include <sys/dnode.h>
4621bf64agw#include <sys/vdev_impl.h>
47ea8dc4beschrock
48ea8dc4beschrock#include <sys/mkdev.h>
49ea8dc4beschrock
50ea8dc4beschrock#include "zinject.h"
51ea8dc4beschrock
52ea8dc4beschrockextern void kernel_init(int);
53ea8dc4beschrockextern void kernel_fini(void);
54ea8dc4beschrock
55ea8dc4beschrockstatic int debug;
56ea8dc4beschrock
57ea8dc4beschrockstatic void
58ea8dc4beschrockziprintf(const char *fmt, ...)
59ea8dc4beschrock{
60ea8dc4beschrock	va_list ap;
61ea8dc4beschrock
62ea8dc4beschrock	if (!debug)
63ea8dc4beschrock		return;
64ea8dc4beschrock
65ea8dc4beschrock	va_start(ap, fmt);
66ea8dc4beschrock	(void) vprintf(fmt, ap);
67ea8dc4beschrock	va_end(ap);
68ea8dc4beschrock}
69ea8dc4beschrock
70f80ce22Chris Kirbystatic void
71f80ce22Chris Kirbycompress_slashes(const char *src, char *dest)
72f80ce22Chris Kirby{
73f80ce22Chris Kirby	while (*src != '\0') {
74f80ce22Chris Kirby		*dest = *src++;
75f80ce22Chris Kirby		while (*dest == '/' && *src == '/')
76f80ce22Chris Kirby			++src;
77f80ce22Chris Kirby		++dest;
78f80ce22Chris Kirby	}
79f80ce22Chris Kirby	*dest = '\0';
80f80ce22Chris Kirby}
81f80ce22Chris Kirby
82ea8dc4beschrock/*
83ea8dc4beschrock * Given a full path to a file, translate into a dataset name and a relative
84ea8dc4beschrock * path within the dataset.  'dataset' must be at least MAXNAMELEN characters,
85ea8dc4beschrock * and 'relpath' must be at least MAXPATHLEN characters.  We also pass a stat64
86ea8dc4beschrock * buffer, which we need later to get the object ID.
87ea8dc4beschrock */
88ea8dc4beschrockstatic int
89f80ce22Chris Kirbyparse_pathname(const char *inpath, char *dataset, char *relpath,
90ea8dc4beschrock    struct stat64 *statbuf)
91ea8dc4beschrock{
92ea8dc4beschrock	struct extmnttab mp;
93ea8dc4beschrock	FILE *fp;
94ea8dc4beschrock	int match;
95ea8dc4beschrock	const char *rel;
96f80ce22Chris Kirby	char fullpath[MAXPATHLEN];
97f80ce22Chris Kirby
98f80ce22Chris Kirby	compress_slashes(inpath, fullpath);
99ea8dc4beschrock
100ea8dc4beschrock	if (fullpath[0] != '/') {
101ea8dc4beschrock		(void) fprintf(stderr, "invalid object '%s': must be full "
102ea8dc4beschrock		    "path\n", fullpath);
103ea8dc4beschrock		usage();
104ea8dc4beschrock		return (-1);
105ea8dc4beschrock	}
106ea8dc4beschrock
107ea8dc4beschrock	if (strlen(fullpath) >= MAXPATHLEN) {
108ea8dc4beschrock		(void) fprintf(stderr, "invalid object; pathname too long\n");
109ea8dc4beschrock		return (-1);
110ea8dc4beschrock	}
111ea8dc4beschrock
112ea8dc4beschrock	if (stat64(fullpath, statbuf) != 0) {
113ea8dc4beschrock		(void) fprintf(stderr, "cannot open '%s': %s\n",
114ea8dc4beschrock		    fullpath, strerror(errno));
115ea8dc4beschrock		return (-1);
116ea8dc4beschrock	}
117ea8dc4beschrock
118ea8dc4beschrock	if ((fp = fopen(MNTTAB, "r")) == NULL) {
119ea8dc4beschrock		(void) fprintf(stderr, "cannot open /etc/mnttab\n");
120ea8dc4beschrock		return (-1);
121ea8dc4beschrock	}
122ea8dc4beschrock
123ea8dc4beschrock	match = 0;
124ea8dc4beschrock	while (getextmntent(fp, &mp, sizeof (mp)) == 0) {
125ea8dc4beschrock		if (makedev(mp.mnt_major, mp.mnt_minor) == statbuf->st_dev) {
126ea8dc4beschrock			match = 1;
127ea8dc4beschrock			break;
128ea8dc4beschrock		}
129ea8dc4beschrock	}
130ea8dc4beschrock
131ea8dc4beschrock	if (!match) {
132ea8dc4beschrock		(void) fprintf(stderr, "cannot find mountpoint for '%s'\n",
133ea8dc4beschrock		    fullpath);
134ea8dc4beschrock		return (-1);
135ea8dc4beschrock	}
136ea8dc4beschrock
137ea8dc4beschrock	if (strcmp(mp.mnt_fstype, MNTTYPE_ZFS) != 0) {
138ea8dc4beschrock		(void) fprintf(stderr, "invalid path '%s': not a ZFS "
139ea8dc4beschrock		    "filesystem\n", fullpath);
140ea8dc4beschrock		return (-1);
141ea8dc4beschrock	}
142ea8dc4beschrock
143ea8dc4beschrock	if (strncmp(fullpath, mp.mnt_mountp, strlen(mp.mnt_mountp)) != 0) {
144ea8dc4beschrock		(void) fprintf(stderr, "invalid path '%s': mountpoint "
145ea8dc4beschrock		    "doesn't match path\n", fullpath);
146ea8dc4beschrock		return (-1);
147ea8dc4beschrock	}
148ea8dc4beschrock
149ea8dc4beschrock	(void) strcpy(dataset, mp.mnt_special);
150ea8dc4beschrock
151ea8dc4beschrock	rel = fullpath + strlen(mp.mnt_mountp);
152ea8dc4beschrock	if (rel[0] == '/')
153ea8dc4beschrock		rel++;
154ea8dc4beschrock	(void) strcpy(relpath, rel);
155ea8dc4beschrock
156ea8dc4beschrock	return (0);
157ea8dc4beschrock}
158ea8dc4beschrock
159ea8dc4beschrock/*
160ea8dc4beschrock * Convert from a (dataset, path) pair into a (objset, object) pair.  Note that
161ea8dc4beschrock * we grab the object number from the inode number, since looking this up via
162ea8dc4beschrock * libzpool is a real pain.
163ea8dc4beschrock */
164ea8dc4beschrock/* ARGSUSED */
165ea8dc4beschrockstatic int
166ea8dc4beschrockobject_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
167ea8dc4beschrock    zinject_record_t *record)
168ea8dc4beschrock{
169ea8dc4beschrock	objset_t *os;
170ea8dc4beschrock	int err;
171ea8dc4beschrock
172ea8dc4beschrock	/*
173ea8dc4beschrock	 * Before doing any libzpool operations, call sync() to ensure that the
174ea8dc4beschrock	 * on-disk state is consistent with the in-core state.
175ea8dc4beschrock	 */
176ea8dc4beschrock	sync();
177ea8dc4beschrock
178eb63303Tom Caputi	err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, B_FALSE, FTAG, &os);
179503ad85Matthew Ahrens	if (err != 0) {
180ea8dc4beschrock		(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
181ea8dc4beschrock		    dataset, strerror(err));
182ea8dc4beschrock		return (-1);
183ea8dc4beschrock	}
184ea8dc4beschrock
185ea8dc4beschrock	record->zi_objset = dmu_objset_id(os);
186ea8dc4beschrock	record->zi_object = statbuf->st_ino;
187ea8dc4beschrock
188eb63303Tom Caputi	dmu_objset_disown(os, B_FALSE, FTAG);
189ea8dc4beschrock
190ea8dc4beschrock	return (0);
191ea8dc4beschrock}
192ea8dc4beschrock
193ea8dc4beschrock/*
194ea8dc4beschrock * Calculate the real range based on the type, level, and range given.
195ea8dc4beschrock */
196ea8dc4beschrockstatic int
197ea8dc4beschrockcalculate_range(const char *dataset, err_type_t type, int level, char *range,
198ea8dc4beschrock    zinject_record_t *record)
199