]>
Commit | Line | Data |
---|---|---|
6bb24f4d BB |
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 | ||
90f1c3c9 AZ |
33 | |
34 | static __attribute__((noreturn)) void | |
6bb24f4d BB |
35 | usage(char *progname) |
36 | { | |
37 | (void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname); | |
38 | exit(1); | |
39 | } | |
40 | ||
90f1c3c9 AZ |
41 | static __attribute__((noreturn)) void |
42 | fail(char *err) | |
6bb24f4d BB |
43 | { |
44 | perror(err); | |
90f1c3c9 | 45 | exit(1); |
6bb24f4d BB |
46 | } |
47 | ||
48 | static void | |
49 | daemonize(void) | |
50 | { | |
51 | pid_t pid; | |
52 | ||
53 | if ((pid = fork()) < 0) { | |
90f1c3c9 | 54 | fail("fork"); |
6bb24f4d BB |
55 | } else if (pid != 0) { |
56 | (void) fprintf(stdout, "%ld\n", (long)pid); | |
57 | exit(0); | |
58 | } | |
59 | ||
60 | (void) setsid(); | |
61 | (void) close(0); | |
62 | (void) close(1); | |
63 | (void) close(2); | |
64 | } | |
65 | ||
514498fe BB |
66 | |
67 | static const char * | |
68 | get_basename(const char *path) | |
69 | { | |
70 | const char *bn = strrchr(path, '/'); | |
71 | return (bn ? bn + 1 : path); | |
72 | } | |
73 | ||
74 | static ssize_t | |
75 | get_dirnamelen(const char *path) | |
76 | { | |
77 | const char *end = strrchr(path, '/'); | |
78 | return (end ? end - path : -1); | |
79 | } | |
80 | ||
6bb24f4d BB |
81 | int |
82 | main(int argc, char *argv[]) | |
83 | { | |
90f1c3c9 | 84 | int c; |
6bb24f4d | 85 | boolean_t isdir = B_FALSE; |
6bb24f4d BB |
86 | struct stat sbuf; |
87 | char *fpath = NULL; | |
88 | char *prog = argv[0]; | |
89 | ||
90f1c3c9 | 90 | while ((c = getopt(argc, argv, "")) != -1) { |
6bb24f4d | 91 | switch (c) { |
6bb24f4d BB |
92 | default: |
93 | usage(prog); | |
94 | } | |
95 | } | |
96 | ||
97 | argc -= optind; | |
98 | argv += optind; | |
99 | ||
100 | if (argc != 1) | |
101 | usage(prog); | |
102 | ||
90f1c3c9 AZ |
103 | if (stat(argv[0], &sbuf) != 0) { |
104 | char *arg; | |
105 | const char *dname, *fname; | |
106 | size_t arglen; | |
107 | ssize_t dnamelen; | |
6bb24f4d BB |
108 | |
109 | /* | |
110 | * The argument supplied doesn't exist. Copy the path, and | |
dd4bc569 | 111 | * remove the trailing slash if present. |
6bb24f4d BB |
112 | */ |
113 | if ((arg = strdup(argv[0])) == NULL) | |
90f1c3c9 | 114 | fail("strdup"); |
6bb24f4d BB |
115 | arglen = strlen(arg); |
116 | if (arg[arglen - 1] == '/') | |
117 | arg[arglen - 1] = '\0'; | |
118 | ||
90f1c3c9 | 119 | /* Get the directory and file names. */ |
514498fe | 120 | fname = get_basename(arg); |
90f1c3c9 | 121 | dname = arg; |
514498fe | 122 | if ((dnamelen = get_dirnamelen(arg)) != -1) |
90f1c3c9 AZ |
123 | arg[dnamelen] = '\0'; |
124 | else | |
125 | dname = "."; | |
6bb24f4d BB |
126 | |
127 | /* The directory portion of the path must exist */ | |
90f1c3c9 | 128 | if (stat(dname, &sbuf) != 0 || !(sbuf.st_mode & S_IFDIR)) |
6bb24f4d BB |
129 | usage(prog); |
130 | ||
90f1c3c9 AZ |
131 | if (asprintf(&fpath, "%s/%s", dname, fname) == -1) |
132 | fail("asprintf"); | |
6bb24f4d | 133 | |
90f1c3c9 AZ |
134 | free(arg); |
135 | } else | |
136 | switch (sbuf.st_mode & S_IFMT) { | |
137 | case S_IFDIR: | |
138 | isdir = B_TRUE; | |
9a70e97f | 139 | zfs_fallthrough; |
90f1c3c9 AZ |
140 | case S_IFLNK: |
141 | case S_IFCHR: | |
142 | case S_IFBLK: | |
143 | if ((fpath = strdup(argv[0])) == NULL) | |
144 | fail("strdup"); | |
145 | break; | |
146 | default: | |
147 | usage(prog); | |
148 | } | |
6bb24f4d | 149 | |
90f1c3c9 AZ |
150 | if (!isdir) { |
151 | int fd; | |
6bb24f4d | 152 | |
90f1c3c9 AZ |
153 | if ((fd = open(fpath, O_CREAT | O_RDWR, 0600)) < 0) |
154 | fail("open"); | |
6bb24f4d BB |
155 | } else { |
156 | DIR *dp; | |
157 | ||
158 | if ((dp = opendir(fpath)) == NULL) | |
90f1c3c9 | 159 | fail("opendir"); |
6bb24f4d BB |
160 | } |
161 | free(fpath); | |
162 | ||
90f1c3c9 | 163 | daemonize(); |
6bb24f4d BB |
164 | (void) pause(); |
165 | ||
6bb24f4d BB |
166 | return (0); |
167 | } |