1#!/bin/sh
2
3#
4# Copyright (c) 2011 Peter Holm <pho@FreeBSD.org>
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# Variation of suj20.sh, with focus on the FS state after a panic / power
30# cycle.
31
32# Demonstrate "multiple references to blocks" in FS after reboot from a
33# looping mksnap_ffs(8).
34
35[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
36
37. ../default.cfg
38
39# Scenario by mckusick@
40#
41# create a bunch of files/directories
42# create a snapshot
43# remove many (but not all) of those files/directories
44# create some new files/directories in what remains of those
45#     original files/directories.
46# create another snapshot
47# repeat {
48#         remove many (somewhat different) of those files/directories
49#         create some new files/directories in what remains of those
50#             remaining files/directories.
51#         create a new snapshot
52#         remove oldest snapshot
53# }
54
55snap () {
56	for i in `jot 5`; do
57		mksnap_ffs $1 $2 2>&1 | grep -v "Resource temporarily unavailable"
58		[ ! -s $2 ] && rm -f $2	|| return 0
59		sleep 1
60	done
61	return 1
62}
63
64D=$diskimage
65
66if [ -n "`find $D -mtime -1h 2>/dev/null`" ]; then
67	# FS left by previous crash
68	mdconfig -a -t vnode -f $D -u $mdstart
69	fsck -t ufs -y md$mdstart
70	fsck -t ufs -y md$mdstart
71	rm -f $D
72	exit 0
73fi
74
75here=`pwd`
76cd /tmp
77sed '1,/^EOF/d' < $here/$0 > suj22.c
78mycc -o suj22 -Wall -Wextra -O2 suj22.c
79rm -f suj22.c
80
81mount | grep "$mntpoint" | grep -q md$mdstart && umount $mntpoint
82mdconfig -l | grep -q md$mdstart &&  mdconfig -d -u $mdstart
83
84dd if=/dev/zero of=$D bs=1m count=1k status=none || exit 1
85mdconfig -a -t vnode -f $D -u $mdstart
86newfs -j md$mdstart > /dev/null
87mount /dev/md$mdstart $mntpoint
88
89cd $mntpoint
90chmod 777 $mntpoint
91/tmp/suj22
92snap $mntpoint $mntpoint/.snap/snap1
93/tmp/suj22 prune
94snap $mntpoint $mntpoint/.snap/snap2
95/tmp/suj22
96for i in `jot 10`; do
97	/tmp/suj22 prune
98	/tmp/suj22
99	snap $mntpoint $mntpoint/.snap/snap$((i + 2)) || break
100	sn=`ls -tU $mntpoint/.snap | tail -1`
101	rm -f $mntpoint/.snap/$sn
102done
103cd $here
104
105while mount | grep -q $mntpoint; do
106	umount $mntpoint || sleep 1
107done
108fsck -t ufs -y md$mdstart
109fsck -t ufs -y md$mdstart
110mdconfig -d -u $mdstart
111rm -f /tmp/suj22 $D
112exit 0
113EOF
114#include <sys/types.h>
115#include <err.h>
116#include <errno.h>
117#include <fcntl.h>
118#include <stdio.h>
119#include <stdlib.h>
120#include <sys/stat.h>
121#include <unistd.h>
122
123static char buf[4096];
124#define ND 100
125#define NF 100
126
127void
128setup(void)
129{
130	int d, f, fd, i, n;
131	char name[128];
132
133	for (d = 0; d < ND; d++) {
134		snprintf(name, sizeof(name), "d%03d", d);
135		if (mkdir(name, 00700) == -1 && errno != EEXIST)
136			err(1, "mkdir(%s)", name);
137		if (chdir(name) == -1)
138			err(1, "chdir(%s)", name);
139		for (f = 0; f < NF; f++) {
140			if (arc4random() % 100 < 33)
141				continue;
142			snprintf(name, sizeof(name), "f%03d", f);
143			if ((fd = open(name, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1)
144				err(1, "open(%s)", name);
145			n = arc4random() % 10;
146			for (i = 0; i < n; i++) {
147				if (write(fd, buf, sizeof(buf)) != sizeof(buf))
148					err(1, "write()");
149			}
150			close(fd);
151		}
152		if (chdir("..") == -1)
153			err(1, "chdir(%s)", "..");
154	}
155}
156void
157
158prune(void)
159{
160	int d, f;
161	char name[128];
162
163	for (d = 0; d < ND; d++) {
164		snprintf(name, sizeof(name), "d%03d", d);
165		if (chdir(name) == -1)
166			err(1, "chdir(%s)", name);
167		for (f = 0; f < NF; f++) {
168			if (arc4random() % 100 < 33)
169				continue;
170			snprintf(name, sizeof(name), "f%03d", f);
171			if (unlink(name) == -1 && errno != ENOENT)
172				err(1, "unlink(%s)", name);
173		}
174		if (chdir("..") == -1)
175			err(1, "chdir(%s)", "..");
176	}
177	for (d = 0; d < ND; d++) {
178		if (arc4random() % 100 > 10)
179			continue;
180		snprintf(name, sizeof(name), "rm -rf d%03d", d);
181		system(name);
182	}
183}
184
185int
186main(int argc, char **argv __unused)
187{
188	if (argc == 1)
189		setup();
190	if (argc == 2)
191		prune();
192
193	return (0);
194}
195