/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2012 by Delphix. All rights reserved. */ /* * Make a directory busy. If the argument is an existing file or directory, * simply open it directly and pause. If not, verify that the parent directory * exists, and create a new file in that directory. */ #include #include #include #include #include #include #include #include #include #include typedef enum boolean { B_FALSE, B_TRUE } boolean_t; static void usage(char *progname) { (void) fprintf(stderr, "Usage: %s \n", progname); exit(1); } static void fail(char *err, int rval) { perror(err); exit(rval); } static void daemonize(void) { pid_t pid; if ((pid = fork()) < 0) { fail("fork", 1); } else if (pid != 0) { (void) fprintf(stdout, "%ld\n", (long)pid); exit(0); } (void) setsid(); (void) close(0); (void) close(1); (void) close(2); } int main(int argc, char *argv[]) { int ret, c; boolean_t isdir = B_FALSE; boolean_t fflag = B_FALSE; boolean_t rflag = B_FALSE; struct stat sbuf; char *fpath = NULL; char *prog = argv[0]; while ((c = getopt(argc, argv, "fr")) != -1) { switch (c) { /* Open the file or directory read only */ case 'r': rflag = B_TRUE; break; /* Run in the foreground */ case 'f': fflag = B_TRUE; break; default: usage(prog); } } argc -= optind; argv += optind; if (argc != 1) usage(prog); if ((ret = stat(argv[0], &sbuf)) != 0) { char *arg, *dname, *fname; int arglen, dlen, flen; char *slash; /* * The argument supplied doesn't exist. Copy the path, and * remove the trailing slash if presnt. */ if ((arg = strdup(argv[0])) == NULL) fail("strdup", 1); arglen = strlen(arg); if (arg[arglen - 1] == '/') arg[arglen - 1] = '\0'; /* * Get the directory and file names, using the current directory * if the provided path doesn't specify a directory at all. */ if ((slash = strrchr(arg, '/')) == NULL) { dname = strdup("."); fname = strdup(arg); } else { *slash = '\0'; dname = strdup(arg); fname = strdup(slash + 1); } free(arg); if (dname == NULL || fname == NULL) fail("strdup", 1); dlen = strlen(dname); flen = strlen(fname); /* The directory portion of the path must exist */ if ((ret = stat(dname, &sbuf)) != 0 || !(sbuf.st_mode & S_IFDIR)) usage(prog); if ((fpath = (char *)malloc(dlen + 1 + flen + 1)) == NULL) fail("malloc", 1); (void) memset(fpath, '\0', dlen + 1 + flen + 1); (void) strncpy(fpath, dname, dlen); fpath[dlen] = '/'; (void) strncat(fpath, fname, flen); free(dname); free(fname); } else if ((sbuf.st_mode & S_IFMT) == S_IFREG || (sbuf.st_mode & S_IFMT) == S_IFLNK || (sbuf.st_mode & S_IFMT) == S_IFCHR || (sbuf.st_mode & S_IFMT) == S_IFBLK) { fpath = strdup(argv[0]); } else if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { fpath = strdup(argv[0]); isdir = B_TRUE; } else { usage(prog); } if (fpath == NULL) fail("strdup", 1); if (isdir == B_FALSE) { int fd, flags; mode_t mode = S_IRUSR | S_IWUSR; flags = rflag == B_FALSE ? O_CREAT | O_RDWR : O_RDONLY; if ((fd = open(fpath, flags, mode)) < 0) fail("open", 1); } else { DIR *dp; if ((dp = opendir(fpath)) == NULL) fail("opendir", 1); } free(fpath); if (fflag == B_FALSE) daemonize(); (void) pause(); /* NOTREACHED */ return (0); }