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 <string.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <errno.h> 31 #include <string.h> 32 33 34 static __attribute__((noreturn)) void 35 usage(const char *progname) 36 { 37 (void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname); 38 exit(1); 39 } 40 41 static __attribute__((noreturn)) void 42 fail(const char *err) 43 { 44 perror(err); 45 exit(1); 46 } 47 48 static void 49 daemonize(void) 50 { 51 pid_t pid; 52 53 if ((pid = fork()) < 0) { 54 fail("fork"); 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 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 81 int 82 main(int argc, char *argv[]) 83 { 84 int c; 85 boolean_t isdir = B_FALSE; 86 struct stat sbuf; 87 char *fpath = NULL; 88 char *prog = argv[0]; 89 90 while ((c = getopt(argc, argv, "")) != -1) { 91 switch (c) { 92 default: 93 usage(prog); 94 } 95 } 96 97 argc -= optind; 98 argv += optind; 99 100 if (argc != 1) 101 usage(prog); 102 103 if (stat(argv[0], &sbuf) != 0) { 104 char *arg; 105 const char *dname, *fname; 106 size_t arglen; 107 ssize_t dnamelen; 108 109 /* 110 * The argument supplied doesn't exist. Copy the path, and 111 * remove the trailing slash if present. 112 */ 113 if ((arg = strdup(argv[0])) == NULL) 114 fail("strdup"); 115 arglen = strlen(arg); 116 if (arg[arglen - 1] == '/') 117 arg[arglen - 1] = '\0'; 118 119 /* Get the directory and file names. */ 120 fname = get_basename(arg); 121 dname = arg; 122 if ((dnamelen = get_dirnamelen(arg)) != -1) 123 arg[dnamelen] = '\0'; 124 else 125 dname = "."; 126 127 /* The directory portion of the path must exist */ 128 if (stat(dname, &sbuf) != 0 || !(sbuf.st_mode & S_IFDIR)) 129 usage(prog); 130 131 if (asprintf(&fpath, "%s/%s", dname, fname) == -1) 132 fail("asprintf"); 133 134 free(arg); 135 } else 136 switch (sbuf.st_mode & S_IFMT) { 137 case S_IFDIR: 138 isdir = B_TRUE; 139 zfs_fallthrough; 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 } 149 150 if (!isdir) { 151 if (open(fpath, O_CREAT | O_RDWR, 0600) < 0) 152 fail("open"); 153 } else { 154 if (opendir(fpath) == NULL) 155 fail("opendir"); 156 } 157 free(fpath); 158 159 daemonize(); 160 (void) pause(); 161 162 return (0); 163 } 164