#include "global.h"
#include <sys/mnttab.h>
#include <sys/mntent.h>
#include <sys/autoconf.h>
#include <signal.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/swap.h>
#include <sys/sysmacros.h>
#include <sys/mkdev.h>
#include <sys/modctl.h>
#include <ctype.h>
#include <libdiskmgt.h>
#include <libnvpair.h>
#include "misc.h"
#include "checkdev.h"
#include <sys/efi_partition.h>
static struct swaptable *getswapentries(void);
static void freeswapentries(struct swaptable *);
static int getpartition(char *pathname);
static int checkpartitions(int bm_mounted);
static struct swaptable *
getswapentries(void)
{
struct swaptable *st;
struct swapent *swapent;
int i, num;
char fullpathname[MAXPATHLEN];
if ((num = swapctl(SC_GETNSWP, NULL)) == -1) {
err_print("swapctl error ");
fullabort();
}
if (num == 0)
return (NULL);
if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int)))
== NULL) {
err_print("getswapentries: malloc failed.\n");
fullabort();
}
swapent = st->swt_ent;
for (i = 0; i < num; i++, swapent++) {
if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) {
err_print("getswapentries: malloc failed.\n");
fullabort();
}
}
st->swt_n = num;
if ((num = swapctl(SC_LIST, (void *)st)) == -1) {
err_print("swapctl error ");
fullabort();
}
swapent = st->swt_ent;
for (i = 0; i < num; i++, swapent++) {
if (*swapent->ste_path != '/') {
(void) snprintf(fullpathname, sizeof (fullpathname),
"/dev/%s", swapent->ste_path);
(void) strcpy(swapent->ste_path, fullpathname);
}
}
return (st);
}
static void
freeswapentries(struct swaptable *st)
{
struct swapent *swapent;
int i;
swapent = st->swt_ent;
for (i = 0; i < st->swt_n; i++, swapent++)
free(swapent->ste_path);
free(st);
}
static int
getpartition(char *pathname)
{
int mfd;
struct dk_cinfo dkinfo;
struct stat stbuf;
char raw_device[MAXPATHLEN];
int found = -1;
if (match_substr(pathname, "/dev/") == 0)
return (found);
(void) strcpy(raw_device, "/dev/r");
(void) strcat(raw_device, pathname + strlen("/dev/"));
if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
return (found);
}
if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
(void) close(mfd);
return (found);
}
if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) {
(void) close(mfd);
return (found);
}
(void) close(mfd);
if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype ||
cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum ||
cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit ||
strcmp(cur_disk->disk_dkinfo.dki_dname, dkinfo.dki_dname) != 0) {
return (found);
}
return (PARTITION(stbuf.st_rdev));
}
int
checkswap(diskaddr_t start, diskaddr_t end)
{
struct swaptable *st;
struct swapent *swapent;
int i;
int found = 0;
struct dk_map32 *map;
int part;
if (cur_parts == NULL)
return (0);
st = getswapentries();
if (st == NULL)
return (0);
swapent = st->swt_ent;
for (i = 0; i < st->swt_n; i++, swapent++) {
if ((part = getpartition(swapent->ste_path)) != -1) {
if (start == UINT_MAX64) {
found = -1;
break;
}
map = &cur_parts->pinfo_map[part];
if ((start >= (int)(map->dkl_cylno * spc() +
map->dkl_nblk)) ||
(end < (int)(map->dkl_cylno * spc()))) {
continue;
}
found = -1;
break;
};
}
freeswapentries(st);
if (found && option_f) {
err_print(
"Operation on disks being used for swapping must be interactive.\n");
cmdabort(SIGINT);
}
return (found);
}
int
checkdevinuse(char *cur_disk_path, diskaddr_t start, diskaddr_t end, int print,
int check_label)
{
int error;
int found = 0;
int check = 0;
int i;
int bm_inuse = 0;
int part = 0;
uint64_t slice_start, slice_size;
dm_descriptor_t *slices = NULL;
nvlist_t *attrs = NULL;
char *usage;
char *name;
if (NOINUSE_SET)
return (0);
if (*cur_disk_path != 'c') {
struct stat stbuf;
char majorname[16];
major_t majornum;
(void) stat(cur_disk_path, &stbuf);
majornum = major(stbuf.st_rdev);
(void) modctl(MODGETNAME, majorname, sizeof (majorname),
&majornum);
if (strcmp(majorname, "sd"))
if (strcmp(majorname, "ssd"))
if (strcmp(majorname, "cmdk"))
return (0);
}
cur_disk_path = basename(cur_disk_path);
name = strrchr(cur_disk_path, 'd');
if (name) {
name++;
for (; (*name <= '9') && (*name >= '0'); name++) {
}
*name = (char)0;
}
dm_get_slices(cur_disk_path, &slices, &error);
if (error) {
if (error != ENODEV) {
err_print("Error occurred with device in use"
"checking: %s\n", strerror(error));
return (found);
}
}
if (slices == NULL)
return (found);
for (i = 0; slices[i] != 0; i++) {
if (start == UINT_MAX64) {
name = dm_get_name(slices[i], &error);
if (error != 0 || !name) {
err_print("Error occurred with device "
"in use checking: %s\n", strerror(error));
continue;
}
if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) ||
error) {
if (error != 0) {
dm_free_name(name);
name = NULL;
err_print("Error occurred with "
"device in use checking: "
"%s\n", strerror(error));
continue;
}
dm_free_name(name);
name = NULL;
if (strstr(usage, DM_USE_DUMP)) {
if (print) {
err_print(usage);
free(usage);
}
dm_free_descriptors(slices);
return (1);
}
found ++;
check = 1;
if (print) {
err_print(usage);
free(usage);
}
}
} else {
attrs = dm_get_attributes(slices[i], &error);
if (error) {
err_print("Error occurred with device in use "
"checking: %s\n", strerror(error));
continue;
}
if (attrs == NULL) {
continue;
}
(void) nvlist_lookup_uint64(attrs, DM_START,
&slice_start);
(void) nvlist_lookup_uint64(attrs, DM_SIZE,
&slice_size);
if (start >= (slice_start + slice_size) ||
(end < slice_start)) {
nvlist_free(attrs);
attrs = NULL;
continue;
}
name = dm_get_name(slices[i], &error);
if (error != 0 || !name) {
err_print("Error occurred with device "
"in use checking: %s\n", strerror(error));
nvlist_free(attrs);
attrs = NULL;
continue;
}
if (dm_inuse(name, &usage,
DM_WHO_FORMAT, &error) || error) {
if (error != 0) {
dm_free_name(name);
name = NULL;
err_print("Error occurred with "
"device in use checking: "
"%s\n", strerror(error));
nvlist_free(attrs);
attrs = NULL;
continue;
}
dm_free_name(name);
name = NULL;
if (strstr(usage, DM_USE_DUMP)) {
if (print) {
err_print(usage);
free(usage);
}
dm_free_descriptors(slices);
nvlist_free(attrs);
return (1);
}
found ++;
check = 1;
if (print) {
err_print(usage);
free(usage);
}
}
}
if (check) {
name = dm_get_name(slices[i], &error);
if (error != 0 || !name) {
err_print("Error occurred with device "
"in use checking: %s\n", strerror(error));
nvlist_free(attrs);
attrs = NULL;
continue;
}
part = getpartition(name);
dm_free_name(name);
name = NULL;
if (part != -1) {
bm_inuse |= 1 << part;
}
check = 0;
}
if (attrs) {
nvlist_free(attrs);
break;
}
}
if (slices) {
dm_free_descriptors(slices);
}
if (check_label && bm_inuse) {
return (checkpartitions(bm_inuse));
}
return (found);
}
int
checkmount(diskaddr_t start, diskaddr_t end)
{
FILE *fp;
int found = 0;
struct dk_map32 *map;
int part;
struct mnttab mnt_record;
struct mnttab *mp = &mnt_record;
if (cur_parts == NULL)
return (0);
enter_critical();
fp = fopen(MNTTAB, "r");
if (fp == NULL) {
err_print("Unable to open mount table.\n");
fullabort();
}
while ((getmntent(fp, mp)) != -1) {
if ((part = getpartition(mp->mnt_special)) == -1)
continue;
if (start == UINT_MAX64) {
found = -1;
break;
}
map = &cur_parts->pinfo_map[part];
if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) ||
(end < (int)(map->dkl_cylno * spc()))) {
continue;
}
found = -1;
break;
}
(void) fclose(fp);
exit_critical();
if (found && option_f) {
err_print("Operation on mounted disks must be interactive.\n");
cmdabort(SIGINT);
}
return (found);
}
int
check_label_with_swap(void)
{
int i;
struct swaptable *st;
struct swapent *swapent;
int part;
int bm_swap = 0;
if (cur_parts == NULL)
return (0);
st = getswapentries();
if (st == NULL)
return (0);
swapent = st->swt_ent;
for (i = 0; i < st->swt_n; i++, swapent++)
if ((part = getpartition(swapent->ste_path)) != -1)
bm_swap |= (1 << part);
freeswapentries(st);
return (checkpartitions(bm_swap));
}
int
check_label_with_mount(void)
{
FILE *fp;
int part;
struct mnttab mnt_record;
struct mnttab *mp = &mnt_record;
int bm_mounted = 0;
if (cur_parts == NULL)
return (0);
enter_critical();
fp = fopen(MNTTAB, "r");
if (fp == NULL) {
err_print("Unable to open mount table.\n");
fullabort();
}
while ((getmntent(fp, mp)) != -1) {
if ((part = getpartition(mp->mnt_special)) != -1)
bm_mounted |= (1 << part);
}
(void) fclose(fp);
exit_critical();
return (checkpartitions(bm_mounted));
}
static int
checkpartitions(int bm_mounted)
{
struct dk_map32 *n;
struct dk_map *o;
struct dk_allmap old_map;
int i, found = 0;
struct partition64 o_efi;
if (cur_label == L_TYPE_EFI) {
for (i = 0; i < EFI_NUMPAR; i++) {
if (bm_mounted & (1 << i)) {
o_efi.p_partno = i;
if (ioctl(cur_file, DKIOCPARTITION, &o_efi)
== -1) {
err_print("Unable to get information "
"for EFI partition %d.\n", i);
return (-1);
}
if (o_efi.p_start == cur_parts->etoc->
efi_parts[i].p_start && o_efi.p_size
<= cur_parts->etoc->efi_parts[i].p_size) {
continue;
}
found = -1;
}
if (found)
break;
}
} else {
if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) {
err_print("Unable to get current partition map.\n");
return (-1);
}
for (i = 0; i < NDKMAP; i++) {
if (bm_mounted & (1 << i)) {
o = &old_map.dka_map[i];
n = &cur_parts->pinfo_map[i];
#ifdef DEBUG
fmt_print(
"checkpartitions :checking partition '%c' \n", i + PARTITION_BASE);
#endif
if (o->dkl_cylno == n->dkl_cylno &&
o->dkl_nblk <= n->dkl_nblk) {
#ifdef DEBUG
if (o->dkl_nblk < n->dkl_nblk) {
fmt_print(
"- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk);
}
fmt_print("\n");
#endif
continue;
}
#ifdef DEBUG
fmt_print("- changes; old (%d,%d)->new "
"(%d,%d)\n", o->dkl_cylno, o->dkl_nblk, n->dkl_cylno, n->dkl_nblk);
#endif
found = -1;
}
if (found)
break;
}
}
if (found && option_f) {
err_print("Operation on mounted disks or \
disks currently being used for swapping must be interactive.\n");
cmdabort(SIGINT);
}
return (found);
}