184 lines
3.8 KiB
C
184 lines
3.8 KiB
C
|
/*
|
||
|
* 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 <stdio.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <dirent.h>
|
||
|
#include <strings.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
|
||
|
|
||
|
static void
|
||
|
usage(char *progname)
|
||
|
{
|
||
|
(void) fprintf(stderr, "Usage: %s <dirname|filename>\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);
|
||
|
}
|