xref: /freebsd-src/sys/contrib/openzfs/tests/zfs-tests/cmd/mkbusy.c (revision dbd5678dca91abcefe8d046aa2f9b66497a95ffb)
1716fd348SMartin Matuska /*
2716fd348SMartin Matuska  * This file and its contents are supplied under the terms of the
3716fd348SMartin Matuska  * Common Development and Distribution License ("CDDL"), version 1.0.
4716fd348SMartin Matuska  * You may only use this file in accordance with the terms of version
5716fd348SMartin Matuska  * 1.0 of the CDDL.
6716fd348SMartin Matuska  *
7716fd348SMartin Matuska  * A full copy of the text of the CDDL should have accompanied this
8716fd348SMartin Matuska  * source.  A copy of the CDDL is also available via the Internet at
9716fd348SMartin Matuska  * http://www.illumos.org/license/CDDL.
10716fd348SMartin Matuska  */
11716fd348SMartin Matuska 
12716fd348SMartin Matuska /*
13716fd348SMartin Matuska  * Copyright (c) 2012 by Delphix. All rights reserved.
14716fd348SMartin Matuska  */
15716fd348SMartin Matuska 
16716fd348SMartin Matuska /*
17716fd348SMartin Matuska  * Make a directory busy. If the argument is an existing file or directory,
18716fd348SMartin Matuska  * simply open it directly and pause. If not, verify that the parent directory
19716fd348SMartin Matuska  * exists, and create a new file in that directory.
20716fd348SMartin Matuska  */
21716fd348SMartin Matuska 
22716fd348SMartin Matuska #include <stdio.h>
23716fd348SMartin Matuska #include <sys/types.h>
24716fd348SMartin Matuska #include <sys/stat.h>
25716fd348SMartin Matuska #include <fcntl.h>
26716fd348SMartin Matuska #include <dirent.h>
27716fd348SMartin Matuska #include <string.h>
28716fd348SMartin Matuska #include <stdlib.h>
29716fd348SMartin Matuska #include <unistd.h>
30716fd348SMartin Matuska #include <errno.h>
31716fd348SMartin Matuska #include <string.h>
32716fd348SMartin Matuska 
33716fd348SMartin Matuska 
34716fd348SMartin Matuska static __attribute__((noreturn)) void
usage(const char * progname)35a0b956f5SMartin Matuska usage(const char *progname)
36716fd348SMartin Matuska {
37716fd348SMartin Matuska 	(void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname);
38716fd348SMartin Matuska 	exit(1);
39716fd348SMartin Matuska }
40716fd348SMartin Matuska 
41716fd348SMartin Matuska static __attribute__((noreturn)) void
fail(const char * err)42a0b956f5SMartin Matuska fail(const char *err)
43716fd348SMartin Matuska {
44716fd348SMartin Matuska 	perror(err);
45716fd348SMartin Matuska 	exit(1);
46716fd348SMartin Matuska }
47716fd348SMartin Matuska 
48716fd348SMartin Matuska static void
daemonize(void)49716fd348SMartin Matuska daemonize(void)
50716fd348SMartin Matuska {
51716fd348SMartin Matuska 	pid_t	pid;
52716fd348SMartin Matuska 
53716fd348SMartin Matuska 	if ((pid = fork()) < 0) {
54716fd348SMartin Matuska 		fail("fork");
55716fd348SMartin Matuska 	} else if (pid != 0) {
56716fd348SMartin Matuska 		(void) fprintf(stdout, "%ld\n", (long)pid);
57716fd348SMartin Matuska 		exit(0);
58716fd348SMartin Matuska 	}
59716fd348SMartin Matuska 
60716fd348SMartin Matuska 	(void) setsid();
61716fd348SMartin Matuska 	(void) close(0);
62716fd348SMartin Matuska 	(void) close(1);
63716fd348SMartin Matuska 	(void) close(2);
64716fd348SMartin Matuska }
65716fd348SMartin Matuska 
66716fd348SMartin Matuska 
67716fd348SMartin Matuska static const char *
get_basename(const char * path)68716fd348SMartin Matuska get_basename(const char *path)
69716fd348SMartin Matuska {
70716fd348SMartin Matuska 	const char *bn = strrchr(path, '/');
71716fd348SMartin Matuska 	return (bn ? bn + 1 : path);
72716fd348SMartin Matuska }
73716fd348SMartin Matuska 
74716fd348SMartin Matuska static ssize_t
get_dirnamelen(const char * path)75716fd348SMartin Matuska get_dirnamelen(const char *path)
76716fd348SMartin Matuska {
77716fd348SMartin Matuska 	const char *end = strrchr(path, '/');
78716fd348SMartin Matuska 	return (end ? end - path : -1);
79716fd348SMartin Matuska }
80716fd348SMartin Matuska 
81716fd348SMartin Matuska int
main(int argc,char * argv[])82716fd348SMartin Matuska main(int argc, char *argv[])
83716fd348SMartin Matuska {
84716fd348SMartin Matuska 	int		c;
85716fd348SMartin Matuska 	boolean_t	isdir = B_FALSE;
86716fd348SMartin Matuska 	struct stat	sbuf;
87716fd348SMartin Matuska 	char		*fpath = NULL;
88716fd348SMartin Matuska 	char		*prog = argv[0];
89716fd348SMartin Matuska 
90716fd348SMartin Matuska 	while ((c = getopt(argc, argv, "")) != -1) {
91716fd348SMartin Matuska 		switch (c) {
92716fd348SMartin Matuska 		default:
93716fd348SMartin Matuska 			usage(prog);
94716fd348SMartin Matuska 		}
95716fd348SMartin Matuska 	}
96716fd348SMartin Matuska 
97716fd348SMartin Matuska 	argc -= optind;
98716fd348SMartin Matuska 	argv += optind;
99716fd348SMartin Matuska 
100716fd348SMartin Matuska 	if (argc != 1)
101716fd348SMartin Matuska 		usage(prog);
102716fd348SMartin Matuska 
103716fd348SMartin Matuska 	if (stat(argv[0], &sbuf) != 0) {
104716fd348SMartin Matuska 		char	*arg;
105716fd348SMartin Matuska 		const char	*dname, *fname;
106716fd348SMartin Matuska 		size_t	arglen;
107716fd348SMartin Matuska 		ssize_t	dnamelen;
108716fd348SMartin Matuska 
109716fd348SMartin Matuska 		/*
110716fd348SMartin Matuska 		 * The argument supplied doesn't exist. Copy the path, and
111716fd348SMartin Matuska 		 * remove the trailing slash if present.
112716fd348SMartin Matuska 		 */
113716fd348SMartin Matuska 		if ((arg = strdup(argv[0])) == NULL)
114716fd348SMartin Matuska 			fail("strdup");
115716fd348SMartin Matuska 		arglen = strlen(arg);
116716fd348SMartin Matuska 		if (arg[arglen - 1] == '/')
117716fd348SMartin Matuska 			arg[arglen - 1] = '\0';
118716fd348SMartin Matuska 
119716fd348SMartin Matuska 		/* Get the directory and file names. */
120716fd348SMartin Matuska 		fname = get_basename(arg);
121716fd348SMartin Matuska 		dname = arg;
122716fd348SMartin Matuska 		if ((dnamelen = get_dirnamelen(arg)) != -1)
123716fd348SMartin Matuska 			arg[dnamelen] = '\0';
124716fd348SMartin Matuska 		else
125716fd348SMartin Matuska 			dname = ".";
126716fd348SMartin Matuska 
127716fd348SMartin Matuska 		/* The directory portion of the path must exist */
128716fd348SMartin Matuska 		if (stat(dname, &sbuf) != 0 || !(sbuf.st_mode & S_IFDIR))
129716fd348SMartin Matuska 			usage(prog);
130716fd348SMartin Matuska 
131716fd348SMartin Matuska 		if (asprintf(&fpath, "%s/%s", dname, fname) == -1)
132716fd348SMartin Matuska 			fail("asprintf");
133716fd348SMartin Matuska 
134716fd348SMartin Matuska 		free(arg);
135716fd348SMartin Matuska 	} else
136716fd348SMartin Matuska 		switch (sbuf.st_mode & S_IFMT) {
137716fd348SMartin Matuska 			case S_IFDIR:
138716fd348SMartin Matuska 				isdir = B_TRUE;
139716fd348SMartin Matuska 				zfs_fallthrough;
140716fd348SMartin Matuska 			case S_IFLNK:
141716fd348SMartin Matuska 			case S_IFCHR:
142716fd348SMartin Matuska 			case S_IFBLK:
143716fd348SMartin Matuska 				if ((fpath = strdup(argv[0])) == NULL)
144716fd348SMartin Matuska 					fail("strdup");
145716fd348SMartin Matuska 				break;
146716fd348SMartin Matuska 			default:
147716fd348SMartin Matuska 				usage(prog);
148716fd348SMartin Matuska 		}
149716fd348SMartin Matuska 
150716fd348SMartin Matuska 	if (!isdir) {
151*dbd5678dSMartin Matuska 		if (open(fpath, O_CREAT | O_RDWR, 0600) < 0)
152716fd348SMartin Matuska 			fail("open");
153716fd348SMartin Matuska 	} else {
154*dbd5678dSMartin Matuska 		if (opendir(fpath) == NULL)
155716fd348SMartin Matuska 			fail("opendir");
156716fd348SMartin Matuska 	}
157716fd348SMartin Matuska 	free(fpath);
158716fd348SMartin Matuska 
159716fd348SMartin Matuska 	daemonize();
160716fd348SMartin Matuska 	(void) pause();
161716fd348SMartin Matuska 
162716fd348SMartin Matuska 	return (0);
163716fd348SMartin Matuska }
164