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