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