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