xref: /freebsd/tools/test/stress2/misc/ftruncate.sh (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
1#!/bin/sh
2
3#
4# Copyright (c) 2016 EMC Corp.
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# ftruncate(2) fuzz.
30
31# "panic: softdep_deallocate_dependencies: dangling deps" seen in
32# 10.3-STABLE:
33# https://people.freebsd.org/~pho/stress/log/ftruncate.txt
34
35[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
36
37. ../default.cfg
38
39dir=$RUNDIR
40
41odir=`pwd`
42cd /tmp
43sed '1,/^EOF/d' < $odir/$0 > ftruncate.c
44rm -f /tmp/ftruncate
45mycc -o ftruncate -Wall -Wextra -O2 -g ftruncate.c -lpthread || exit 1
46rm -f ftruncate.c
47
48rm -rf $dir
49mkdir -p $dir
50chmod 777 $dir
51
52cd $dir
53jot 500 | xargs touch
54jot 500 | xargs chmod 666
55cd $odir
56
57(cd /tmp; /tmp/ftruncate $dir)
58e=$?
59
60rm -rf $dir
61
62rm -f /tmp/ftruncate
63exit $e
64EOF
65#include <sys/param.h>
66#include <sys/resource.h>
67
68#include <err.h>
69#include <errno.h>
70#include <fcntl.h>
71#include <fts.h>
72#include <libutil.h>
73#include <pthread.h>
74#include <pwd.h>
75#include <stdint.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <unistd.h>
80
81#define N (128 * 1024 / (int)sizeof(u_int32_t))
82#define RUNTIME 180
83#define THREADS 2
84
85static int fd[900];
86static u_int32_t r[N];
87static char *args[2];
88
89static unsigned long
90makearg(void)
91{
92	unsigned long val;
93
94	val = arc4random();
95#if defined(__LP64__)
96	val = (val << 32) | arc4random();
97	val = val & 0x00007fffffffffffUL;
98#endif
99
100	return(val);
101}
102
103static void *
104test(void *arg __unused)
105{
106	FTS *fts;
107	FTSENT *p;
108	int ftsoptions, i, n;
109
110	ftsoptions = FTS_PHYSICAL;
111
112	for (;;) {
113		for (i = 0; i < N; i++)
114			r[i] = arc4random();
115		if ((fts = fts_open(args, ftsoptions, NULL)) == NULL)
116			err(1, "fts_open");
117
118		i = n = 0;
119		while ((p = fts_read(fts)) != NULL) {
120			if (fd[i] > 0)
121				close(fd[i]);
122			if ((fd[i] = open(p->fts_path, O_RDWR)) == -1)
123				if ((fd[i] = open(p->fts_path, O_WRONLY)) == -1)
124				continue;
125			i++;
126			i = i % nitems(fd);
127		}
128
129		if (fts_close(fts) == -1)
130			err(1, "fts_close()");
131		sleep(1);
132	}
133	return(0);
134}
135
136static void *
137calls(void *arg __unused)
138{
139	off_t offset;
140	time_t start;
141	int fd2;
142
143	start = time(NULL);
144	while ((time(NULL) - start) < RUNTIME) {
145		fd2 = makearg() % nitems(fd) + 3;
146		offset = makearg();
147		if (ftruncate(fd2, offset) == 0) {
148			if (lseek(fd2, offset - 1, SEEK_SET) != -1)
149				write(fd2, "x", 1);
150		}
151
152	}
153
154	return (0);
155}
156
157int
158main(int argc, char **argv)
159{
160	struct passwd *pw;
161	pthread_t rp, cp[THREADS];
162	int e, i;
163
164	if (argc != 2) {
165		fprintf(stderr, "Usage: %s <dir>\n", argv[0]);
166		exit(1);
167	}
168	args[0] = argv[1];
169	args[1] = 0;
170
171	if ((pw = getpwnam("nobody")) == NULL)
172		err(1, "failed to resolve nobody");
173	if (setgroups(1, &pw->pw_gid) ||
174	    setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
175	    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
176		err(1, "Can't drop privileges to \"nobody\"");
177	endpwent();
178
179	if ((e = pthread_create(&rp, NULL, test, NULL)) != 0)
180		errc(1, e, "pthread_create");
181	usleep(1000);
182	for (i = 0; i < THREADS; i++)
183		if ((e = pthread_create(&cp[i], NULL, calls, NULL)) != 0)
184			errc(1, e, "pthread_create");
185	for (i = 0; i < THREADS; i++)
186		pthread_join(cp[i], NULL);
187
188	return (0);
189}
190