]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/zfs-tests/cmd/mkbusy/mkbusy.c
Vendor import of openzfs master @ 184df27eef0abdc7ab2105b21257f753834b936b
[FreeBSD/FreeBSD.git] / tests / zfs-tests / cmd / mkbusy / mkbusy.c
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 #include <string.h>
32
33 static void
34 usage(char *progname)
35 {
36         (void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname);
37         exit(1);
38 }
39
40 static void
41 fail(char *err, int rval)
42 {
43         perror(err);
44         exit(rval);
45 }
46
47 static void
48 daemonize(void)
49 {
50         pid_t   pid;
51
52         if ((pid = fork()) < 0) {
53                 fail("fork", 1);
54         } else if (pid != 0) {
55                 (void) fprintf(stdout, "%ld\n", (long)pid);
56                 exit(0);
57         }
58
59         (void) setsid();
60         (void) close(0);
61         (void) close(1);
62         (void) close(2);
63 }
64
65 int
66 main(int argc, char *argv[])
67 {
68         int             ret, c;
69         boolean_t       isdir = B_FALSE;
70         boolean_t       fflag = B_FALSE;
71         boolean_t       rflag = B_FALSE;
72         struct stat     sbuf;
73         char            *fpath = NULL;
74         char            *prog = argv[0];
75
76         while ((c = getopt(argc, argv, "fr")) != -1) {
77                 switch (c) {
78                 /* Open the file or directory read only */
79                 case 'r':
80                         rflag = B_TRUE;
81                         break;
82                 /* Run in the foreground */
83                 case 'f':
84                         fflag = B_TRUE;
85                         break;
86                 default:
87                         usage(prog);
88                 }
89         }
90
91         argc -= optind;
92         argv += optind;
93
94         if (argc != 1)
95                 usage(prog);
96
97         if ((ret = stat(argv[0], &sbuf)) != 0) {
98                 char    *arg, *dname, *fname;
99                 int     arglen;
100                 char    *slash;
101                 int     rc;
102
103                 /*
104                  * The argument supplied doesn't exist. Copy the path, and
105                  * remove the trailing slash if present.
106                  */
107                 if ((arg = strdup(argv[0])) == NULL)
108                         fail("strdup", 1);
109                 arglen = strlen(arg);
110                 if (arg[arglen - 1] == '/')
111                         arg[arglen - 1] = '\0';
112
113                 /*
114                  * Get the directory and file names, using the current directory
115                  * if the provided path doesn't specify a directory at all.
116                  */
117                 if ((slash = strrchr(arg, '/')) == NULL) {
118                         dname = strdup(".");
119                         fname = strdup(arg);
120                 } else {
121                         *slash = '\0';
122                         dname = strdup(arg);
123                         fname = strdup(slash + 1);
124                 }
125                 free(arg);
126                 if (dname == NULL || fname == NULL)
127                         fail("strdup", 1);
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                 rc = asprintf(&fpath, "%s/%s", dname, fname);
135                 free(dname);
136                 free(fname);
137                 if (rc == -1 || fpath == NULL)
138                         fail("asprintf", 1);
139
140         } else if ((sbuf.st_mode & S_IFMT) == S_IFREG ||
141             (sbuf.st_mode & S_IFMT) == S_IFLNK ||
142             (sbuf.st_mode & S_IFMT) == S_IFCHR ||
143             (sbuf.st_mode & S_IFMT) == S_IFBLK) {
144                 fpath = strdup(argv[0]);
145         } else if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
146                 fpath = strdup(argv[0]);
147                 isdir = B_TRUE;
148         } else {
149                 usage(prog);
150         }
151
152         if (fpath == NULL)
153                 fail("strdup", 1);
154
155         if (isdir == B_FALSE) {
156                 int     fd, flags;
157                 mode_t  mode = S_IRUSR | S_IWUSR;
158
159                 flags = rflag == B_FALSE ? O_CREAT | O_RDWR : O_RDONLY;
160
161                 if ((fd = open(fpath, flags, mode)) < 0)
162                         fail("open", 1);
163         } else {
164                 DIR     *dp;
165
166                 if ((dp = opendir(fpath)) == NULL)
167                         fail("opendir", 1);
168         }
169         free(fpath);
170
171         if (fflag == B_FALSE)
172                 daemonize();
173         (void) pause();
174
175         /* NOTREACHED */
176         return (0);
177 }