#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <synch.h>
#include <thread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mnttab.h>
#include <sys/swap.h>
#include "libdiskmgt.h"
#include "disks_private.h"
struct mntpnt_list {
struct mntpnt_list *next;
char *special;
char *mountp;
};
static struct mntpnt_list *mntpoint_listp = NULL;
static rwlock_t mntpoint_lock = DEFAULTRWLOCK;
static int initialized = 0;
static mutex_t init_lock = DEFAULTMUTEX;
static boolean_t diff_mnttab(int send_event, struct mntpnt_list *firstp,
struct mntpnt_list *secondp);
static void free_mnttab(struct mntpnt_list *listp);
static boolean_t in_list(struct mntpnt_list *elementp,
struct mntpnt_list *listp);
static int load_mnttab(int send_event);
static void *watch_mnttab(void *);
int
inuse_mnt(char *slice, nvlist_t *attrs, int *errp)
{
struct mntpnt_list *listp;
int found = 0;
*errp = 0;
if (slice == NULL) {
return (found);
}
(void) mutex_lock(&init_lock);
if (!initialized) {
thread_t mnttab_thread;
*errp = load_mnttab(B_FALSE);
if (*errp == 0) {
*errp = thr_create(NULL, 0, watch_mnttab,
NULL, THR_NEW_LWP | THR_DAEMON, &mnttab_thread);
}
if (*errp == 0) {
initialized = 1;
}
}
(void) mutex_unlock(&init_lock);
(void) rw_rdlock(&mntpoint_lock);
listp = mntpoint_listp;
while (listp != NULL) {
if (libdiskmgt_str_eq(slice, listp->special)) {
libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_MOUNT, errp);
libdiskmgt_add_str(attrs, DM_USED_NAME, listp->mountp, errp);
found = 1;
break;
}
listp = listp->next;
}
(void) rw_unlock(&mntpoint_lock);
return (found);
}
static boolean_t
diff_mnttab(int send_event, struct mntpnt_list *firstp,
struct mntpnt_list *secondp)
{
boolean_t different = B_FALSE;
struct mntpnt_list *listp;
listp = firstp;
while (listp != NULL) {
if (! in_list(listp, secondp)) {
if (send_event) {
events_new_slice_event(listp->special, DM_EV_TCHANGE);
}
different = B_TRUE;
}
listp = listp->next;
}
listp = secondp;
while (listp != NULL) {
if (! in_list(listp, firstp)) {
if (send_event) {
events_new_slice_event(listp->special, DM_EV_TCHANGE);
}
different = B_TRUE;
}
listp = listp->next;
}
return (different);
}
static void
free_mnttab(struct mntpnt_list *listp) {
struct mntpnt_list *nextp;
while (listp != NULL) {
nextp = listp->next;
free((void *)listp->special);
free((void *)listp->mountp);
free((void *)listp);
listp = nextp;
}
}
static boolean_t
in_list(struct mntpnt_list *elementp, struct mntpnt_list *listp)
{
while (listp != NULL) {
if (libdiskmgt_str_eq(elementp->special, listp->special) &&
libdiskmgt_str_eq(elementp->mountp, listp->mountp)) {
return (B_TRUE);
}
listp = listp->next;
}
return (B_FALSE);
}
static int
load_mnttab(int send_event)
{
struct mntpnt_list *currp;
FILE *fp;
struct mntpnt_list *headp;
int num;
struct mntpnt_list *prevp;
struct swaptable *st;
struct swapent *swapent;
int err;
int i;
headp = NULL;
prevp = NULL;
if ((fp = fopen("/etc/mnttab", "r")) != NULL) {
struct mnttab entry;
while (getmntent(fp, &entry) == 0) {
if (entry.mnt_special == NULL ||
entry.mnt_mountp == NULL ||
strncmp(entry.mnt_special, "/dev", 4) != 0) {
continue;
}
currp = (struct mntpnt_list *)calloc((size_t)1,
(size_t)sizeof (struct mntpnt_list));
if (currp == NULL) {
free_mnttab(headp);
(void) fclose(fp);
return (ENOMEM);
}
if (headp == NULL) {
headp = currp;
} else {
prevp->next = currp;
}
currp->next = NULL;
currp->special = strdup(entry.mnt_special);
if (currp->special == NULL) {
free_mnttab(headp);
(void) fclose(fp);
return (ENOMEM);
}
currp->mountp = strdup(entry.mnt_mountp);
if (currp->mountp == NULL) {
free_mnttab(headp);
(void) fclose(fp);
return (ENOMEM);
}
prevp = currp;
}
(void) fclose(fp);
}
num = dm_get_swapentries(&st, &err);
if (num < 0) {
free_mnttab(headp);
return (ENOMEM);
}
for (i = 0, swapent = st->swt_ent; i < num; i++, swapent++) {
char fullpath[MAXPATHLEN+1];
currp = (struct mntpnt_list *)
calloc((size_t)1, (size_t)sizeof (struct mntpnt_list));
if (currp == NULL) {
dm_free_swapentries(st);
free_mnttab(headp);
return (ENOMEM);
}
if (headp == NULL) {
headp = currp;
} else {
prevp->next = currp;
}
currp->next = NULL;
if (*swapent->ste_path != '/') {
(void) snprintf(fullpath, sizeof (fullpath), "/dev/%s",
swapent->ste_path);
} else {
(void) strlcpy(fullpath, swapent->ste_path,
sizeof (fullpath));
}
currp->special = strdup(fullpath);
if (currp->special == NULL) {
dm_free_swapentries(st);
free_mnttab(headp);
return (ENOMEM);
}
currp->mountp = strdup("swap");
if (currp->mountp == NULL) {
dm_free_swapentries(st);
free_mnttab(headp);
return (ENOMEM);
}
prevp = currp;
}
if (num)
dm_free_swapentries(st);
(void) rw_wrlock(&mntpoint_lock);
if (diff_mnttab(send_event, mntpoint_listp, headp) == B_TRUE) {
struct mntpnt_list *tmpp;
tmpp = mntpoint_listp;
mntpoint_listp = headp;
(void) rw_unlock(&mntpoint_lock);
free_mnttab(tmpp);
} else {
(void) rw_unlock(&mntpoint_lock);
free_mnttab(headp);
}
return (0);
}
static void *
watch_mnttab(void *arg __unused)
{
struct pollfd fds[1];
int res;
if ((fds[0].fd = open("/etc/mnttab", O_RDONLY)) != -1) {
char buf[81];
(void) read(fds[0].fd, buf, (size_t)(sizeof (buf) - 1));
(void) lseek(fds[0].fd, 0, SEEK_SET);
fds[0].events = POLLRDBAND;
while (res = poll(fds, (nfds_t)1, -1)) {
if (res <= 0)
continue;
(void) load_mnttab(B_TRUE);
(void) read(fds[0].fd, buf, (size_t)(sizeof (buf) - 1));
(void) lseek(fds[0].fd, 0, SEEK_SET);
}
}
return (NULL);
}