#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/loadable_fs.h>
#include <fcntl.h>
#include <sys/time.h>
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitrationPrivate.h>
#include "ui.h"
#define COOKIE_FILE "/var/run/nofsalertcookie"
#define ALERT_INTERVAL 3600
const char *progname;
static void
usage(void)
{
fprintf(stderr, "usage: %s -p device\n", progname);
exit(FSUR_INVAL);
}
static void
suppress_mount(char *devname)
{
DASessionRef session =(DASessionRef) 0;
DADiskRef disk = (DADiskRef)0;
session = DASessionCreate(kCFAllocatorDefault);
if (session == (DASessionRef)0)
goto exit;
disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, devname);
if (disk == (DADiskRef)0)
goto exit;
DADiskSetOptions(disk, kDADiskOptionMountAutomatic, FALSE);
exit:
if (disk)
CFRelease(disk);
if (session)
CFRelease(session);
}
static void
display_alert()
{
int fd, ret, err;
struct stat st;
struct timeval tv;
time_t last;
time_t now;
top:
fd = open(COOKIE_FILE, O_CREAT|O_EXCL|O_WRONLY, 0644);
if (fd == -1) {
err = errno;
if (err != EEXIST) {
goto out;
}
ret = lstat(COOKIE_FILE, &st);
if (ret == -1) {
goto out;
}
ret = gettimeofday(&tv, 0);
if (ret == -1) {
goto out;
}
now = tv.tv_sec;
last = st.st_mtimespec.tv_sec;
if (((st.st_mode & S_IFMT) != S_IFREG) || last > now) {
ret = remove(COOKIE_FILE);
if (ret == -1) {
goto out;
} else {
goto top;
}
}
if ((now - last) < ALERT_INTERVAL) {
goto out;
}
} else {
close(fd);
}
AlertZFSNotInstalled();
ret = utimes(COOKIE_FILE, NULL);
out:
return;
}
static void
print_fsname()
{
char cstr[1024];
CFStringRef str;
str = CFCopyLocalizedString(CFSTR("ZFS File System"), "ZFS File System");
CFStringGetCString(str, cstr, 1024, kCFStringEncodingUTF8);
(void) fprintf(stdout, "%s", cstr);
fflush(stdout);
if (str)
CFRelease(str);
}
int
get_zfs_version()
{
int ret = 0;
CFURLRef zfs_url = NULL;
CFBundleRef zfs_bundle = NULL;
CFStringRef vers_str = NULL;
char vers_cstr[256];
unsigned long major_vers;
zfs_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
CFSTR("/System/Library/Filesystems/zfs.fs"),
kCFURLPOSIXPathStyle,
true);
if (zfs_url == NULL) {
ret = 0;
goto out;
}
zfs_bundle = CFBundleCreate(NULL, zfs_url);
if (zfs_bundle == NULL) {
ret = 0;
goto out;
}
vers_str = CFBundleGetValueForInfoDictionaryKey(zfs_bundle, kCFBundleVersionKey);
CFStringGetCString(vers_str, vers_cstr, sizeof(vers_cstr), kCFStringEncodingUTF8);
major_vers = strtol(vers_cstr, NULL, 10);
ret = major_vers;
out:
if (zfs_url)
CFRelease(zfs_url);
if (zfs_bundle)
CFRelease(zfs_bundle);
return ret;
}
int
main(int argc, char **argv)
{
char what;
char *devname;
int ret = FSUR_UNRECOGNIZED;
progname = argv[0];
argc--;
argv++;
if (argc < 2 || argv[0][0] != '-') {
usage();
}
what = argv[0][1];
devname = argv[1];
switch (what) {
case FSUC_PROBE:
if (get_zfs_version() < 9) {
ret = FSUR_RECOGNIZED;
print_fsname();
suppress_mount(devname);
display_alert();
}
break;
default:
usage();
}
return ret;
}