1716fd348SMartin Matuska /* 2716fd348SMartin Matuska * This file and its contents are supplied under the terms of the 3716fd348SMartin Matuska * Common Development and Distribution License ("CDDL"), version 1.0. 4716fd348SMartin Matuska * You may only use this file in accordance with the terms of version 5716fd348SMartin Matuska * 1.0 of the CDDL. 6716fd348SMartin Matuska * 7716fd348SMartin Matuska * A full copy of the text of the CDDL should have accompanied this 8716fd348SMartin Matuska * source. A copy of the CDDL is also available via the Internet at 9716fd348SMartin Matuska * http://www.illumos.org/license/CDDL. 10716fd348SMartin Matuska */ 11716fd348SMartin Matuska 12716fd348SMartin Matuska /* 13716fd348SMartin Matuska * Copyright (c) 2012 by Delphix. All rights reserved. 14716fd348SMartin Matuska */ 15716fd348SMartin Matuska 16716fd348SMartin Matuska /* 17716fd348SMartin Matuska * Make a directory busy. If the argument is an existing file or directory, 18716fd348SMartin Matuska * simply open it directly and pause. If not, verify that the parent directory 19716fd348SMartin Matuska * exists, and create a new file in that directory. 20716fd348SMartin Matuska */ 21716fd348SMartin Matuska 22716fd348SMartin Matuska #include <stdio.h> 23716fd348SMartin Matuska #include <sys/types.h> 24716fd348SMartin Matuska #include <sys/stat.h> 25716fd348SMartin Matuska #include <fcntl.h> 26716fd348SMartin Matuska #include <dirent.h> 27716fd348SMartin Matuska #include <string.h> 28716fd348SMartin Matuska #include <stdlib.h> 29716fd348SMartin Matuska #include <unistd.h> 30716fd348SMartin Matuska #include <errno.h> 31716fd348SMartin Matuska #include <string.h> 32716fd348SMartin Matuska 33716fd348SMartin Matuska 34716fd348SMartin Matuska static __attribute__((noreturn)) void 35*a0b956f5SMartin Matuska usage(const char *progname) 36716fd348SMartin Matuska { 37716fd348SMartin Matuska (void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname); 38716fd348SMartin Matuska exit(1); 39716fd348SMartin Matuska } 40716fd348SMartin Matuska 41716fd348SMartin Matuska static __attribute__((noreturn)) void 42*a0b956f5SMartin Matuska fail(const char *err) 43716fd348SMartin Matuska { 44716fd348SMartin Matuska perror(err); 45716fd348SMartin Matuska exit(1); 46716fd348SMartin Matuska } 47716fd348SMartin Matuska 48716fd348SMartin Matuska static void 49716fd348SMartin Matuska daemonize(void) 50716fd348SMartin Matuska { 51716fd348SMartin Matuska pid_t pid; 52716fd348SMartin Matuska 53716fd348SMartin Matuska if ((pid = fork()) < 0) { 54716fd348SMartin Matuska fail("fork"); 55716fd348SMartin Matuska } else if (pid != 0) { 56716fd348SMartin Matuska (void) fprintf(stdout, "%ld\n", (long)pid); 57716fd348SMartin Matuska exit(0); 58716fd348SMartin Matuska } 59716fd348SMartin Matuska 60716fd348SMartin Matuska (void) setsid(); 61716fd348SMartin Matuska (void) close(0); 62716fd348SMartin Matuska (void) close(1); 63716fd348SMartin Matuska (void) close(2); 64716fd348SMartin Matuska } 65716fd348SMartin Matuska 66716fd348SMartin Matuska 67716fd348SMartin Matuska static const char * 68716fd348SMartin Matuska get_basename(const char *path) 69716fd348SMartin Matuska { 70716fd348SMartin Matuska const char *bn = strrchr(path, '/'); 71716fd348SMartin Matuska return (bn ? bn + 1 : path); 72716fd348SMartin Matuska } 73716fd348SMartin Matuska 74716fd348SMartin Matuska static ssize_t 75716fd348SMartin Matuska get_dirnamelen(const char *path) 76716fd348SMartin Matuska { 77716fd348SMartin Matuska const char *end = strrchr(path, '/'); 78716fd348SMartin Matuska return (end ? end - path : -1); 79716fd348SMartin Matuska } 80716fd348SMartin Matuska 81716fd348SMartin Matuska int 82716fd348SMartin Matuska main(int argc, char *argv[]) 83716fd348SMartin Matuska { 84716fd348SMartin Matuska int c; 85716fd348SMartin Matuska boolean_t isdir = B_FALSE; 86716fd348SMartin Matuska struct stat sbuf; 87716fd348SMartin Matuska char *fpath = NULL; 88716fd348SMartin Matuska char *prog = argv[0]; 89716fd348SMartin Matuska 90716fd348SMartin Matuska while ((c = getopt(argc, argv, "")) != -1) { 91716fd348SMartin Matuska switch (c) { 92716fd348SMartin Matuska default: 93716fd348SMartin Matuska usage(prog); 94716fd348SMartin Matuska } 95716fd348SMartin Matuska } 96716fd348SMartin Matuska 97716fd348SMartin Matuska argc -= optind; 98716fd348SMartin Matuska argv += optind; 99716fd348SMartin Matuska 100716fd348SMartin Matuska if (argc != 1) 101716fd348SMartin Matuska usage(prog); 102716fd348SMartin Matuska 103716fd348SMartin Matuska if (stat(argv[0], &sbuf) != 0) { 104716fd348SMartin Matuska char *arg; 105716fd348SMartin Matuska const char *dname, *fname; 106716fd348SMartin Matuska size_t arglen; 107716fd348SMartin Matuska ssize_t dnamelen; 108716fd348SMartin Matuska 109716fd348SMartin Matuska /* 110716fd348SMartin Matuska * The argument supplied doesn't exist. Copy the path, and 111716fd348SMartin Matuska * remove the trailing slash if present. 112716fd348SMartin Matuska */ 113716fd348SMartin Matuska if ((arg = strdup(argv[0])) == NULL) 114716fd348SMartin Matuska fail("strdup"); 115716fd348SMartin Matuska arglen = strlen(arg); 116716fd348SMartin Matuska if (arg[arglen - 1] == '/') 117716fd348SMartin Matuska arg[arglen - 1] = '\0'; 118716fd348SMartin Matuska 119716fd348SMartin Matuska /* Get the directory and file names. */ 120716fd348SMartin Matuska fname = get_basename(arg); 121716fd348SMartin Matuska dname = arg; 122716fd348SMartin Matuska if ((dnamelen = get_dirnamelen(arg)) != -1) 123716fd348SMartin Matuska arg[dnamelen] = '\0'; 124716fd348SMartin Matuska else 125716fd348SMartin Matuska dname = "."; 126716fd348SMartin Matuska 127716fd348SMartin Matuska /* The directory portion of the path must exist */ 128716fd348SMartin Matuska if (stat(dname, &sbuf) != 0 || !(sbuf.st_mode & S_IFDIR)) 129716fd348SMartin Matuska usage(prog); 130716fd348SMartin Matuska 131716fd348SMartin Matuska if (asprintf(&fpath, "%s/%s", dname, fname) == -1) 132716fd348SMartin Matuska fail("asprintf"); 133716fd348SMartin Matuska 134716fd348SMartin Matuska free(arg); 135716fd348SMartin Matuska } else 136716fd348SMartin Matuska switch (sbuf.st_mode & S_IFMT) { 137716fd348SMartin Matuska case S_IFDIR: 138716fd348SMartin Matuska isdir = B_TRUE; 139716fd348SMartin Matuska zfs_fallthrough; 140716fd348SMartin Matuska case S_IFLNK: 141716fd348SMartin Matuska case S_IFCHR: 142716fd348SMartin Matuska case S_IFBLK: 143716fd348SMartin Matuska if ((fpath = strdup(argv[0])) == NULL) 144716fd348SMartin Matuska fail("strdup"); 145716fd348SMartin Matuska break; 146716fd348SMartin Matuska default: 147716fd348SMartin Matuska usage(prog); 148716fd348SMartin Matuska } 149716fd348SMartin Matuska 150716fd348SMartin Matuska if (!isdir) { 151716fd348SMartin Matuska int fd; 152716fd348SMartin Matuska 153716fd348SMartin Matuska if ((fd = open(fpath, O_CREAT | O_RDWR, 0600)) < 0) 154716fd348SMartin Matuska fail("open"); 155716fd348SMartin Matuska } else { 156716fd348SMartin Matuska DIR *dp; 157716fd348SMartin Matuska 158716fd348SMartin Matuska if ((dp = opendir(fpath)) == NULL) 159716fd348SMartin Matuska fail("opendir"); 160716fd348SMartin Matuska } 161716fd348SMartin Matuska free(fpath); 162716fd348SMartin Matuska 163716fd348SMartin Matuska daemonize(); 164716fd348SMartin Matuska (void) pause(); 165716fd348SMartin Matuska 166716fd348SMartin Matuska return (0); 167716fd348SMartin Matuska } 168