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
usage(char * progname)33 usage(char *progname)
34 {
35 (void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname);
36 exit(1);
37 }
38
39 static void
fail(char * err,int rval)40 fail(char *err, int rval)
41 {
42 perror(err);
43 exit(rval);
44 }
45
46 static void
daemonize(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
main(int argc,char * argv[])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