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