#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mnttab.h>
#include <sys/types.h>
#include <sys/statvfs.h>
#include <strings.h>
#include "libfsmgt.h"
static fs_mntlist_t *create_mntlist_entry(struct mnttab mnttab_entry);
static fs_mntlist_t *create_extmntlist_entry(struct extmnttab mnttab_entry);
static struct mnttab *create_mnttab_filter(char *resource, char *mountp,
char *fstype, char *mntopts, char *time);
static void find_overlayed_filesystems(fs_mntlist_t *mnt_list,
boolean_t filtered_list, int *errp);
static void free_mnttab_entry(struct mnttab *mnttab_entry);
static char *is_option(char *opt_string, char *opt, int *errp);
boolean_t is_overlayed(fs_mntlist_t *complete_mnt_list,
char *mountp);
void
fs_free_mount_list(fs_mntlist_t *headp) {
fs_mntlist_t *tmp;
while (headp != NULL) {
tmp = headp->next;
free(headp->resource);
free(headp->mountp);
free(headp->fstype);
free(headp->mntopts);
free(headp->time);
headp->next = NULL;
free(headp);
headp = tmp;
}
}
unsigned long long
fs_get_availablesize(char *mntpnt, int *errp) {
struct statvfs64 stvfs;
unsigned long long availablesize;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (0);
}
if (statvfs64(mntpnt, &stvfs) != -1) {
availablesize = stvfs.f_bfree;
availablesize = availablesize * stvfs.f_frsize;
} else {
*errp = errno;
return (0);
}
return (availablesize);
}
unsigned long long
fs_get_avail_for_nonsuperuser_size(char *mntpnt, int *errp) {
struct statvfs64 stvfs;
unsigned long long avail_for_nonsu_size;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (0);
}
if (statvfs64(mntpnt, &stvfs) != -1) {
avail_for_nonsu_size = stvfs.f_bavail;
avail_for_nonsu_size = avail_for_nonsu_size * stvfs.f_frsize;
} else {
*errp = errno;
return (0);
}
return (avail_for_nonsu_size);
}
unsigned long long
fs_get_blocksize(char *mntpnt, int *errp) {
struct statvfs64 stvfs;
unsigned long long blocksize;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (0);
}
if (statvfs64(mntpnt, &stvfs) != -1) {
blocksize = stvfs.f_bsize;
} else {
*errp = errno;
return (0);
}
return (blocksize);
}
fs_mntlist_t *
fs_get_filtered_mount_list(char *resource, char *mountp, char *fstype,
char *mntopts, char *time, boolean_t find_overlays, int *errp) {
fs_mntlist_t *newp;
fs_mntlist_t *headp;
fs_mntlist_t *tailp;
FILE *fp;
*errp = 0;
headp = NULL;
tailp = NULL;
if ((fp = fopen(MNTTAB, "r")) != NULL) {
struct mnttab mnttab_entry;
struct mnttab *search_entry;
search_entry = create_mnttab_filter(resource, mountp, fstype,
mntopts, time);
if (search_entry == NULL) {
fs_free_mount_list(headp);
(void) fclose(fp);
*errp = ENOMEM;
return (NULL);
}
while (getmntany(fp, &mnttab_entry, search_entry) == 0) {
newp = create_mntlist_entry(mnttab_entry);
if (newp == NULL) {
fs_free_mount_list(headp);
(void) fclose(fp);
*errp = ENOMEM;
return (NULL);
}
if (headp == NULL) {
headp = newp;
tailp = newp;
} else {
tailp->next = newp;
tailp = newp;
}
}
free_mnttab_entry(search_entry);
(void) fclose(fp);
if (find_overlays == B_TRUE)
find_overlayed_filesystems(headp, B_TRUE, errp);
} else {
*errp = errno;
}
return (headp);
}
unsigned long
fs_get_fragsize(char *mntpnt, int *errp) {
struct statvfs64 stvfs;
unsigned long fragsize;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (0);
}
if (statvfs64(mntpnt, &stvfs) != -1) {
fragsize = stvfs.f_frsize;
} else {
*errp = errno;
return (0);
}
return (fragsize);
}
unsigned long
fs_get_maxfilenamelen(char *mntpnt, int *errp) {
long int returned_val;
unsigned long maxfilenamelen;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (0);
}
returned_val = pathconf(mntpnt, _PC_PATH_MAX);
if (returned_val != -1) {
maxfilenamelen = (unsigned long)returned_val;
} else {
*errp = errno;
return (0);
}
return (maxfilenamelen);
}
fs_mntlist_t *
fs_get_mounts_by_mntopt(char *mntopt, boolean_t find_overlays, int *errp) {
fs_mntlist_t *newp;
fs_mntlist_t *headp;
fs_mntlist_t *tailp;
FILE *fp;
*errp = 0;
headp = NULL;
tailp = NULL;
if (mntopt == NULL)
return (NULL);
if ((fp = fopen(MNTTAB, "r")) != NULL) {
struct mnttab mnttab_entry;
char *opt_found;
while (getmntent(fp, &mnttab_entry) == 0) {
opt_found = hasmntopt(&mnttab_entry, mntopt);
if (opt_found != NULL) {
newp = create_mntlist_entry(mnttab_entry);
if (newp == NULL) {
fs_free_mount_list(headp);
(void) fclose(fp);
*errp = ENOMEM;
return (NULL);
}
if (headp == NULL) {
headp = newp;
tailp = newp;
} else {
tailp->next = newp;
tailp = newp;
}
}
}
(void) fclose(fp);
if (find_overlays == B_TRUE)
find_overlayed_filesystems(headp, B_TRUE, errp);
} else {
*errp = errno;
}
return (headp);
}
fs_mntlist_t *
fs_get_mount_list(boolean_t find_overlays, int *errp) {
FILE *fp;
fs_mntlist_t *headp;
fs_mntlist_t *tailp;
fs_mntlist_t *newp;
*errp = 0;
headp = NULL;
tailp = NULL;
if ((fp = fopen(MNTTAB, "r")) != NULL) {
struct extmnttab mnttab_entry;
resetmnttab(fp);
while (getextmntent(fp, &mnttab_entry,
sizeof (struct extmnttab)) == 0) {
newp = create_extmntlist_entry(mnttab_entry);
if (newp == NULL) {
fs_free_mount_list(headp);
(void) fclose(fp);
*errp = ENOMEM;
return (NULL);
}
if (headp == NULL) {
headp = newp;
tailp = newp;
} else {
tailp->next = newp;
tailp = newp;
}
}
(void) fclose(fp);
if (find_overlays)
find_overlayed_filesystems(headp, B_FALSE, errp);
} else {
*errp = errno;
}
return (headp);
}
boolean_t
fs_is_readonly(char *mntpnt, int *errp) {
struct statvfs64 stvfs;
boolean_t readonly;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (B_FALSE);
}
if (statvfs64(mntpnt, &stvfs) != -1) {
readonly = stvfs.f_flag & ST_RDONLY;
} else {
*errp = errno;
return (B_FALSE);
}
return (readonly);
}
char *
fs_parse_optlist_for_option(char *optlist, char *opt, int *errp) {
const char *delimiter = ",";
char *token;
char *return_value;
char *optlist_copy;
*errp = 0;
optlist_copy = strdup(optlist);
if (optlist_copy == NULL) {
*errp = errno;
return (NULL);
}
token = strtok(optlist_copy, delimiter);
if (token == NULL) {
free(optlist_copy);
return (NULL);
} else if ((return_value = is_option(token, opt, errp)) != NULL) {
free(optlist_copy);
return (return_value);
}
while (token != NULL) {
token = NULL;
token = strtok(NULL, delimiter);
if (token == NULL) {
free(optlist_copy);
return (NULL);
} else if ((return_value =
is_option(token, opt, errp)) != NULL) {
free(optlist_copy);
return (return_value);
}
}
free(optlist_copy);
return (NULL);
}
unsigned long long
fs_get_totalsize(char *mntpnt, int *errp) {
struct statvfs64 stvfs;
unsigned long long totalsize;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (0);
}
if (statvfs64(mntpnt, &stvfs) != -1) {
totalsize = stvfs.f_blocks;
totalsize = totalsize * stvfs.f_frsize;
} else {
*errp = errno;
return (0);
}
return (totalsize);
}
unsigned long long
fs_get_usedsize(char *mntpnt, int *errp) {
struct statvfs64 stvfs;
unsigned long long usedsize;
*errp = 0;
if (mntpnt == NULL) {
*errp = EINVAL;
return (0);
}
if (statvfs64(mntpnt, &stvfs) != -1) {
usedsize = stvfs.f_blocks - stvfs.f_bfree;
usedsize = usedsize * stvfs.f_frsize;
} else {
*errp = errno;
return (0);
}
return (usedsize);
}
static fs_mntlist_t *
create_mntlist_entry(struct mnttab mnttab_entry) {
fs_mntlist_t *newp;
newp = (fs_mntlist_t *)calloc((size_t)1,
(size_t)sizeof (fs_mntlist_t));
if (newp == NULL) {
return (NULL);
}
newp->resource = strdup(mnttab_entry.mnt_special);
if (newp->resource == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->mountp = strdup(mnttab_entry.mnt_mountp);
if (newp->mountp == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->fstype = strdup(mnttab_entry.mnt_fstype);
if (newp->fstype == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->mntopts = strdup(mnttab_entry.mnt_mntopts);
if (newp->mntopts == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->time = strdup(mnttab_entry.mnt_time);
if (newp->time == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->next = NULL;
return (newp);
}
static fs_mntlist_t *
create_extmntlist_entry(struct extmnttab mnttab_entry) {
fs_mntlist_t *newp;
newp = (fs_mntlist_t *)calloc((size_t)1,
(size_t)sizeof (fs_mntlist_t));
if (newp == NULL) {
return (NULL);
}
newp->resource = strdup(mnttab_entry.mnt_special);
if (newp->resource == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->mountp = strdup(mnttab_entry.mnt_mountp);
if (newp->mountp == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->fstype = strdup(mnttab_entry.mnt_fstype);
if (newp->fstype == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->mntopts = strdup(mnttab_entry.mnt_mntopts);
if (newp->mntopts == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->time = strdup(mnttab_entry.mnt_time);
if (newp->time == NULL) {
fs_free_mount_list(newp);
return (NULL);
}
newp->major = mnttab_entry.mnt_major;
newp->minor = mnttab_entry.mnt_minor;
newp->next = NULL;
return (newp);
}
static struct mnttab *
create_mnttab_filter(char *resource, char *mountp, char *fstype, char *mntopts,
char *time) {
struct mnttab *search_entry;
search_entry = (struct mnttab *)calloc((size_t)1,
(size_t)sizeof (struct mnttab));
if (search_entry == NULL) {
return (NULL);
}
if (resource != NULL) {
search_entry->mnt_special = strdup(resource);
if (search_entry->mnt_special == NULL) {
free_mnttab_entry(search_entry);
return (NULL);
}
}
if (mountp != NULL) {
search_entry->mnt_mountp = strdup(mountp);
if (search_entry->mnt_mountp == NULL) {
free_mnttab_entry(search_entry);
return (NULL);
}
}
if (fstype != NULL) {
search_entry->mnt_fstype = strdup(fstype);
if (search_entry->mnt_fstype == NULL) {
free_mnttab_entry(search_entry);
return (NULL);
}
}
if (mntopts != NULL) {
search_entry->mnt_mntopts = strdup(mntopts);
if (search_entry->mnt_mntopts == NULL) {
free_mnttab_entry(search_entry);
return (NULL);
}
}
if (time != NULL) {
search_entry->mnt_time = strdup(time);
if (search_entry->mnt_time == NULL) {
free_mnttab_entry(search_entry);
return (NULL);
}
}
return (search_entry);
}
static void
find_overlayed_filesystems(fs_mntlist_t *mnt_list,
boolean_t filtered_list, int *errp) {
boolean_t exit = B_FALSE;
fs_mntlist_t *mnt_list_to_compare;
fs_mntlist_t *tmp;
*errp = 0;
if (filtered_list == B_TRUE) {
mnt_list_to_compare = fs_get_mount_list(B_FALSE, errp);
if (mnt_list_to_compare == NULL) {
return;
}
} else {
mnt_list_to_compare = mnt_list;
}
tmp = mnt_list_to_compare;
while (mnt_list != NULL) {
if (!(strcmp(mnt_list->fstype, "autofs") == 0)) {
char *dev_id;
dev_id = fs_parse_optlist_for_option(mnt_list->mntopts,
"dev=", errp);
if (dev_id == NULL) {
return;
}
exit = B_FALSE;
while (tmp != NULL && exit == B_FALSE) {
if (!(strcmp(tmp->fstype, "autofs")) == 0) {
char *tmp_dev_id;
tmp_dev_id =
fs_parse_optlist_for_option(
tmp->mntopts, "dev=", errp);
if (tmp_dev_id == NULL) {
return;
}
if (strcmp(tmp_dev_id, dev_id) == 0) {
mnt_list->overlayed =
is_overlayed(tmp,
mnt_list->mountp);
exit = B_TRUE;
}
free(tmp_dev_id);
}
tmp = tmp->next;
}
free(dev_id);
}
mnt_list = mnt_list->next;
}
if (filtered_list == B_TRUE)
fs_free_mount_list(mnt_list_to_compare);
}
static void
free_mnttab_entry(struct mnttab *mnttab_entry) {
free(mnttab_entry->mnt_special);
free(mnttab_entry->mnt_mountp);
free(mnttab_entry->mnt_fstype);
free(mnttab_entry->mnt_mntopts);
free(mnttab_entry->mnt_time);
free(mnttab_entry);
}
char *
is_option(char *opt_string, char *opt, int *errp) {
char *equalsign = "=";
char *found_equalsign;
char *return_val;
*errp = 0;
found_equalsign = strstr(opt, equalsign);
if (found_equalsign == NULL) {
if (strcmp(opt_string, opt) == 0) {
return_val = strdup(opt);
if (return_val == NULL) {
*errp = errno;
return (NULL);
}
} else {
return_val = NULL;
}
} else {
int counter = 0;
char *opt_found;
char *value;
opt_found = strstr(opt_string, opt);
if (opt_found == NULL) {
return_val = NULL;
} else {
size_t opt_string_len;
size_t opt_len;
size_t value_len;
opt_string_len = strlen(opt_string);
opt_len = strlen(opt);
value_len = opt_string_len - opt_len;
value = (char *)calloc((size_t)(value_len+1),
(size_t)sizeof (char));
if (value == NULL) {
*errp = ENOMEM;
return (NULL);
}
while (counter <= (value_len-1)) {
value[counter] = opt_string[opt_len+counter];
counter = counter + 1;
}
value[counter] = '\0';
return_val = value;
}
}
return (return_val);
}
boolean_t
is_overlayed(fs_mntlist_t *mnt_list, char *mountp) {
boolean_t ret_val = B_FALSE;
mnt_list = mnt_list->next;
while (mnt_list != NULL && ret_val == B_FALSE) {
if (!(strcmp(mnt_list->fstype, "autofs") == 0)) {
if (strcmp(mnt_list->mountp, mountp) == 0) {
ret_val = B_TRUE;
} else {
ret_val = B_FALSE;
}
}
mnt_list = mnt_list->next;
}
return (ret_val);
}