1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 * $FreeBSD$
21 */
22
23/*
24 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#pragma ident	"@(#)rm_lnkcnt_zero_file.c	1.3	07/05/25 SMI"
29
30/*
31 * --------------------------------------------------------------------
32 * The purpose of this test is to see if the bug reported (#4723351) for
33 * UFS exists when using a ZFS file system.
34 * --------------------------------------------------------------------
35 *
36 */
37#define	_REENTRANT 1
38#include <stdio.h>
39#include <fcntl.h>
40#include <pthread.h>
41#include <errno.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <stdlib.h>
45#include <unistd.h>
46
47static const int TRUE = 1;
48static char *filebase;
49
50static int
51pickidx()
52{
53	return (random() % 1000);
54}
55
56/* ARGSUSED */
57static void *
58mover(void *a)
59{
60	char buf[256];
61	int idx, ret;
62
63	while (TRUE) {
64		idx = pickidx();
65		(void) sprintf(buf, "%s.%03d", filebase, idx);
66		ret = rename(filebase, buf);
67		if (ret < 0 && errno != ENOENT)
68			(void) perror("renaming file");
69	}
70
71	return (NULL);
72}
73
74/* ARGSUSED */
75static void *
76cleaner(void *a)
77{
78	char buf[256];
79	int idx, ret;
80
81	while (TRUE) {
82		idx = pickidx();
83		(void) sprintf(buf, "%s.%03d", filebase, idx);
84		ret = remove(buf);
85		if (ret < 0 && errno != ENOENT)
86			(void) perror("removing file");
87	}
88
89	return (NULL);
90}
91
92static void *
93writer(void *a)
94{
95	int *fd = (int *)a;
96
97	while (TRUE) {
98		(void) close (*fd);
99		*fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644);
100		if (*fd < 0)
101			perror("refreshing file");
102		(void) write(*fd, "test\n", 5);
103	}
104
105	return (NULL);
106}
107
108int
109main(int argc, char **argv)
110{
111	int fd;
112	pthread_t tid;
113
114	if (argc == 1) {
115		(void) printf("Usage: %s <filebase>\n", argv[0]);
116		exit(-1);
117	}
118
119	filebase = argv[1];
120	fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644);
121	if (fd < 0) {
122		perror("creating test file");
123		exit(-1);
124	}
125
126	if (pthread_setconcurrency(4)) {	/* 3 threads + main */
127		fprintf(stderr, "failed to set concurrency\n");
128		exit(-1);
129	}
130	(void) pthread_create(&tid, NULL, mover, NULL);
131	(void) pthread_create(&tid, NULL, cleaner, NULL);
132	(void) pthread_create(&tid, NULL, writer, (void *) &fd);
133
134	while (TRUE) {
135		int ret;
136		struct stat st;
137
138		ret = stat(filebase, &st);
139		if (ret == 0 && (st.st_nlink > 2 || st.st_nlink < 1)) {
140			(void) printf("st.st_nlink = %d, exiting\n", \
141			    (int)st.st_nlink);
142			exit(0);
143		}
144		(void) sleep(1);
145	}
146
147	return (0);
148}
149