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 32 static void 33 usage(char *progname) 34 { 35 (void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname); 36 exit(1); 37 } 38 39 static void 40 fail(char *err, int rval) 41 { 42 perror(err); 43 exit(rval); 44 } 45 46 static void 47 daemonize(void) 48 { 49 pid_t pid; 50 51 if ((pid = fork()) < 0) { 52 fail("fork", 1); 53 } else if (pid != 0) { 54 (void) fprintf(stdout, "%ld\n", pid); 55 exit(0); 56 } 57 58 (void) setsid(); 59 (void) close(0); 60 (void) close(1); 61 (void) close(2); 62 } 63 64 int 65 main(int argc, char *argv[]) 66 { 67 int ret, c; 68 boolean_t isdir = B_FALSE; 69 boolean_t fflag = B_FALSE; 70 boolean_t rflag = B_FALSE; 71 struct stat sbuf; 72 char *fpath = NULL; 73 char *prog = argv[0]; 74 75 while ((c = getopt(argc, argv, "fr")) != -1) { 76 switch (c) { 77 /* Open the file or directory read only */ 78 case 'r': 79 rflag = B_TRUE; 80 break; 81 /* Run in the foreground */ 82 case 'f': 83 fflag = B_TRUE; 84 break; 85 default: 86 usage(prog); 87 } 88 } 89 90 argc -= optind; 91 argv += optind; 92 93 if (argc != 1) 94 usage(prog); 95 96 if ((ret = stat(argv[0], &sbuf)) != 0) { 97 char *arg, *dname, *fname; 98 int arglen, dlen, flen; 99 char *slash; 100 101 /* 102 * The argument supplied doesn't exist. Copy the path, and 103 * remove the trailing slash if presnt. 104 */ 105 if ((arg = strdup(argv[0])) == NULL) 106 fail("strdup", 1); 107 arglen = strlen(arg); 108 if (arg[arglen - 1] == '/') 109 arg[arglen - 1] = '\0'; 110 111 /* 112 * Get the directory and file names, using the current directory 113 * if the provided path doesn't specify a directory at all. 114 */ 115 if ((slash = strrchr(arg, '/')) == NULL) { 116 dname = strdup("."); 117 fname = strdup(arg); 118 } else { 119 *slash = '\0'; 120 dname = strdup(arg); 121 fname = strdup(slash + 1); 122 } 123 free(arg); 124 if (dname == NULL || fname == NULL) 125 fail("strdup", 1); 126 dlen = strlen(dname); 127 flen = strlen(fname); 128 129 /* The directory portion of the path must exist */ 130 if ((ret = stat(dname, &sbuf)) != 0 || !(sbuf.st_mode & 131 S_IFDIR)) 132 usage(prog); 133 134 if ((fpath = (char *)malloc(dlen + 1 + flen + 1)) == NULL) 135 fail("malloc", 1); 136 (void) memset(fpath, '\0', dlen + 1 + flen + 1); 137 138 (void) strncpy(fpath, dname, dlen); 139 fpath[dlen] = '/'; 140 (void) strncat(fpath, fname, flen); 141 free(dname); 142 free(fname); 143 } else if ((sbuf.st_mode & S_IFMT) == S_IFREG || 144 (sbuf.st_mode & S_IFMT) == S_IFLNK || 145 (sbuf.st_mode & S_IFMT) == S_IFCHR || 146 (sbuf.st_mode & S_IFMT) == S_IFBLK) { 147 fpath = strdup(argv[0]); 148 } else if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { 149 fpath = strdup(argv[0]); 150 isdir = B_TRUE; 151 } else { 152 usage(prog); 153 } 154 155 if (fpath == NULL) 156 fail("strdup", 1); 157 158 if (isdir == B_FALSE) { 159 int fd, flags; 160 mode_t mode = S_IRUSR | S_IWUSR; 161 162 flags = rflag == B_FALSE ? O_CREAT | O_RDWR : O_RDONLY; 163 164 if ((fd = open(fpath, flags, mode)) < 0) 165 fail("open", 1); 166 } else { 167 DIR *dp; 168 169 if ((dp = opendir(fpath)) == NULL) 170 fail("opendir", 1); 171 } 172 free(fpath); 173 174 if (fflag == B_FALSE) 175 daemonize(); 176 (void) pause(); 177 178 /* NOTREACHED */ 179 return (0); 180 } 181