summaryrefslogtreecommitdiff
path: root/usr/src/cmd/rmformat/rmf_misc.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/rmformat/rmf_misc.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/rmformat/rmf_misc.c')
-rw-r--r--usr/src/cmd/rmformat/rmf_misc.c2159
1 files changed, 2159 insertions, 0 deletions
diff --git a/usr/src/cmd/rmformat/rmf_misc.c b/usr/src/cmd/rmformat/rmf_misc.c
new file mode 100644
index 0000000000..77269cc028
--- /dev/null
+++ b/usr/src/cmd/rmformat/rmf_misc.c
@@ -0,0 +1,2159 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * rmf_misc.c :
+ * Miscelleneous routines for rmformat.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/mnttab.h>
+#include <volmgt.h>
+#include <sys/dkio.h>
+#include <sys/fdio.h>
+#include <sys/vtoc.h>
+#include <sys/termios.h>
+#include <sys/mount.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <priv.h>
+#include <stdarg.h>
+#include "rmformat.h"
+/*
+ * These defines are from the PCMCIA memory driver driver
+ * header files (pcramio.h/pcramvar.h) and they are in
+ * the Platform Specific (PS) train.
+ */
+#ifndef PCRAM_PROBESIZE
+#define PCRAMIOC ('P' << 8)
+#define PCRAM_PROBESIZE (PCRAMIOC|22) /* Probe memory card size */
+#endif
+
+/*
+ * Definitions.
+ */
+#define SENSE_KEY(rqbuf) (rqbuf[2] & 0xf) /* scsi error category */
+#define ASC(rqbuf) (rqbuf[12]) /* additional sense code */
+#define ASCQ(rqbuf) (rqbuf[13]) /* ASC qualifier */
+
+#define DEFAULT_SCSI_TIMEOUT 60
+#define INQUIRY_CMD 0x12
+#define RQBUFLEN 32
+#define CD_RW 1 /* CD_RW/CD-R */
+#define WRITE_10_CMD 0x2A
+#define READ_INFO_CMD 0x51
+#define SYNC_CACHE_CMD 0x35
+#define CLOSE_TRACK_CMD 0x5B
+#define MODE_SENSE_10_CMD 0x5A
+#define DEVFS_PREFIX "/devices"
+
+int uscsi_error; /* used for debugging failed uscsi */
+char rqbuf[RQBUFLEN];
+static uint_t total_retries;
+static struct uscsi_cmd uscmd;
+static char ucdb[16];
+uchar_t uscsi_status, rqstatus, rqresid;
+int total_devices_found = 0;
+int removable_found = 0;
+
+extern char *global_intr_msg;
+extern int vol_running;
+extern char *dev_name;
+extern int32_t m_flag;
+
+/*
+ * ON-private functions from libvolmgt
+ */
+int _dev_mounted(char *path);
+
+/*
+ * Function prototypes.
+ */
+static int my_umount(char *mountp);
+static int my_volrmmount(char *real_name);
+static int vol_name_to_dev_node(char *vname, char *found);
+static int vol_lookup(char *supplied, char *found);
+static device_t *get_device(char *user_supplied, char *node);
+static char *get_physical_name(char *path);
+static int lookup_device(char *supplied, char *found);
+static void fini_device(device_t *dev);
+static int is_cd(char *node);
+void *my_zalloc(size_t size);
+void err_msg(char *fmt, ...);
+int inquiry(int fd, uchar_t *inq);
+struct uscsi_cmd *get_uscsi_cmd(void);
+int uscsi(int fd, struct uscsi_cmd *scmd);
+int get_mode_page(int fd, int page_no, int pc, int buf_len,
+ uchar_t *buffer);
+int mode_sense(int fd, uchar_t pc, int dbd, int page_len,
+ uchar_t *buffer);
+uint16_t read_scsi16(void *addr);
+int check_device(device_t *dev, int cond);
+static void get_media_info(device_t *t_dev, char *sdev,
+ char *pname, char *sn);
+
+extern void process_p_flag(smedia_handle_t handle, int32_t fd);
+
+void
+my_perror(char *err_string)
+{
+
+ int error_no;
+ if (errno == 0)
+ return;
+
+ error_no = errno;
+ (void) fprintf(stderr, "%s", err_string);
+ (void) fprintf(stderr, gettext(" : "));
+ errno = error_no;
+ perror("");
+}
+
+int32_t
+get_confirmation()
+{
+ char c;
+
+ (void) fprintf(stderr, gettext("Do you want to continue? (y/n)"));
+ c = getchar();
+ if (c == 'y' || c == 'Y')
+ return (1);
+ else if (c == 'n' || c == 'N')
+ return (0);
+ else {
+ (void) fprintf(stderr, gettext("Invalid choice\n"));
+ return (0);
+ }
+}
+
+
+void
+get_passwd(struct smwp_state *wp, int32_t confirm)
+{
+ char passwd[256], re_passwd[256];
+ int32_t len;
+ struct termios tio;
+ int32_t echo_off = 0;
+ FILE *in, *out;
+ char *buf;
+
+
+ in = fopen("/dev/tty", "r+");
+ if (in == NULL) {
+ in = stdin;
+ out = stderr;
+ } else {
+ out = in;
+ }
+
+ /* Turn echoing off if it is on now. */
+
+ if (tcgetattr(fileno(in), &tio) < 0) {
+ PERROR("Echo off ioctl failed");
+ exit(1);
+ }
+ if (tio.c_lflag & ECHO) {
+ tio.c_lflag &= ~ECHO;
+ /* echo_off = tcsetattr(fileno(in), TCSAFLUSH, &tio) == 0; */
+ echo_off = tcsetattr(fileno(in), TCSAFLUSH, &tio) == 0;
+ tio.c_lflag |= ECHO;
+ }
+
+ /* CONSTCOND */
+ while (1) {
+ (void) fputs(
+ gettext("Please enter password (32 chars maximum):"),
+ out);
+ (void) fflush(out);
+ buf = fgets(passwd, (size_t)256, in);
+ rewind(in);
+ if (buf == NULL) {
+ PERROR("Error reading password");
+ continue;
+ }
+ len = strlen(passwd);
+ (void) fputc('\n', out);
+ len--; /* To offset the \n */
+ if ((len <= 0) || (len > 32)) {
+ (void) fprintf(stderr,
+ gettext("Invalid length of password \n"));
+ (void) fputs("Try again\n", out);
+ continue;
+ }
+
+ if (!confirm)
+ break;
+
+ (void) fputs("Please reenter password:", out);
+ (void) fflush(out);
+ buf = fgets(re_passwd, (size_t)256, in);
+ rewind(in);
+ (void) fputc('\n', out);
+ if ((buf == NULL) || strcmp(passwd, re_passwd)) {
+ (void) fputs("passwords did not match\n", out);
+ (void) fputs("Try again\n", out);
+ } else {
+ break;
+ }
+ }
+ wp->sm_passwd_len = len;
+ (void) strncpy(wp->sm_passwd, passwd, wp->sm_passwd_len);
+ wp->sm_version = SMWP_STATE_V_1;
+
+ /* Restore echoing. */
+ if (echo_off)
+ (void) tcsetattr(fileno(in), TCSAFLUSH, &tio);
+
+}
+
+int32_t
+check_and_unmount_vold(char *device_name, int32_t flag)
+{
+ char *real_name;
+ char *nm;
+ char tmp_path_name[PATH_MAX];
+ struct stat stat_buf;
+ int32_t ret_val = 0;
+ struct mnttab *mntp;
+ FILE *fp;
+ int nl;
+
+ DPRINTF1("Device name %s\n", device_name);
+
+ if (volmgt_running() == 0) {
+ DPRINTF("Vold not running\n");
+ return (0);
+ }
+ if ((nm = volmgt_symname(device_name)) == NULL) {
+ DPRINTF("path not managed\n");
+ real_name = media_findname(device_name);
+ } else {
+ DPRINTF1("path managed as %s\n", nm);
+ real_name = media_findname(nm);
+ DPRINTF1("real name %s\n", real_name);
+ }
+
+ if (real_name == NULL)
+ return (-1);
+
+ /*
+ * To find out whether the device has been mounted by
+ * volume manager...
+ *
+ * Convert the real name to a block device address.
+ * Do a partial match with the mnttab entries.
+ * Make sure the match is in the beginning to avoid if
+ * anybody puts a label similiar to volume manager path names.
+ * Then use "volrmmount -e <dev_name>" if -U flag is set.
+ */
+
+ nl = strlen("/vol/dev/");
+
+ if (strncmp(real_name, "/vol/dev/", nl) != 0)
+ return (0);
+ if (real_name[nl] == 'r') {
+ (void) snprintf(tmp_path_name, PATH_MAX, "%s%s", "/vol/dev/",
+ &real_name[nl + 1]);
+ } else {
+ (void) snprintf(tmp_path_name, PATH_MAX, "%s", real_name);
+ }
+ DPRINTF1("%s \n", tmp_path_name);
+ ret_val = stat(tmp_path_name, &stat_buf);
+ if (ret_val < 0) {
+ PERROR("Could not stat");
+ return (-1);
+ }
+
+ fp = fopen("/etc/mnttab", "r");
+
+ if (fp == NULL) {
+ PERROR("Could not open /etc/mnttab");
+ return (-1);
+ }
+
+ mntp = (struct mnttab *)malloc(sizeof (struct mnttab));
+ if (mntp == NULL) {
+ PERROR("malloc failed");
+ (void) fclose(fp);
+ return (-1);
+ }
+ errno = 0;
+ while (getmntent(fp, mntp) == 0) {
+ if (errno != 0) {
+ PERROR("Error with mnttab");
+ (void) fclose(fp);
+ return (-1);
+ }
+ /* Is it a probable entry? */
+ DPRINTF1(" %s \n", mntp->mnt_special);
+ if (strstr(mntp->mnt_special, tmp_path_name) !=
+ mntp->mnt_special) {
+ /* Skip to next entry */
+ continue;
+ } else {
+ DPRINTF1("Found!! %s\n", mntp->mnt_special);
+ ret_val = 1;
+ break;
+ }
+ }
+
+ if (ret_val == 1) {
+ if (flag) {
+ if (my_volrmmount(real_name) < 0) {
+ ret_val = -1;
+ }
+ } else {
+ ret_val = -1;
+ }
+ }
+ (void) fclose(fp);
+ free(mntp);
+ return (ret_val);
+}
+
+/*
+ * This routine checks if a device has mounted partitions. The
+ * device name is assumed to be /dev/rdsk/cNtNdNsN. So, this can
+ * be used for SCSI and PCMCIA cards.
+ * Returns
+ * 0 : if not mounted
+ * 1 : if successfully unmounted
+ * -1 : Any error or umount failed
+ */
+
+int32_t
+check_and_unmount_scsi(char *device_name, int32_t flag)
+{
+
+ struct mnttab *mntrefp;
+ struct mnttab *mntp;
+ FILE *fp;
+ char block_dev_name[PATH_MAX];
+ char tmp_name[PATH_MAX];
+ int32_t i, j;
+ int32_t unmounted = 0;
+
+ /*
+ * If the device name is not a character special, anyway we
+ * can not progress further
+ */
+
+ if (strncmp(device_name, "/dev/rdsk/c", strlen("/dev/rdsk/c")) != 0)
+ return (0);
+
+ (void) snprintf(block_dev_name, PATH_MAX, "/dev/%s",
+ &device_name[strlen("/dev/r")]);
+ fp = fopen("/etc/mnttab", "r");
+
+ if (fp == NULL) {
+ PERROR("Could not open /etc/mnttab");
+ return (-1);
+ }
+
+ mntrefp = (struct mnttab *)malloc(sizeof (struct mnttab));
+ if (mntrefp == NULL) {
+ PERROR("malloc failed");
+ (void) fclose(fp);
+ return (-1);
+ }
+
+ mntp = (struct mnttab *)malloc(sizeof (struct mnttab));
+ if (mntp == NULL) {
+ PERROR("malloc failed");
+ (void) fclose(fp);
+ free(mntrefp);
+ return (-1);
+ }
+
+ /* Try all the partitions */
+
+ (void) snprintf(tmp_name, PATH_MAX, "/dev/%s",
+ &device_name[strlen("/dev/r")]);
+
+ tmp_name[strlen("/dev/dsk/c0t0d0s")] = '\0';
+
+ errno = 0;
+ while (getmntent(fp, mntp) == 0) {
+ if (errno != 0) {
+ PERROR("Error with mnttab");
+ (void) fclose(fp);
+ return (-1);
+ }
+ /* Is it a probable entry? */
+ if (strncmp(mntp->mnt_special, tmp_name, strlen(tmp_name))) {
+ /* Skip to next entry */
+ continue;
+ }
+ for (i = 0; i < NDKMAP; i++) {
+ /* Check for ufs style mount devices */
+ (void) snprintf(block_dev_name, PATH_MAX,
+ "%s%d", tmp_name, i);
+
+ if (strcmp(mntp->mnt_special, block_dev_name) == 0) {
+ if (flag) {
+ if (my_umount(mntp->mnt_mountp) < 0) {
+ (void) fclose(fp);
+ return (-1);
+ }
+ unmounted = 1;
+ } else {
+ (void) fclose(fp);
+ return (-1);
+ }
+ /* Skip to next entry */
+ continue;
+ }
+
+ /* Try for :1 -> :24 for pcfs */
+
+ for (j = 1; j < 24; j++) {
+ (void) snprintf(block_dev_name, PATH_MAX,
+ "%s%d:%d", tmp_name, i, j);
+
+ if (strcmp(mntp->mnt_special,
+ block_dev_name) == 0) {
+ if (flag) {
+ if (my_umount(mntp->mnt_mountp)
+ < 0) {
+ (void) fclose(fp);
+ return (-1);
+ }
+ unmounted = 1;
+ } else {
+ (void) fclose(fp);
+ return (-1);
+ }
+ /* Skip to next entry */
+ continue;
+ }
+ (void) snprintf(block_dev_name, PATH_MAX,
+ "%s%d:%c", tmp_name, i, 'b' + j);
+
+ if (strcmp(mntp->mnt_special,
+ block_dev_name) == 0) {
+ if (flag) {
+ if (my_umount(mntp->mnt_mountp)
+ < 0) {
+ (void) fclose(fp);
+ return (-1);
+ }
+ unmounted = 1;
+ } else {
+ (void) fclose(fp);
+ return (-1);
+ }
+ /* Skip to next entry */
+ continue;
+ }
+ }
+ }
+
+ }
+
+ if (unmounted)
+ return (1);
+ return (0);
+}
+
+/*
+ * This routine checks if a device has mounted partitions. The
+ * device name is assumed to be /dev/rdiskette. So, this can
+ * be used for Floppy controllers
+ * Returns
+ * 0 : if not mounted
+ * 1 : if successfully unmounted
+ * -1 : Any error or unmount failed
+ */
+
+int32_t
+check_and_unmount_floppy(int32_t fd, int32_t flag)
+{
+ FILE *fp = NULL;
+ int32_t mfd;
+ struct dk_cinfo dkinfo, dkinfo_tmp;
+ struct mnttab mnt_record;
+ struct mnttab *mp = &mnt_record;
+ struct stat stbuf;
+ char raw_device[PATH_MAX];
+ int32_t found = 0;
+
+
+ if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
+ return (-1);
+ }
+
+ if ((fp = fopen(MNTTAB, "r")) == NULL) {
+ PERROR("Could not open /etc/mnttab");
+ (void) close(fd);
+ exit(3);
+ }
+
+ while (getmntent(fp, mp) == 0) {
+ if (strstr(mp->mnt_special, "/dev/fd") == NULL &&
+ strstr(mp->mnt_special, "/dev/disket") == NULL &&
+ strstr(mp->mnt_special, "/dev/c") == NULL) {
+ continue;
+ }
+
+ (void) strcpy(raw_device, "/dev/r");
+ (void) strcat(raw_device, mp->mnt_special + strlen("/dev/"));
+
+
+ /*
+ * Attempt to open the device. If it fails, skip it.
+ */
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ mfd = open(raw_device, O_RDWR | O_NDELAY);
+
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ if (mfd < 0) {
+ continue;
+ }
+
+ /*
+ * Must be a character device
+ */
+ if (fstat(mfd, &stbuf) < 0 || !S_ISCHR(stbuf.st_mode)) {
+ (void) close(mfd);
+ continue;
+ }
+ /*
+ * Attempt to read the configuration info on the disk.
+ */
+ if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) {
+ (void) close(mfd);
+ continue;
+ }
+ /*
+ * Finished with the opened device
+ */
+ (void) close(mfd);
+
+ /*
+ * If it's not the disk we're interested in, it doesn't apply.
+ */
+ if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype ||
+ dkinfo.dki_cnum != dkinfo_tmp.dki_cnum ||
+ dkinfo.dki_unit != dkinfo_tmp.dki_unit) {
+ continue;
+ }
+ /*
+ * It's a mount on the disk we're checking. If we are
+ * checking whole disk, then we found trouble. We can
+ * quit searching.
+ */
+
+ if (flag) {
+ if (my_umount(mp->mnt_mountp) < 0) {
+ return (-1);
+ }
+ found = 1;
+ } else {
+ return (-1);
+ }
+ }
+ return (found);
+}
+
+
+int32_t
+my_open(char *device_name, int32_t flags)
+{
+ char *real_name;
+ char *nm;
+ char tmp_path_name[PATH_MAX];
+ struct stat stat_buf;
+ int32_t ret_val;
+ int32_t fd;
+ int32_t have_read_priv = 0;
+ DIR *dirp;
+ struct dirent *dp;
+
+ DPRINTF1("Device name %s\n", device_name);
+
+ if ((nm = volmgt_symname(device_name)) == NULL) {
+ DPRINTF("path not managed\n");
+ real_name = media_findname(device_name);
+ } else {
+ DPRINTF1("path managed as %s\n", nm);
+ real_name = media_findname(nm);
+ DPRINTF1("real name %s\n", real_name);
+ }
+
+ if (real_name == NULL)
+ return (-1);
+
+ (void) strcpy(tmp_path_name, real_name);
+ ret_val = stat(tmp_path_name, &stat_buf);
+ if (ret_val < 0) {
+ PERROR("Could not stat");
+ return (-1);
+ }
+ if (stat_buf.st_mode & S_IFDIR) {
+
+ /*
+ * Open the directory and look for the
+ * first non '.' entry.
+ * Since raw_read and raw_writes are used, we don't
+ * need to access the backup slice.
+ * For PCMCIA Memory cards, raw_read and raw_writes are
+ * not supported, but that is not a problem as, only slice2
+ * is allowed on PCMCIA memory cards.
+ */
+
+ /*
+ * First make sure we are operating with a /vol/....
+ * Otherwise it can dangerous,
+ * e.g. rmformat -s /dev/rdsk
+ * We should not look into the directory contents here.
+ */
+ if (strncmp(tmp_path_name, "/vol/dev/", strlen("/vol/dev/"))
+ != 0) {
+ (void) fprintf(stderr, gettext("The specified device \
+is not a raw device.\n"));
+ exit(1);
+ }
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ dirp = opendir(tmp_path_name);
+
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ if (dirp == NULL) {
+ return (-1);
+ }
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+ have_read_priv = 1;
+
+ while ((dp = readdir(dirp)) != NULL) {
+
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ, (char *)NULL);
+ have_read_priv = 0;
+
+ DPRINTF1("Found %s\n", dp->d_name);
+ if ((strcmp(dp->d_name, ".") != 0) &&
+ (strcmp(dp->d_name, "..") != 0)) {
+ (void) snprintf(tmp_path_name, PATH_MAX,
+ "%s/%s", tmp_path_name, dp->d_name);
+
+ DPRINTF1("tmp_pathname is %s\n", tmp_path_name);
+ break;
+ }
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ, (char *)NULL);
+ have_read_priv = 1;
+ }
+
+ if (have_read_priv) {
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ, (char *)NULL);
+ have_read_priv = 0;
+ }
+
+ (void) closedir(dirp);
+ }
+
+
+ if (volmgt_running() == 0) {
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+ have_read_priv = 1;
+ }
+
+ fd = open(tmp_path_name, flags);
+
+ if (have_read_priv) {
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+ have_read_priv = 0;
+ }
+
+ DPRINTF1("path opened %s\n", tmp_path_name);
+
+ return (fd);
+}
+
+int64_t
+my_atoll(char *ptr)
+{
+ char *tmp_ptr = ptr;
+ int32_t base = 10;
+ int64_t ret_val;
+
+ while (*tmp_ptr) {
+ if (isdigit(*tmp_ptr))
+ tmp_ptr++;
+ else {
+ base = 16;
+ break;
+ }
+ }
+ tmp_ptr = ptr;
+ if (base == 16) {
+ if (strlen(tmp_ptr) < 3) {
+ return (-1);
+ }
+ if (*tmp_ptr++ != '0' || (*tmp_ptr != 'x' && *tmp_ptr != 'X')) {
+ return (-1);
+ }
+ tmp_ptr++;
+ while (*tmp_ptr) {
+ if (isxdigit(*tmp_ptr))
+ tmp_ptr++;
+ else {
+ return (-1);
+ }
+ }
+ }
+ ret_val = strtoll(ptr, (char **)NULL, 0);
+ return (ret_val);
+}
+
+int32_t
+write_sunos_label(int32_t fd, int32_t media_type)
+{
+
+ struct vtoc v_toc;
+ int32_t ret;
+
+ (void) memset(&v_toc, 0, sizeof (struct vtoc));
+
+ /* Initialize the vtoc information */
+
+ if (media_type == SM_FLOPPY) {
+ struct fd_char fdchar;
+ int32_t mult_factor;
+
+ if (ioctl(fd, FDIOGCHAR, &fdchar) < 0) {
+ PERROR("FDIOGCHAR failed");
+ return (-1);
+ }
+
+ /* SPARC and x86 fd drivers use fdc_medium differently */
+#if defined(__sparc)
+ mult_factor = (fdchar.fdc_medium) ? 2 : 1;
+#elif defined(__x86)
+ mult_factor = (fdchar.fdc_medium == 5) ? 2 : 1;
+#else
+#error No Platform defined
+#endif /* defined(__sparc) */
+
+ /* initialize the vtoc structure */
+ v_toc.v_nparts = 3;
+
+ v_toc.v_part[0].p_start = 0;
+ v_toc.v_part[0].p_size = (fdchar.fdc_ncyl - 1) * 2 *
+ fdchar.fdc_secptrack * mult_factor;
+ v_toc.v_part[1].p_start = (fdchar.fdc_ncyl - 1) * 2 *
+ fdchar.fdc_secptrack * mult_factor;
+ v_toc.v_part[1].p_size = 2 * fdchar.fdc_secptrack * mult_factor;
+
+ v_toc.v_part[2].p_start = 0;
+ v_toc.v_part[2].p_size = fdchar.fdc_ncyl * 2 *
+ fdchar.fdc_secptrack * mult_factor;
+
+ } else if (media_type == SM_PCMCIA_MEM) {
+
+ static struct dk_geom dkg;
+
+ /* Get card cyl/head/secptrack info */
+ if (ioctl(fd, DKIOCGGEOM, &dkg) < 0) {
+ /*
+ * Card doesn't have a CIS. So, ask driver
+ * to probe card size info
+ */
+ if (ioctl(fd, PCRAM_PROBESIZE, &dkg) < 0) {
+ (void) fprintf(stderr,
+ gettext(
+ "Could not get card size information\n"));
+ (void) close(fd);
+ exit(3);
+ }
+ }
+
+
+ v_toc.v_part[2].p_start = 0;
+ v_toc.v_part[2].p_size = dkg.dkg_ncyl * dkg.dkg_nhead *
+ dkg.dkg_nsect;
+
+ /* v_nparts was 1 in fdformat. But write vtoc failes */
+ v_toc.v_nparts = 3;
+
+ } else if (media_type == SM_SCSI_FLOPPY) {
+
+ smedia_handle_t handle;
+ smmedium_prop_t med_info;
+ struct dk_geom dkgeom;
+
+
+ /*
+ * call smedia_get_medium_property to get the
+ * correct media information, since DKIOCGMEDIAINFO
+ * may fail for unformatted media.
+ */
+
+ handle = smedia_get_handle(fd);
+ if (handle == NULL) {
+ (void) fprintf(stderr,
+ gettext("Failed to get libsmedia handle.\n"));
+
+ (void) close(fd);
+ return (-1);
+ }
+
+
+ if (smedia_get_medium_property(handle, &med_info) < 0) {
+ (void) fprintf(stderr,
+ gettext("Get medium property failed \n"));
+
+ (void) smedia_release_handle(handle);
+ (void) close(fd);
+ return (-1);
+ }
+
+ /* Fill in our own geometry information */
+
+ dkgeom.dkg_pcyl = med_info.sm_pcyl;
+ dkgeom.dkg_ncyl = med_info.sm_pcyl;
+ dkgeom.dkg_nhead = med_info.sm_nhead;
+ dkgeom.dkg_nsect = med_info.sm_nsect;
+ dkgeom.dkg_acyl = 0;
+ dkgeom.dkg_bcyl = 0;
+ dkgeom.dkg_intrlv = 0;
+ dkgeom.dkg_apc = 0;
+
+ /*
+ * Try to set vtoc, if not successful we will
+ * continue to use the faked geometry information.
+ */
+
+ (void) ioctl(fd, DKIOCSGEOM, &dkgeom);
+
+ (void) smedia_release_handle(handle);
+
+ /* we want the same partitioning as used for normal floppies */
+
+ v_toc.v_part[0].p_start = 0;
+ v_toc.v_part[0].p_size = (dkgeom.dkg_ncyl - 1) *
+ dkgeom.dkg_nhead * dkgeom.dkg_nsect;
+
+ v_toc.v_part[1].p_start = (dkgeom.dkg_ncyl - 1) *
+ dkgeom.dkg_nhead * dkgeom.dkg_nsect;
+ v_toc.v_part[1].p_size = dkgeom.dkg_nhead * dkgeom.dkg_nsect;
+
+ v_toc.v_part[2].p_start = 0;
+ v_toc.v_part[2].p_size = dkgeom.dkg_ncyl *
+ dkgeom.dkg_nhead * dkgeom.dkg_nsect;
+
+ /* both write_vtoc and DKIOCSVTOC require V_NUMPAR partitions */
+ v_toc.v_nparts = V_NUMPAR;
+
+ } else {
+
+ return (0);
+ }
+
+ v_toc.v_sanity = VTOC_SANE;
+ v_toc.v_version = V_VERSION;
+
+ /*
+ * The label structure is set up for DEV_BSIZE(512 byte) blocks,
+ * even though a medium density diskette has 1024 byte blocks
+ * See dklabel.h for more details.
+ */
+ v_toc.v_sectorsz = DEV_BSIZE;
+
+ /* let the fd driver finish constructing the label and writing it. */
+
+
+ /* need the file_dac_write privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE,
+ (char *)NULL);
+
+ ret = write_vtoc(fd, &v_toc);
+
+ /* drop the file_dac_write privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE,
+ (char *)NULL);
+
+ if (ret < 0) {
+ PERROR("Write vtoc");
+ DPRINTF1("Write vtoc failed errno:%d\n", errno);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+intr_sig_handler()
+{
+ char c;
+
+ (void) fprintf(stderr, gettext(global_intr_msg));
+ (void) fprintf(stderr,
+ gettext("\nDo you want to stop formatting?(y/n)"));
+ (void) fflush(stdout);
+ rewind(stdin);
+ while ((c = getchar()) == -1);
+ if (c == 'y' || c == 'Y') {
+ (void) fprintf(stderr, gettext("Format interrupted\n"));
+ exit(1);
+ } else if (c == 'n' || c == 'N')
+ return;
+ else {
+ (void) fprintf(stderr, gettext("Did not interrupt\n"));
+ return;
+ }
+}
+
+static struct sigaction act, oact;
+void
+trap_SIGINT()
+{
+
+ act.sa_handler = intr_sig_handler;
+ (void) memset(&act.sa_mask, 0, sizeof (sigset_t));
+ act.sa_flags = SA_RESTART; /* | SA_NODEFER; */
+ if (sigaction(SIGINT, &act, &oact) < 0) {
+ DPRINTF("sigset failed\n");
+ return;
+ }
+}
+
+void
+release_SIGINT()
+{
+ if (sigaction(SIGINT, &oact, (struct sigaction *)NULL) < 0) {
+ DPRINTF("sigunset failed\n");
+ return;
+ }
+}
+
+int32_t
+verify(smedia_handle_t handle, int32_t fd, uint32_t start_sector,
+ uint32_t nblocks, char *buf,
+ int32_t flag, int32_t blocksize, int32_t no_raw_rw)
+{
+ int32_t ret;
+
+ DPRINTF("ANALYSE MEDIA \n");
+
+
+ if ((flag == VERIFY_READ) && (!no_raw_rw)) {
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ ret = smedia_raw_read(handle, start_sector, buf, nblocks *
+ blocksize);
+
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ if ((ret < 0) || (ret != (nblocks * blocksize)))
+ return (-1);
+ return (0);
+
+ } else if ((flag == VERIFY_WRITE) && (!no_raw_rw)) {
+
+ /* need the file_dac_write privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE,
+ (char *)NULL);
+
+ ret = smedia_raw_write(handle, start_sector, buf, nblocks *
+ blocksize);
+
+ /* drop the file_dac_write privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE,
+ (char *)NULL);
+
+ if ((ret < 0) || (ret != (blocksize * nblocks)))
+ return (-1);
+ return (0);
+
+ } else if ((flag == VERIFY_READ) && (no_raw_rw)) {
+ ret = llseek(fd, start_sector * blocksize, SEEK_SET);
+ if (ret != start_sector * blocksize) {
+ (void) fprintf(stderr, gettext("Seek failed\n"));
+ return (-2);
+ }
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ ret = read(fd, buf, nblocks * blocksize);
+
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ if (ret != nblocks * blocksize) {
+ return (-1);
+ }
+ return (0);
+ } else if ((flag == VERIFY_WRITE) && (no_raw_rw)) {
+ ret = llseek(fd, start_sector * blocksize, SEEK_SET);
+ if (ret != start_sector * blocksize) {
+ (void) fprintf(stderr, gettext("Seek failed\n"));
+ return (-2);
+ }
+
+ /* need the file_dac_write privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE,
+ (char *)NULL);
+
+ ret = write(fd, buf, nblocks * blocksize);
+
+ /* drop the file_dac_write privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE,
+ (char *)NULL);
+
+ if (ret != nblocks * blocksize) {
+ return (-1);
+ }
+ return (0);
+ } else {
+ DPRINTF("Illegal parameter to verify_analysis!\n");
+ return (-1);
+ }
+}
+
+static int
+my_umount(char *mountp)
+{
+ pid_t pid; /* forked proc's pid */
+ int rval; /* proc's return value */
+
+
+ /* create a child to unmount the path */
+
+ /* need the proc_fork privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, (char *)NULL);
+
+ pid = fork();
+
+ /* drop the proc_fork privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, (char *)NULL);
+
+ if (pid < 0) {
+ PERROR("fork failed");
+ exit(0);
+ }
+
+ if (pid == 0) {
+ /* the child */
+ /* get rid of those nasty err messages */
+ DPRINTF1("call_unmount_prog: calling %s \n", mountp);
+
+ /* need the proc_exec privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
+ (char *)NULL);
+
+ /* umount needs the sys_mount privilege */
+ (void) priv_set(PRIV_ON, PRIV_INHERITABLE, PRIV_SYS_MOUNT,
+ (char *)NULL);
+
+ /* Become root again for the exec */
+ if (seteuid(0) < 0) {
+ PERROR("Can't set effective user id to root");
+ }
+ if (execl("/usr/sbin/umount", "/usr/sbin/umount", mountp,
+ NULL) < 0) {
+ perror("exec failed");
+ exit(-1);
+ }
+ }
+
+ /* wait for the umount command to exit */
+ rval = 0;
+ if (waitpid(pid, &rval, 0) == pid) {
+ if (WIFEXITED(rval)) {
+ if (WEXITSTATUS(rval) == 0) {
+ DPRINTF("umount : Success\n");
+ return (1);
+ }
+ }
+ }
+ return (-1);
+}
+
+static int
+my_volrmmount(char *real_name)
+{
+ int pid, rval;
+
+ /* need the proc_fork privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, (char *)NULL);
+
+ pid = fork();
+
+ /* drop the proc_fork privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, (char *)NULL);
+
+ /* create a child to unmount the path */
+ if (pid < 0) {
+ PERROR("fork failed");
+ exit(0);
+ }
+
+ if (pid == 0) {
+ /* the child */
+ /* get rid of those nasty err messages */
+ DPRINTF1("call_unmount_prog: calling %s \n",
+ "/usr/bin/volrmmount");
+
+ /* need the proc_exec privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
+ (char *)NULL);
+
+ /* volrmmount needs the sys_mount privilege */
+ (void) priv_set(PRIV_ON, PRIV_INHERITABLE, PRIV_SYS_MOUNT,
+ (char *)NULL);
+
+ /* Become root again for the exec */
+ if (seteuid(0) < 0) {
+ PERROR("Can't set effective user id to root");
+ }
+ if (execl("/usr/bin/volrmmount", "/usr/bin/volrmmount", "-e",
+ real_name, NULL) < 0) {
+ PERROR("volrmmount exec failed");
+ exit(-1);
+ }
+ } else if (waitpid(pid, &rval, 0) == pid) {
+ if (WIFEXITED(rval)) {
+ if (WEXITSTATUS(rval) == 0) {
+ DPRINTF("volrmmount: Success\n");
+ return (1);
+ }
+ }
+ }
+ return (-1);
+}
+
+int
+find_device(int defer, char *tmpstr)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ char sdev[PATH_MAX], dev[PATH_MAX], *pname;
+ device_t *t_dev;
+ int removable, device_type;
+ struct dk_minfo mediainfo;
+ static int found = 0;
+
+ dir = opendir("/dev/rdsk");
+ if (dir == NULL)
+ return (-1);
+
+ total_devices_found = 0;
+ while ((dirent = readdir(dir)) != NULL) {
+ if (dirent->d_name[0] == '.') {
+ continue;
+ }
+ (void) snprintf(sdev, PATH_MAX, "/dev/rdsk/%s",
+ dirent->d_name);
+#ifdef sparc
+ if (!strstr(sdev, "s2")) {
+ continue;
+ }
+#else /* x86 */
+ if (vol_running) {
+ if (!(strstr(sdev, "s2") || strstr(sdev, "p0"))) {
+ continue;
+ }
+ } else {
+ if (!strstr(sdev, "p0")) {
+ continue;
+ }
+ }
+#endif
+ if (!lookup_device(sdev, dev)) {
+ continue;
+ }
+ if ((t_dev = get_device(NULL, dev)) == NULL) {
+ continue;
+ }
+ total_devices_found++;
+
+ if ((!defer) && !found) {
+ char *sn, *tmpbuf;
+ /*
+ * dev_name is an optional command line input.
+ */
+ if (dev_name) {
+ if (strstr(dirent->d_name, tmpstr)) {
+ found = 1;
+ } else if (!vol_running) {
+ continue;
+ }
+ }
+ /*
+ * volmgt_symname() returns NULL if the device
+ * is not managed by volmgt.
+ */
+ sn = volmgt_symname(sdev);
+
+ if (vol_running && (sn != NULL)) {
+ if (strstr(sn, "dev") == NULL) {
+ tmpbuf = (char *)my_zalloc(PATH_MAX);
+ (void) strcpy(tmpbuf,
+ "/vol/dev/aliases/");
+ (void) strcat(tmpbuf, sn);
+ free(sn);
+ sn = tmpbuf;
+ }
+ if (dev_name && !found) {
+ if (!strstr(tmpbuf, tmpstr)) {
+ continue;
+ } else {
+ found = 1;
+ }
+ }
+ }
+
+ /*
+ * Get device type information for CD/DVD devices.
+ */
+ if (is_cd(dev)) {
+ if (check_device(t_dev,
+ CHECK_DEVICE_IS_DVD_WRITABLE)) {
+ device_type = DK_DVDR;
+ } else if (check_device(t_dev,
+ CHECK_DEVICE_IS_DVD_READABLE)) {
+ device_type = DK_DVDROM;
+ } else if (check_device(t_dev,
+ CHECK_DEVICE_IS_CD_WRITABLE)) {
+ device_type = DK_CDR;
+ } else {
+ device_type = DK_CDROM;
+ }
+ } else {
+ device_type = ioctl(t_dev->d_fd,
+ DKIOCGMEDIAINFO, &mediainfo);
+ if (device_type < 0)
+ device_type = 0;
+ else
+ device_type = mediainfo.dki_media_type;
+ }
+
+ if (!ioctl(t_dev->d_fd, DKIOCREMOVABLE, &removable)) {
+ if (removable) {
+ removable_found++;
+ pname = get_physical_name(sdev);
+ if (sn) {
+ (void) printf(" %4d. "
+ "Volmgt Node: %s\n",
+ removable_found, sn);
+ (void) printf(" "
+ "Logical Node: %s\n", sdev);
+ (void) printf(" "
+ "Physical Node: %s\n",
+ pname);
+ } else {
+ (void) printf(" %4d. "
+ "Logical Node: %s\n",
+ removable_found, sdev);
+ (void) printf(" "
+ "Physical Node: %s\n",
+ pname);
+ }
+ (void) printf(" Connected "
+ "Device: %-8.8s %-16.16s "
+ "%-4.4s\n",
+ &t_dev->d_inq[8],
+ &t_dev->d_inq[16],
+ &t_dev->d_inq[32]);
+ (void) printf(" Device "
+ "Type: ");
+ } else
+ continue;
+ } else
+ continue;
+
+ switch (device_type) {
+ case DK_CDROM:
+ (void) printf("CD Reader\n");
+ break;
+ case DK_CDR:
+ case DK_CDRW:
+ (void) printf("CD Reader/Writer\n");
+ break;
+ case DK_DVDROM:
+ (void) printf("DVD Reader\n");
+ break;
+ case DK_DVDR:
+ case DK_DVDRAM:
+ (void) printf("DVD Reader/Writer\n");
+ break;
+ case DK_FIXED_DISK:
+ if (strstr((const char *)
+ &t_dev->d_inq[16], "FD") ||
+ strstr((const char *)
+ &t_dev->d_inq[16], "LS-120"))
+ (void) printf("Floppy "
+ "drive\n");
+ else
+ (void) printf("Removable\n");
+ break;
+ case DK_FLOPPY:
+ (void) printf("Floppy drive\n");
+ break;
+ case DK_ZIP:
+ (void) printf("Zip drive\n");
+ break;
+ case DK_JAZ:
+ (void) printf("Jaz drive\n");
+ break;
+ default:
+ (void) printf("<Unknown>\n");
+ DPRINTF1("\t %d\n", device_type);
+ break;
+ }
+ get_media_info(t_dev, sdev, pname, sn);
+ }
+ fini_device(t_dev);
+ }
+
+ (void) closedir(dir);
+ return (removable_found);
+}
+
+/*
+ * Returns a device_t handle for a node returned by lookup_device()
+ * and takes the user supplied name and stores it inside the node.
+ */
+static device_t *
+get_device(char *user_supplied, char *node)
+{
+ device_t *dev;
+ int fd;
+ char devnode[PATH_MAX];
+ int size;
+
+ /*
+ * we need to resolve any link paths to avoid fake files
+ * such as /dev/rdsk/../../export/file.
+ */
+ size = resolvepath(node, devnode, PATH_MAX);
+ if ((size <= 0) || (size >= (PATH_MAX - 1)))
+ return (NULL);
+
+ /* resolvepath may not return a null terminated string */
+ devnode[size] = '\0';
+
+
+ /* the device node must be in /devices/ or /vol/dev/rdsk */
+
+ if ((strncmp(devnode, "/devices/", 9) != 0) &&
+ (strncmp(devnode, "/vol/dev/rdsk", 13) != 0))
+ return (NULL);
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ /*
+ * Since we are currently running with the user euid it is
+ * safe to try to open the file without checking access.
+ */
+
+ fd = open(devnode, O_RDONLY|O_NDELAY);
+
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ if (fd < 0) {
+ return (NULL);
+ }
+
+ dev = (device_t *)my_zalloc(sizeof (device_t));
+
+ dev->d_node = (char *)my_zalloc(strlen(devnode) + 1);
+ (void) strcpy(dev->d_node, devnode);
+
+ dev->d_fd = fd;
+
+ dev->d_inq = (uchar_t *)my_zalloc(INQUIRY_DATA_LENGTH);
+
+ if (!inquiry(fd, dev->d_inq)) {
+ DPRINTF1("USCSI ioctl failed %d\n",
+ uscsi_error);
+ free(dev->d_inq);
+ free(dev->d_node);
+ (void) close(dev->d_fd);
+ free(dev);
+ return (NULL);
+ }
+
+ if (user_supplied) {
+ dev->d_name = (char *)my_zalloc(strlen(user_supplied) + 1);
+ (void) strcpy(dev->d_name, user_supplied);
+ }
+ return (dev);
+}
+
+/*
+ * Check for device specific characteristics.
+ */
+int
+check_device(device_t *dev, int cond)
+{
+ uchar_t page_code[4];
+
+ /* Look at the capabilities page for this information */
+ if (cond & CHECK_DEVICE_IS_CD_WRITABLE) {
+ if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
+ (page_code[3] & 1)) {
+ return (1);
+ }
+ }
+
+ if (cond & CHECK_DEVICE_IS_DVD_WRITABLE) {
+ if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
+ (page_code[3] & 0x10)) {
+ return (1);
+ }
+ }
+
+ if (cond & CHECK_DEVICE_IS_DVD_READABLE) {
+ if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
+ (page_code[2] & 0x8)) {
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Builds an open()able device path from a user supplied node which can be
+ * of the * form of /dev/[r]dsk/cxtxdx[sx] or cxtxdx[sx] or volmgt-name like
+ * cdrom[n].
+ * Returns the path found in 'found' and returns 1. Otherwise returns 0.
+ */
+int
+lookup_device(char *supplied, char *found)
+{
+ struct stat statbuf;
+ int fd;
+ char tmpstr[PATH_MAX];
+
+ /* need the file_dac_read privilege */
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ /* If everything is fine and proper, no need to analyze */
+ if ((stat(supplied, &statbuf) == 0) && (statbuf.st_mode & S_IFCHR) &&
+ ((fd = open(supplied, O_RDONLY|O_NDELAY)) >= 0)) {
+ (void) close(fd);
+ (void) strlcpy(found, supplied, PATH_MAX);
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+ return (1);
+ }
+
+ /* drop the file_dac_read privilege */
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
+ (char *)NULL);
+
+ if (strncmp(supplied, "/dev/rdsk/", 10) == 0)
+ return (vol_lookup(supplied, found));
+ if (strncmp(supplied, "/dev/dsk/", 9) == 0) {
+ (void) snprintf(tmpstr, PATH_MAX, "/dev/rdsk/%s",
+ (char *)strrchr(supplied, '/'));
+
+ if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
+ (void) close(fd);
+ (void) strlcpy(found, supplied, PATH_MAX);
+ return (1);
+ }
+ if ((access(tmpstr, F_OK) == 0) && vol_running)
+ return (vol_lookup(tmpstr, found));
+ else
+ return (0);
+ }
+ if ((strncmp(supplied, "cdrom", 5) != 0) &&
+ (strlen(supplied) < 32)) {
+ (void) snprintf(tmpstr, sizeof (tmpstr), "/dev/rdsk/%s",
+ supplied);
+ if (access(tmpstr, F_OK) < 0) {
+ (void) strcat(tmpstr, "s2");
+ }
+ if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
+ (void) close(fd);
+ (void) strlcpy(found, tmpstr, PATH_MAX);
+ return (1);
+ }
+ if ((access(tmpstr, F_OK) == 0) && vol_running)
+ return (vol_lookup(tmpstr, found));
+ }
+ return (vol_name_to_dev_node(supplied, found));
+}
+
+int
+is_cd(char *node)
+{
+ int fd;
+ struct dk_cinfo cinfo;
+
+ fd = open(node, O_RDONLY|O_NDELAY);
+ if (fd < 0)
+ return (0);
+ if (ioctl(fd, DKIOCINFO, &cinfo) < 0) {
+ (void) close(fd);
+ return (0);
+ }
+ if (cinfo.dki_ctype != DKC_CDROM)
+ return (0);
+ return (1);
+}
+
+void
+print_header(void)
+{
+ /* l10n_NOTE : Column spacing should be kept same */
+ (void) printf(gettext(" Node "
+ "Connected Device"));
+ /* l10n_NOTE : Column spacing should be kept same */
+ (void) printf(gettext(" Device type\n"));
+ (void) printf(
+ "---------------------------+---------------------------");
+ (void) printf("-----+----------------\n");
+}
+
+void
+print_divider(void)
+{
+ (void) printf(
+ "---------------------------+---------------------------");
+ (void) printf("-----+----------------\n");
+}
+
+static void
+fini_device(device_t *dev)
+{
+ free(dev->d_inq);
+ free(dev->d_node);
+ (void) close(dev->d_fd);
+ if (dev->d_name)
+ free(dev->d_name);
+ free(dev);
+}
+
+void *
+my_zalloc(size_t size)
+{
+ void *ret;
+
+ ret = malloc(size);
+ if (ret == NULL) {
+
+ /* Lets wait a sec. and try again */
+ if (errno == EAGAIN) {
+ (void) sleep(1);
+ ret = malloc(size);
+ }
+
+ if (ret == NULL) {
+ (void) err_msg("%s\n", gettext(strerror(errno)));
+ (void) err_msg(gettext(
+ "Memory allocation failure, Exiting...\n"));
+ exit(1);
+ }
+ }
+ (void) memset(ret, 0, size);
+ return (ret);
+}
+
+static int
+vol_name_to_dev_node(char *vname, char *found)
+{
+ struct stat statbuf;
+ char *p1;
+ int i;
+
+ if (vname == NULL)
+ return (0);
+ if (vol_running)
+ (void) volmgt_check(vname);
+ p1 = media_findname(vname);
+ if (p1 == NULL)
+ return (0);
+ if (stat(p1, &statbuf) < 0) {
+ free(p1);
+ return (0);
+ }
+ if (statbuf.st_mode & S_IFDIR) {
+ for (i = 0; i < 16; i++) {
+ (void) snprintf(found, PATH_MAX, "%s/s%d", p1, i);
+ if (access(found, F_OK) >= 0)
+ break;
+ }
+ if (i == 16) {
+ free(p1);
+ return (0);
+ }
+ } else {
+ (void) strlcpy(found, p1, PATH_MAX);
+ }
+ free(p1);
+ return (1);
+}
+
+/*
+ * Searches for volume manager's equivalent char device for the
+ * supplied pathname which is of the form of /dev/rdsk/cxtxdxsx
+ */
+static int
+vol_lookup(char *supplied, char *found)
+{
+ char tmpstr[PATH_MAX], tmpstr1[PATH_MAX], *p;
+ int i, ret;
+
+ (void) strlcpy(tmpstr, supplied, PATH_MAX);
+ if ((p = volmgt_symname(tmpstr)) == NULL) {
+ if (strstr(tmpstr, "s2") != NULL) {
+ *((char *)(strrchr(tmpstr, 's') + 1)) = 0;
+ for (i = 0; i < 16; i++) {
+ (void) snprintf(tmpstr1, PATH_MAX, "%s%d",
+ tmpstr, i);
+ if ((p = volmgt_symname(tmpstr1)) != NULL)
+ break;
+ }
+ } else if (strstr(tmpstr, "p0") != NULL) {
+ *((char *)(strrchr(tmpstr, 'p') + 1)) = 0;
+ for (i = 0; i < 5; i++) {
+ (void) snprintf(tmpstr1, PATH_MAX, "%s%d",
+ tmpstr, i);
+ if ((p = volmgt_symname(tmpstr1)) != NULL)
+ break;
+ }
+ } else
+ return (0);
+ if (p == NULL)
+ return (0);
+ }
+
+ ret = vol_name_to_dev_node(p, found);
+ free(p);
+ return (ret);
+}
+
+/*PRINTFLIKE1*/
+void
+err_msg(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+int
+inquiry(int fd, uchar_t *inq)
+{
+ struct uscsi_cmd *scmd;
+
+ scmd = get_uscsi_cmd();
+ scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
+ scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
+ scmd->uscsi_cdb[0] = INQUIRY_CMD;
+ scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH;
+ scmd->uscsi_cdblen = 6;
+ scmd->uscsi_bufaddr = (char *)inq;
+ scmd->uscsi_buflen = INQUIRY_DATA_LENGTH;
+ if ((uscsi_error = uscsi(fd, scmd)) < 0)
+ return (0);
+ return (1);
+}
+
+struct uscsi_cmd *
+get_uscsi_cmd(void)
+{
+ (void) memset(&uscmd, 0, sizeof (uscmd));
+ (void) memset(ucdb, 0, 16);
+ uscmd.uscsi_cdb = ucdb;
+ return (&uscmd);
+}
+
+int
+uscsi(int fd, struct uscsi_cmd *scmd)
+{
+ int ret, global_rqsense;
+ int retries, max_retries = 5;
+ int i;
+
+ /* set up for request sense extensions */
+ if (!(scmd->uscsi_flags & USCSI_RQENABLE)) {
+ scmd->uscsi_flags |= USCSI_RQENABLE;
+ scmd->uscsi_rqlen = RQBUFLEN;
+ scmd->uscsi_rqbuf = rqbuf;
+ global_rqsense = 1;
+ } else {
+ global_rqsense = 0;
+ }
+
+ /*
+ * The device may be busy or slow and fail with a not ready status.
+ * we'll allow a limited number of retries to give the drive time
+ * to recover.
+ */
+ for (retries = 0; retries < max_retries; retries++) {
+
+ scmd->uscsi_status = 0;
+
+ if (global_rqsense)
+ (void) memset(rqbuf, 0, RQBUFLEN);
+
+ DPRINTF("cmd:[");
+ for (i = 0; i < scmd->uscsi_cdblen; i++)
+ DPRINTF1("0x%02x ",
+ (uchar_t)scmd->uscsi_cdb[i]);
+ DPRINTF("]\n");
+
+ /*
+ * We need to have root privledges in order to use
+ * uscsi commands on the device.
+ */
+
+ ret = ioctl(fd, USCSICMD, scmd);
+
+ /* maintain consistency in case of sgen */
+ if ((ret == 0) && (scmd->uscsi_status == 2)) {
+ ret = -1;
+ errno = EIO;
+ }
+
+ /* if error and extended request sense, retrieve errors */
+ if (global_rqsense && (ret < 0) && (scmd->uscsi_status == 2)) {
+ /*
+ * The drive is not ready to recieve commands but
+ * may be in the process of becoming ready.
+ * sleep for a short time then retry command.
+ * SENSE/ASC = 2/4 : not ready
+ * ASCQ = 0 Not Reportable.
+ * ASCQ = 1 Becoming ready.
+ */
+ if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
+ ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1))) {
+ total_retries++;
+ (void) sleep(3);
+ continue;
+ }
+
+ /*
+ * Device is not ready to transmit or a device reset
+ * has occurred. wait for a short period of time then
+ * retry the command.
+ */
+ if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
+ (ASC(rqbuf) == 0x29))) {
+ (void) sleep(3);
+ total_retries++;
+ continue;
+ }
+
+ DPRINTF3("cmd: 0x%02x ret:%i status:%02x ",
+ (uchar_t)scmd->uscsi_cdb[0], ret,
+ scmd->uscsi_status);
+ DPRINTF3(" sense: %02x ASC: %02x ASCQ:%02x\n",
+ (uchar_t)SENSE_KEY(rqbuf),
+ (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf));
+ }
+
+ /* no errors we'll return */
+ break;
+ }
+
+ /* store the error status for later debug printing */
+ if ((ret < 0) && (global_rqsense)) {
+ uscsi_status = scmd->uscsi_status;
+ rqstatus = scmd->uscsi_rqstatus;
+ rqresid = scmd->uscsi_rqresid;
+
+ }
+
+ DPRINTF1("total retries: %d\n", total_retries);
+
+ return (ret);
+}
+
+/*
+ * will get the mode page only i.e. will strip off the header.
+ */
+int
+get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer)
+{
+ int ret;
+ uchar_t byte2, *buf;
+ uint_t header_len, page_len, copy_cnt;
+
+ byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
+ buf = (uchar_t *)my_zalloc(256);
+
+ /* Ask 254 bytes only to make our IDE driver happy */
+ ret = mode_sense(fd, byte2, 1, 254, buf);
+ if (ret == 0) {
+ free(buf);
+ return (0);
+ }
+
+ header_len = 8 + read_scsi16(&buf[6]);
+ page_len = buf[header_len + 1] + 2;
+
+ copy_cnt = (page_len > buf_len) ? buf_len : page_len;
+ (void) memcpy(buffer, &buf[header_len], copy_cnt);
+ free(buf);
+
+ return (1);
+}
+
+int
+mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
+{
+ struct uscsi_cmd *scmd;
+
+ scmd = get_uscsi_cmd();
+ scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
+ scmd->uscsi_buflen = page_len;
+ scmd->uscsi_bufaddr = (char *)buffer;
+ scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
+ scmd->uscsi_cdblen = 0xa;
+ scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD;
+ if (dbd) {
+ /* don't return any block descriptors */
+ scmd->uscsi_cdb[1] = 0x8;
+ }
+ /* the page code we want */
+ scmd->uscsi_cdb[2] = pc;
+ /* allocation length */
+ scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
+ scmd->uscsi_cdb[8] = page_len & 0xff;
+
+ if ((uscsi_error = uscsi(fd, scmd)) < 0)
+ return (0);
+ return (1);
+}
+
+uint16_t
+read_scsi16(void *addr)
+{
+ uchar_t *ad = (uchar_t *)addr;
+ uint16_t ret;
+
+ ret = ((((uint16_t)ad[0]) << 8) | ad[1]);
+ return (ret);
+}
+
+/*
+ * Allocate space for and return a pointer to a string
+ * on the stack. If the string is null, create
+ * an empty string.
+ * Use destroy_data() to free when no longer used.
+ */
+char *
+alloc_string(s)
+ char *s;
+{
+ char *ns;
+
+ if (s == (char *)NULL) {
+ ns = (char *)my_zalloc(1);
+ } else {
+ ns = (char *)my_zalloc(strlen(s) + 1);
+ (void) strcpy(ns, s);
+ }
+ return (ns);
+}
+
+/*
+ * Follow symbolic links from the logical device name to
+ * the /devfs physical device name. To be complete, we
+ * handle the case of multiple links. This function
+ * either returns NULL (no links, or some other error),
+ * or the physical device name, alloc'ed on the heap.
+ *
+ * Note that the standard /devices prefix is stripped from
+ * the final pathname, if present. The trailing options
+ * are also removed (":c, raw").
+ */
+static char *
+get_physical_name(char *path)
+{
+ struct stat stbuf;
+ int i;
+ int level;
+ char *p;
+ char s[MAXPATHLEN];
+ char buf[MAXPATHLEN];
+ char dir[MAXPATHLEN];
+ char savedir[MAXPATHLEN];
+ char *result = NULL;
+
+ if (getcwd(savedir, sizeof (savedir)) == NULL) {
+ DPRINTF1("getcwd() failed - %s\n", strerror(errno));
+ return (NULL);
+ }
+
+ (void) strcpy(s, path);
+ if ((p = strrchr(s, '/')) != NULL) {
+ *p = 0;
+ }
+ if (s[0] == 0) {
+ (void) strcpy(s, "/");
+ }
+ if (chdir(s) == -1) {
+ DPRINTF2("cannot chdir() to %s - %s\n",
+ s, strerror(errno));
+ goto exit;
+ }
+
+ level = 0;
+ (void) strcpy(s, path);
+ for (;;) {
+ /*
+ * See if there's a real file out there. If not,
+ * we have a dangling link and we ignore it.
+ */
+ if (stat(s, &stbuf) == -1) {
+ goto exit;
+ }
+ if (lstat(s, &stbuf) == -1) {
+ DPRINTF2("%s: lstat() failed - %s\n",
+ s, strerror(errno));
+ goto exit;
+ }
+ /*
+ * If the file is not a link, we're done one
+ * way or the other. If there were links,
+ * return the full pathname of the resulting
+ * file.
+ */
+ if (!S_ISLNK(stbuf.st_mode)) {
+ if (level > 0) {
+ /*
+ * Strip trailing options from the
+ * physical device name
+ */
+ if ((p = strrchr(s, ':')) != NULL) {
+ *p = 0;
+ }
+ /*
+ * Get the current directory, and
+ * glue the pieces together.
+ */
+ if (getcwd(dir, sizeof (dir)) == NULL) {
+ DPRINTF1("getcwd() failed - %s\n",
+ strerror(errno));
+ goto exit;
+ }
+ (void) strcat(dir, "/");
+ (void) strcat(dir, s);
+ /*
+ * If we have the standard fixed
+ * /devices prefix, remove it.
+ */
+ p = (strstr(dir, DEVFS_PREFIX) == dir) ?
+ dir+strlen(DEVFS_PREFIX) : dir;
+ result = alloc_string(p);
+ }
+ goto exit;
+ }
+ i = readlink(s, buf, sizeof (buf));
+ if (i == -1) {
+ DPRINTF2("%s: readlink() failed - %s\n",
+ s, strerror(errno));
+ goto exit;
+ }
+ level++;
+ buf[i] = 0;
+
+ /*
+ * Break up the pathname into the directory
+ * reference, if applicable and simple filename.
+ * chdir()'ing to the directory allows us to
+ * handle links with relative pathnames correctly.
+ */
+ (void) strcpy(dir, buf);
+ if ((p = strrchr(dir, '/')) != NULL) {
+ *p = 0;
+ if (chdir(dir) == -1) {
+ DPRINTF2("cannot chdir() to %s - %s\n",
+ dir, strerror(errno));
+ goto exit;
+ }
+ (void) strcpy(s, p+1);
+ } else {
+ (void) strcpy(s, buf);
+ }
+ }
+
+exit:
+ if (chdir(savedir) == -1) {
+ (void) printf("cannot chdir() to %s - %s\n",
+ savedir, strerror(errno));
+ }
+
+ return (result);
+}
+
+static void
+get_media_info(device_t *t_dev, char *sdev, char *pname, char *sn)
+{
+ struct dk_cinfo cinfo;
+ struct vtoc vtocinfo;
+ float size;
+ int32_t fd;
+ smedia_handle_t handle;
+ struct dk_minfo mediainfo;
+ int device_type;
+
+ device_type = ioctl(t_dev->d_fd, DKIOCGMEDIAINFO, &mediainfo);
+
+ /*
+ * Determine bus type.
+ */
+ if (!ioctl(t_dev->d_fd, DKIOCINFO, &cinfo)) {
+ if (strstr(cinfo.dki_cname, "usb") || strstr(pname, "usb")) {
+ (void) printf("\tBus: USB\n");
+ } else if (strstr(cinfo.dki_cname, "firewire") ||
+ strstr(pname, "firewire")) {
+ (void) printf("\tBus: Firewire\n");
+ } else if (strstr(cinfo.dki_cname, "ide") ||
+ strstr(pname, "ide")) {
+ (void) printf("\tBus: IDE\n");
+ } else if (strstr(cinfo.dki_cname, "scsi") ||
+ strstr(pname, "scsi")) {
+ (void) printf("\tBus: SCSI\n");
+ } else {
+ (void) printf("\tBus: <Unknown>\n");
+ }
+ } else {
+ (void) printf("\tBus: <Unknown>\n");
+ }
+
+ /*
+ * Calculate size of media.
+ */
+ if (!device_type &&
+ (!ioctl(t_dev->d_fd, DKIOCGMEDIAINFO, &mediainfo))) {
+ size = (mediainfo.dki_lbsize*
+ mediainfo.dki_capacity)/(1024.0*1024.0);
+ if (size < 1000) {
+ (void) printf("\tSize: %.1f MB\n", size);
+ } else {
+ size = size/1000;
+ (void) printf("\tSize: %.1f GB\n", size);
+ }
+ } else {
+ (void) printf("\tSize: <Unknown>\n");
+ }
+
+ /*
+ * Print label.
+ */
+ if (!device_type && (!ioctl(t_dev->d_fd, DKIOCGVTOC, &vtocinfo))) {
+ if (*vtocinfo.v_volume) {
+ (void) printf("\tLabel: %s\n", vtocinfo.v_volume);
+ } else {
+ (void) printf("\tLabel: <None>\n");
+ }
+ } else {
+ (void) printf("\tLabel: <Unknown>\n");
+ }
+
+ /*
+ * Acess permissions.
+ */
+ if (device_type) {
+ (void) printf("\tAccess permissions: <Unknown>\n");
+ return;
+ }
+
+ (void) fprintf(stderr, gettext("\tAccess permissions: "));
+ if (sn) {
+ /*
+ * Set dev_name for process_p_flag().
+ */
+ dev_name = sn;
+ fd = my_open(sn, O_RDONLY|O_NDELAY);
+ } else {
+ dev_name = sdev;
+ fd = my_open(sdev, O_RDONLY|O_NDELAY);
+ }
+ if (fd < 0) {
+ (void) printf("<Unknown>\n");
+ DPRINTF("Could not open device.\n");
+ (void) close(fd);
+ } else {
+ /* register the fd with the libsmedia */
+ handle = smedia_get_handle(fd);
+ if (handle == NULL) {
+ (void) printf("<Unknown>\n");
+ DPRINTF("Failed to get libsmedia handle.\n");
+ (void) close(fd);
+ } else {
+ process_p_flag(handle, fd);
+ /* Clear dev_name */
+ dev_name = NULL;
+ }
+ }
+}