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 
47 static const int TRUE = 1;
48 static char *filebase;
49 
50 static int
51 pickidx()
52 {
53 	return (random() % 1000);
54 }
55 
56 /* ARGSUSED */
57 static void *
58 mover(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 */
75 static void *
76 cleaner(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 
92 static void *
93 writer(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 
108 int
109 main(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