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