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