xref: /freebsd-src/sys/contrib/openzfs/tests/zfs-tests/cmd/mkbusy.c (revision 716fd348e01c5f2ba125f878a634a753436c2994)
1*716fd348SMartin Matuska /*
2*716fd348SMartin Matuska  * This file and its contents are supplied under the terms of the
3*716fd348SMartin Matuska  * Common Development and Distribution License ("CDDL"), version 1.0.
4*716fd348SMartin Matuska  * You may only use this file in accordance with the terms of version
5*716fd348SMartin Matuska  * 1.0 of the CDDL.
6*716fd348SMartin Matuska  *
7*716fd348SMartin Matuska  * A full copy of the text of the CDDL should have accompanied this
8*716fd348SMartin Matuska  * source.  A copy of the CDDL is also available via the Internet at
9*716fd348SMartin Matuska  * http://www.illumos.org/license/CDDL.
10*716fd348SMartin Matuska  */
11*716fd348SMartin Matuska 
12*716fd348SMartin Matuska /*
13*716fd348SMartin Matuska  * Copyright (c) 2012 by Delphix. All rights reserved.
14*716fd348SMartin Matuska  */
15*716fd348SMartin Matuska 
16*716fd348SMartin Matuska /*
17*716fd348SMartin Matuska  * Make a directory busy. If the argument is an existing file or directory,
18*716fd348SMartin Matuska  * simply open it directly and pause. If not, verify that the parent directory
19*716fd348SMartin Matuska  * exists, and create a new file in that directory.
20*716fd348SMartin Matuska  */
21*716fd348SMartin Matuska 
22*716fd348SMartin Matuska #include <stdio.h>
23*716fd348SMartin Matuska #include <sys/types.h>
24*716fd348SMartin Matuska #include <sys/stat.h>
25*716fd348SMartin Matuska #include <fcntl.h>
26*716fd348SMartin Matuska #include <dirent.h>
27*716fd348SMartin Matuska #include <string.h>
28*716fd348SMartin Matuska #include <stdlib.h>
29*716fd348SMartin Matuska #include <unistd.h>
30*716fd348SMartin Matuska #include <errno.h>
31*716fd348SMartin Matuska #include <string.h>
32*716fd348SMartin Matuska 
33*716fd348SMartin Matuska 
34*716fd348SMartin Matuska static __attribute__((noreturn)) void
35*716fd348SMartin Matuska usage(char *progname)
36*716fd348SMartin Matuska {
37*716fd348SMartin Matuska 	(void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname);
38*716fd348SMartin Matuska 	exit(1);
39*716fd348SMartin Matuska }
40*716fd348SMartin Matuska 
41*716fd348SMartin Matuska static __attribute__((noreturn)) void
42*716fd348SMartin Matuska fail(char *err)
43*716fd348SMartin Matuska {
44*716fd348SMartin Matuska 	perror(err);
45*716fd348SMartin Matuska 	exit(1);
46*716fd348SMartin Matuska }
47*716fd348SMartin Matuska 
48*716fd348SMartin Matuska static void
49*716fd348SMartin Matuska daemonize(void)
50*716fd348SMartin Matuska {
51*716fd348SMartin Matuska 	pid_t	pid;
52*716fd348SMartin Matuska 
53*716fd348SMartin Matuska 	if ((pid = fork()) < 0) {
54*716fd348SMartin Matuska 		fail("fork");
55*716fd348SMartin Matuska 	} else if (pid != 0) {
56*716fd348SMartin Matuska 		(void) fprintf(stdout, "%ld\n", (long)pid);
57*716fd348SMartin Matuska 		exit(0);
58*716fd348SMartin Matuska 	}
59*716fd348SMartin Matuska 
60*716fd348SMartin Matuska 	(void) setsid();
61*716fd348SMartin Matuska 	(void) close(0);
62*716fd348SMartin Matuska 	(void) close(1);
63*716fd348SMartin Matuska 	(void) close(2);
64*716fd348SMartin Matuska }
65*716fd348SMartin Matuska 
66*716fd348SMartin Matuska 
67*716fd348SMartin Matuska static const char *
68*716fd348SMartin Matuska get_basename(const char *path)
69*716fd348SMartin Matuska {
70*716fd348SMartin Matuska 	const char *bn = strrchr(path, '/');
71*716fd348SMartin Matuska 	return (bn ? bn + 1 : path);
72*716fd348SMartin Matuska }
73*716fd348SMartin Matuska 
74*716fd348SMartin Matuska static ssize_t
75*716fd348SMartin Matuska get_dirnamelen(const char *path)
76*716fd348SMartin Matuska {
77*716fd348SMartin Matuska 	const char *end = strrchr(path, '/');
78*716fd348SMartin Matuska 	return (end ? end - path : -1);
79*716fd348SMartin Matuska }
80*716fd348SMartin Matuska 
81*716fd348SMartin Matuska int
82*716fd348SMartin Matuska main(int argc, char *argv[])
83*716fd348SMartin Matuska {
84*716fd348SMartin Matuska 	int		c;
85*716fd348SMartin Matuska 	boolean_t	isdir = B_FALSE;
86*716fd348SMartin Matuska 	struct stat	sbuf;
87*716fd348SMartin Matuska 	char		*fpath = NULL;
88*716fd348SMartin Matuska 	char		*prog = argv[0];
89*716fd348SMartin Matuska 
90*716fd348SMartin Matuska 	while ((c = getopt(argc, argv, "")) != -1) {
91*716fd348SMartin Matuska 		switch (c) {
92*716fd348SMartin Matuska 		default:
93*716fd348SMartin Matuska 			usage(prog);
94*716fd348SMartin Matuska 		}
95*716fd348SMartin Matuska 	}
96*716fd348SMartin Matuska 
97*716fd348SMartin Matuska 	argc -= optind;
98*716fd348SMartin Matuska 	argv += optind;
99*716fd348SMartin Matuska 
100*716fd348SMartin Matuska 	if (argc != 1)
101*716fd348SMartin Matuska 		usage(prog);
102*716fd348SMartin Matuska 
103*716fd348SMartin Matuska 	if (stat(argv[0], &sbuf) != 0) {
104*716fd348SMartin Matuska 		char	*arg;
105*716fd348SMartin Matuska 		const char	*dname, *fname;
106*716fd348SMartin Matuska 		size_t	arglen;
107*716fd348SMartin Matuska 		ssize_t	dnamelen;
108*716fd348SMartin Matuska 
109*716fd348SMartin Matuska 		/*
110*716fd348SMartin Matuska 		 * The argument supplied doesn't exist. Copy the path, and
111*716fd348SMartin Matuska 		 * remove the trailing slash if present.
112*716fd348SMartin Matuska 		 */
113*716fd348SMartin Matuska 		if ((arg = strdup(argv[0])) == NULL)
114*716fd348SMartin Matuska 			fail("strdup");
115*716fd348SMartin Matuska 		arglen = strlen(arg);
116*716fd348SMartin Matuska 		if (arg[arglen - 1] == '/')
117*716fd348SMartin Matuska 			arg[arglen - 1] = '\0';
118*716fd348SMartin Matuska 
119*716fd348SMartin Matuska 		/* Get the directory and file names. */
120*716fd348SMartin Matuska 		fname = get_basename(arg);
121*716fd348SMartin Matuska 		dname = arg;
122*716fd348SMartin Matuska 		if ((dnamelen = get_dirnamelen(arg)) != -1)
123*716fd348SMartin Matuska 			arg[dnamelen] = '\0';
124*716fd348SMartin Matuska 		else
125*716fd348SMartin Matuska 			dname = ".";
126*716fd348SMartin Matuska 
127*716fd348SMartin Matuska 		/* The directory portion of the path must exist */
128*716fd348SMartin Matuska 		if (stat(dname, &sbuf) != 0 || !(sbuf.st_mode & S_IFDIR))
129*716fd348SMartin Matuska 			usage(prog);
130*716fd348SMartin Matuska 
131*716fd348SMartin Matuska 		if (asprintf(&fpath, "%s/%s", dname, fname) == -1)
132*716fd348SMartin Matuska 			fail("asprintf");
133*716fd348SMartin Matuska 
134*716fd348SMartin Matuska 		free(arg);
135*716fd348SMartin Matuska 	} else
136*716fd348SMartin Matuska 		switch (sbuf.st_mode & S_IFMT) {
137*716fd348SMartin Matuska 			case S_IFDIR:
138*716fd348SMartin Matuska 				isdir = B_TRUE;
139*716fd348SMartin Matuska 				zfs_fallthrough;
140*716fd348SMartin Matuska 			case S_IFLNK:
141*716fd348SMartin Matuska 			case S_IFCHR:
142*716fd348SMartin Matuska 			case S_IFBLK:
143*716fd348SMartin Matuska 				if ((fpath = strdup(argv[0])) == NULL)
144*716fd348SMartin Matuska 					fail("strdup");
145*716fd348SMartin Matuska 				break;
146*716fd348SMartin Matuska 			default:
147*716fd348SMartin Matuska 				usage(prog);
148*716fd348SMartin Matuska 		}
149*716fd348SMartin Matuska 
150*716fd348SMartin Matuska 	if (!isdir) {
151*716fd348SMartin Matuska 		int	fd;
152*716fd348SMartin Matuska 
153*716fd348SMartin Matuska 		if ((fd = open(fpath, O_CREAT | O_RDWR, 0600)) < 0)
154*716fd348SMartin Matuska 			fail("open");
155*716fd348SMartin Matuska 	} else {
156*716fd348SMartin Matuska 		DIR	*dp;
157*716fd348SMartin Matuska 
158*716fd348SMartin Matuska 		if ((dp = opendir(fpath)) == NULL)
159*716fd348SMartin Matuska 			fail("opendir");
160*716fd348SMartin Matuska 	}
161*716fd348SMartin Matuska 	free(fpath);
162*716fd348SMartin Matuska 
163*716fd348SMartin Matuska 	daemonize();
164*716fd348SMartin Matuska 	(void) pause();
165*716fd348SMartin Matuska 
166*716fd348SMartin Matuska 	return (0);
167*716fd348SMartin Matuska }
168