1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 *
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2014 Andrew Stormont.
26 */
27
28 /*
29 * rmf_misc.c :
30 * Miscelleneous routines for rmformat.
31 */
32
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <sys/mnttab.h>
36 #include <volmgt.h>
37 #include <sys/dkio.h>
38 #include <sys/fdio.h>
39 #include <sys/vtoc.h>
40 #include <sys/termios.h>
41 #include <sys/mount.h>
42 #include <ctype.h>
43 #include <signal.h>
44 #include <sys/wait.h>
45 #include <dirent.h>
46 #include <priv_utils.h>
47 #include <stdarg.h>
48 #include "rmformat.h"
49
50 /*
51 * Definitions.
52 */
53 #define SENSE_KEY(rqbuf) (rqbuf[2] & 0xf) /* scsi error category */
54 #define ASC(rqbuf) (rqbuf[12]) /* additional sense code */
55 #define ASCQ(rqbuf) (rqbuf[13]) /* ASC qualifier */
56
57 #define DEFAULT_SCSI_TIMEOUT 60
58 #define INQUIRY_CMD 0x12
59 #define RQBUFLEN 32
60 #define CD_RW 1 /* CD_RW/CD-R */
61 #define WRITE_10_CMD 0x2A
62 #define READ_INFO_CMD 0x51
63 #define SYNC_CACHE_CMD 0x35
64 #define CLOSE_TRACK_CMD 0x5B
65 #define MODE_SENSE_10_CMD 0x5A
66 #define DEVFS_PREFIX "/devices"
67
68 int uscsi_error; /* used for debugging failed uscsi */
69 char rqbuf[RQBUFLEN];
70 static uint_t total_retries;
71 static struct uscsi_cmd uscmd;
72 static char ucdb[16];
73 uchar_t uscsi_status, rqstatus, rqresid;
74 int total_devices_found = 0;
75 int removable_found = 0;
76
77 extern char *global_intr_msg;
78 extern int vol_running;
79 extern char *dev_name;
80 extern int32_t m_flag;
81
82 /*
83 * ON-private functions from libvolmgt
84 */
85 int _dev_mounted(char *path);
86
87 /*
88 * Function prototypes.
89 */
90 static int my_umount(char *mountp);
91 static int my_rmmount(char *real_name);
92 static int vol_name_to_dev_node(char *vname, char *found);
93 static int vol_lookup(char *supplied, char *found);
94 static device_t *get_device(char *user_supplied, char *node);
95 static char *get_physical_name(char *path);
96 static int lookup_device(char *supplied, char *found);
97 static void fini_device(device_t *dev);
98 static int is_cd(char *node);
99 void *my_zalloc(size_t size);
100 void err_msg(char *fmt, ...);
101 int inquiry(int fd, uchar_t *inq);
102 struct uscsi_cmd *get_uscsi_cmd(void);
103 int uscsi(int fd, struct uscsi_cmd *scmd);
104 int get_mode_page(int fd, int page_no, int pc, int buf_len,
105 uchar_t *buffer);
106 int mode_sense(int fd, uchar_t pc, int dbd, int page_len,
107 uchar_t *buffer);
108 uint16_t read_scsi16(void *addr);
109 int check_device(device_t *dev, int cond);
110 static void get_media_info(device_t *t_dev, char *sdev,
111 char *pname, char *sn);
112
113 extern void process_p_flag(smedia_handle_t handle, int32_t fd);
114
115 void
116 my_perror(char *err_string)
117 {
118
119 int error_no;
120 if (errno == 0)
121 return;
122
123 error_no = errno;
124 (void) fprintf(stderr, "%s", err_string);
125 (void) fprintf(stderr, gettext(" : "));
126 errno = error_no;
127 perror("");
128 }
129
130 int32_t
131 get_confirmation()
132 {
133 char c;
134
135 (void) fprintf(stderr, gettext("Do you want to continue? (y/n)"));
136 c = getchar();
137 if (c == 'y' || c == 'Y')
138 return (1);
139 else if (c == 'n' || c == 'N')
140 return (0);
141 else {
142 (void) fprintf(stderr, gettext("Invalid choice\n"));
143 return (0);
144 }
145 }
146
147
148 void
149 get_passwd(struct smwp_state *wp, int32_t confirm)
150 {
151 char passwd[256], re_passwd[256];
152 int32_t len;
153 struct termios tio;
154 int32_t echo_off = 0;
155 FILE *in, *out;
156 char *buf;
157
158
159 in = fopen("/dev/tty", "r+");
160 if (in == NULL) {
161 in = stdin;
162 out = stderr;
163 } else {
164 out = in;
165 }
166
167 /* Turn echoing off if it is on now. */
168
169 if (tcgetattr(fileno(in), &tio) < 0) {
170 PERROR("Echo off ioctl failed");
171 exit(1);
172 }
173 if (tio.c_lflag & ECHO) {
174 tio.c_lflag &= ~ECHO;
175 /* echo_off = tcsetattr(fileno(in), TCSAFLUSH, &tio) == 0; */
176 echo_off = tcsetattr(fileno(in), TCSAFLUSH, &tio) == 0;
177 tio.c_lflag |= ECHO;
178 }
179
180 /* CONSTCOND */
181 while (1) {
182 (void) fputs(
183 gettext("Please enter password (32 chars maximum):"),
184 out);
185 (void) fflush(out);
186 buf = fgets(passwd, (size_t)256, in);
187 rewind(in);
188 if (buf == NULL) {
189 PERROR("Error reading password");
190 continue;
191 }
192 len = strlen(passwd);
193 (void) fputc('\n', out);
194 len--; /* To offset the \n */
195 if ((len <= 0) || (len > 32)) {
196 (void) fprintf(stderr,
197 gettext("Invalid length of password \n"));
198 (void) fputs("Try again\n", out);
199 continue;
200 }
201
202 if (!confirm)
203 break;
204
205 (void) fputs("Please reenter password:", out);
206 (void) fflush(out);
207 buf = fgets(re_passwd, (size_t)256, in);
208 rewind(in);
209 (void) fputc('\n', out);
210 if ((buf == NULL) || strcmp(passwd, re_passwd)) {
211 (void) fputs("passwords did not match\n", out);
212 (void) fputs("Try again\n", out);
213 } else {
214 break;
215 }
216 }
217 wp->sm_passwd_len = len;
218 (void) strncpy(wp->sm_passwd, passwd, wp->sm_passwd_len);
219 wp->sm_version = SMWP_STATE_V_1;
220
221 /* Restore echoing. */
222 if (echo_off)
223 (void) tcsetattr(fileno(in), TCSAFLUSH, &tio);
224
225 }
226
227 int32_t
228 check_and_unmount_vold(char *device_name, int32_t flag)
229 {
230 char *real_name;
231 char *nm;
232 char tmp_path_name[PATH_MAX];
233 struct stat stat_buf;
234 int32_t ret_val = 0;
235 struct mnttab *mntp;
236 FILE *fp;
237 int nl;
238
239 DPRINTF1("Device name %s\n", device_name);
240
241 if (volmgt_running() == 0) {
242 DPRINTF("Vold not running\n");
243 return (0);
244 }
245 if ((nm = volmgt_symname(device_name)) == NULL) {
246 DPRINTF("path not managed\n");
247 real_name = media_findname(device_name);
248 } else {
249 DPRINTF1("path managed as %s\n", nm);
250 real_name = media_findname(nm);
251 DPRINTF1("real name %s\n", real_name);
252 }
253
254 if (real_name == NULL)
255 return (-1);
256
257 /*
258 * To find out whether the device has been mounted by
259 * volume manager...
260 *
261 * Convert the real name to a block device address.
262 * Do a partial match with the mnttab entries.
263 * Make sure the match is in the beginning to avoid if
264 * anybody puts a label similiar to volume manager path names.
265 * Then use "rmmount -u <dev_name>" if -U flag is set.
266 */
267
268 nl = strlen("/vol/dev/");
269
270 if (strncmp(real_name, "/vol/dev/", nl) != 0)
271 return (0);
272 if (real_name[nl] == 'r') {
273 (void) snprintf(tmp_path_name, PATH_MAX, "%s%s", "/vol/dev/",
274 &real_name[nl + 1]);
275 } else {
276 (void) snprintf(tmp_path_name, PATH_MAX, "%s", real_name);
277 }
278 DPRINTF1("%s \n", tmp_path_name);
279 ret_val = stat(tmp_path_name, &stat_buf);
280 if (ret_val < 0) {
281 PERROR("Could not stat");
282 return (-1);
283 }
284
285 fp = fopen("/etc/mnttab", "r");
286
287 if (fp == NULL) {
288 PERROR("Could not open /etc/mnttab");
289 return (-1);
290 }
291
292 mntp = (struct mnttab *)malloc(sizeof (struct mnttab));
293 if (mntp == NULL) {
294 PERROR("malloc failed");
295 (void) fclose(fp);
296 return (-1);
297 }
298 errno = 0;
299 while (getmntent(fp, mntp) == 0) {
300 if (errno != 0) {
301 PERROR("Error with mnttab");
302 (void) fclose(fp);
303 return (-1);
304 }
305 /* Is it a probable entry? */
306 DPRINTF1(" %s \n", mntp->mnt_special);
307 if (strstr(mntp->mnt_special, tmp_path_name) !=
308 mntp->mnt_special) {
309 /* Skip to next entry */
310 continue;
311 } else {
312 DPRINTF1("Found!! %s\n", mntp->mnt_special);
313 ret_val = 1;
314 break;
315 }
316 }
317
318 if (ret_val == 1) {
319 if (flag) {
320 if (my_rmmount(real_name) < 0) {
321 ret_val = -1;
322 }
323 } else {
324 ret_val = -1;
325 }
326 }
327 (void) fclose(fp);
328 free(mntp);
329 return (ret_val);
330 }
331
332 /*
333 * This routine checks if a device has mounted partitions. The
334 * device name is assumed to be /dev/rdsk/cNtNdNsN. So, this can
335 * be used for SCSI and PCMCIA cards.
336 * Returns
337 * 0 : if not mounted
338 * 1 : if successfully unmounted
339 * -1 : Any error or umount failed
340 */
341
342 int32_t
343 check_and_unmount_scsi(char *device_name, int32_t flag)
344 {
345
346 struct mnttab *mntrefp;
347 struct mnttab *mntp;
348 FILE *fp;
349 char block_dev_name[PATH_MAX];
350 char tmp_name[PATH_MAX];
351 int32_t i, j;
352 int32_t unmounted = 0;
353
354 /*
355 * If the device name is not a character special, anyway we
356 * can not progress further
357 */
358
359 if (strncmp(device_name, "/dev/rdsk/c", strlen("/dev/rdsk/c")) != 0)
360 return (0);
361
362 (void) snprintf(block_dev_name, PATH_MAX, "/dev/%s",
363 &device_name[strlen("/dev/r")]);
364 fp = fopen("/etc/mnttab", "r");
365
366 if (fp == NULL) {
367 PERROR("Could not open /etc/mnttab");
368 return (-1);
369 }
370
371 mntrefp = (struct mnttab *)malloc(sizeof (struct mnttab));
372 if (mntrefp == NULL) {
373 PERROR("malloc failed");
374 (void) fclose(fp);
375 return (-1);
376 }
377
378 mntp = (struct mnttab *)malloc(sizeof (struct mnttab));
379 if (mntp == NULL) {
380 PERROR("malloc failed");
381 (void) fclose(fp);
382 free(mntrefp);
383 return (-1);
384 }
385
386 /* Try all the partitions */
387
388 (void) snprintf(tmp_name, PATH_MAX, "/dev/%s",
389 &device_name[strlen("/dev/r")]);
390
391 tmp_name[strlen("/dev/dsk/c0t0d0s")] = '\0';
392
393 errno = 0;
394 while (getmntent(fp, mntp) == 0) {
395 if (errno != 0) {
396 PERROR("Error with mnttab");
397 (void) fclose(fp);
398 return (-1);
399 }
400 /* Is it a probable entry? */
401 if (strncmp(mntp->mnt_special, tmp_name, strlen(tmp_name))) {
402 /* Skip to next entry */
403 continue;
404 }
405 for (i = 0; i < NDKMAP; i++) {
406 /* Check for ufs style mount devices */
407 (void) snprintf(block_dev_name, PATH_MAX,
408 "%s%d", tmp_name, i);
409
410 if (strcmp(mntp->mnt_special, block_dev_name) == 0) {
411 if (flag) {
412 if (my_umount(mntp->mnt_mountp) < 0) {
413 (void) fclose(fp);
414 return (-1);
415 }
416 unmounted = 1;
417 } else {
418 (void) fclose(fp);
419 return (-1);
420 }
421 /* Skip to next entry */
422 continue;
423 }
424
425 /* Try for :1 -> :24 for pcfs */
426
427 for (j = 1; j < 24; j++) {
428 (void) snprintf(block_dev_name, PATH_MAX,
429 "%s%d:%d", tmp_name, i, j);
430
431 if (strcmp(mntp->mnt_special,
432 block_dev_name) == 0) {
433 if (flag) {
434 if (my_umount(mntp->mnt_mountp)
435 < 0) {
436 (void) fclose(fp);
437 return (-1);
438 }
439 unmounted = 1;
440 } else {
441 (void) fclose(fp);
442 return (-1);
443 }
444 /* Skip to next entry */
445 continue;
446 }
447 (void) snprintf(block_dev_name, PATH_MAX,
448 "%s%d:%c", tmp_name, i, 'b' + j);
449
450 if (strcmp(mntp->mnt_special,
451 block_dev_name) == 0) {
452 if (flag) {
453 if (my_umount(mntp->mnt_mountp)
454 < 0) {
455 (void) fclose(fp);
456 return (-1);
457 }
458 unmounted = 1;
459 } else {
460 (void) fclose(fp);
461 return (-1);
462 }
463 /* Skip to next entry */
464 continue;
465 }
466 }
467 }
468
469 }
470
471 if (unmounted)
472 return (1);
473 return (0);
474 }
475
476 /*
477 * This routine checks if a device has mounted partitions. The
478 * device name is assumed to be /dev/rdiskette. So, this can
479 * be used for Floppy controllers
480 * Returns
481 * 0 : if not mounted
482 * 1 : if successfully unmounted
483 * -1 : Any error or unmount failed
484 */
485
486 int32_t
487 check_and_unmount_floppy(int32_t fd, int32_t flag)
488 {
489 FILE *fp = NULL;
490 int32_t mfd;
491 struct dk_cinfo dkinfo, dkinfo_tmp;
492 struct mnttab mnt_record;
493 struct mnttab *mp = &mnt_record;
494 struct stat stbuf;
495 char raw_device[PATH_MAX];
496 int32_t found = 0;
497
498
499 if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
500 return (-1);
501 }
502
503 if ((fp = fopen(MNTTAB, "r")) == NULL) {
504 PERROR("Could not open /etc/mnttab");
505 (void) close(fd);
506 exit(3);
507 }
508
509 while (getmntent(fp, mp) == 0) {
510 if (strstr(mp->mnt_special, "/dev/fd") == NULL &&
511 strstr(mp->mnt_special, "/dev/disket") == NULL &&
512 strstr(mp->mnt_special, "/dev/c") == NULL) {
513 continue;
514 }
515
516 (void) strcpy(raw_device, "/dev/r");
517 (void) strcat(raw_device, mp->mnt_special + strlen("/dev/"));
518
519
520 /*
521 * Attempt to open the device. If it fails, skip it.
522 */
523
524 /* Turn on the privileges. */
525 (void) __priv_bracket(PRIV_ON);
526
527 mfd = open(raw_device, O_RDWR | O_NDELAY);
528
529 /* Turn off the privileges. */
530 (void) __priv_bracket(PRIV_OFF);
531
532 if (mfd < 0) {
533 continue;
534 }
535
536 /*
537 * Must be a character device
538 */
539 if (fstat(mfd, &stbuf) < 0 || !S_ISCHR(stbuf.st_mode)) {
540 (void) close(mfd);
541 continue;
542 }
543 /*
544 * Attempt to read the configuration info on the disk.
545 */
546 if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) {
547 (void) close(mfd);
548 continue;
549 }
550 /*
551 * Finished with the opened device
552 */
553 (void) close(mfd);
554
555 /*
556 * If it's not the disk we're interested in, it doesn't apply.
557 */
558 if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype ||
559 dkinfo.dki_cnum != dkinfo_tmp.dki_cnum ||
560 dkinfo.dki_unit != dkinfo_tmp.dki_unit) {
561 continue;
562 }
563 /*
564 * It's a mount on the disk we're checking. If we are
565 * checking whole disk, then we found trouble. We can
566 * quit searching.
567 */
568
569 if (flag) {
570 if (my_umount(mp->mnt_mountp) < 0) {
571 return (-1);
572 }
573 found = 1;
574 } else {
575 return (-1);
576 }
577 }
578 return (found);
579 }
580
581
582 int32_t
583 my_open(char *device_name, int32_t flags)
584 {
585 char *real_name;
586 char *nm;
587 char tmp_path_name[PATH_MAX];
588 struct stat stat_buf;
589 int32_t ret_val;
590 int32_t fd;
591 int32_t have_read_priv = 0;
592 DIR *dirp;
593 struct dirent *dp;
594
595 DPRINTF1("Device name %s\n", device_name);
596
597 if ((nm = volmgt_symname(device_name)) == NULL) {
598 DPRINTF("path not managed\n");
599 real_name = media_findname(device_name);
600 } else {
601 DPRINTF1("path managed as %s\n", nm);
602 real_name = media_findname(nm);
603 DPRINTF1("real name %s\n", real_name);
604 }
605
606 if (real_name == NULL)
607 return (-1);
608
609 (void) strcpy(tmp_path_name, real_name);
610 ret_val = stat(tmp_path_name, &stat_buf);
611 if (ret_val < 0) {
612 PERROR("Could not stat");
613 return (-1);
614 }
615 if (S_ISDIR(stat_buf.st_mode)) {
616
617 /*
618 * Open the directory and look for the
619 * first non '.' entry.
620 * Since raw_read and raw_writes are used, we don't
621 * need to access the backup slice.
622 * For PCMCIA Memory cards, raw_read and raw_writes are
623 * not supported, but that is not a problem as, only slice2
624 * is allowed on PCMCIA memory cards.
625 */
626
627 /*
628 * First make sure we are operating with a /vol/....
629 * Otherwise it can dangerous,
630 * e.g. rmformat -s /dev/rdsk
631 * We should not look into the directory contents here.
632 */
633 if (strncmp(tmp_path_name, "/vol/dev/", strlen("/vol/dev/"))
634 != 0) {
635 (void) fprintf(stderr, gettext("The specified device \
636 is not a raw device.\n"));
637 exit(1);
638 }
639
640 /* Turn on the privileges. */
641 (void) __priv_bracket(PRIV_ON);
642
643 dirp = opendir(tmp_path_name);
644
645 /* Turn off the privileges. */
646 (void) __priv_bracket(PRIV_OFF);
647
648 if (dirp == NULL) {
649 return (-1);
650 }
651
652 /* Turn on the privileges. */
653 (void) __priv_bracket(PRIV_ON);
654 have_read_priv = 1;
655
656 while ((dp = readdir(dirp)) != NULL) {
657
658 /* Turn off the privileges. */
659 (void) __priv_bracket(PRIV_OFF);
660 have_read_priv = 0;
661
662 DPRINTF1("Found %s\n", dp->d_name);
663 if ((strcmp(dp->d_name, ".") != 0) &&
664 (strcmp(dp->d_name, "..") != 0)) {
665 (void) snprintf(tmp_path_name, PATH_MAX,
666 "%s/%s", tmp_path_name, dp->d_name);
667
668 DPRINTF1("tmp_pathname is %s\n", tmp_path_name);
669 break;
670 }
671
672 /* Turn on the privileges. */
673 (void) __priv_bracket(PRIV_ON);
674 have_read_priv = 1;
675 }
676
677 if (have_read_priv) {
678 /* drop the file_dac_read privilege */
679 (void) __priv_bracket(PRIV_OFF);
680 have_read_priv = 0;
681 }
682
683 (void) closedir(dirp);
684 }
685
686
687 if (volmgt_running() == 0) {
688 /* Turn on privileges. */
689 (void) __priv_bracket(PRIV_ON);
690 have_read_priv = 1;
691 }
692
693 fd = open(tmp_path_name, flags);
694
695 if (have_read_priv) {
696 /* Turn off privileges. */
697 (void) __priv_bracket(PRIV_OFF);
698 have_read_priv = 0;
699 }
700
701 DPRINTF1("path opened %s\n", tmp_path_name);
702
703 return (fd);
704 }
705
706 uint64_t
707 my_atoll(char *ptr)
708 {
709 char *tmp_ptr = ptr;
710 int32_t base = 10;
711 uint64_t ret_val;
712
713 while (*tmp_ptr) {
714 if (isdigit(*tmp_ptr))
715 tmp_ptr++;
716 else {
717 base = 16;
718 break;
719 }
720 }
721 tmp_ptr = ptr;
722 if (base == 16) {
723 if (strlen(tmp_ptr) < 3) {
724 return (-1);
725 }
726 if (*tmp_ptr++ != '0' || (*tmp_ptr != 'x' && *tmp_ptr != 'X')) {
727 return (-1);
728 }
729 tmp_ptr++;
730 while (*tmp_ptr) {
731 if (isxdigit(*tmp_ptr))
732 tmp_ptr++;
733 else {
734 return (-1);
735 }
736 }
737 }
738 ret_val = (uint64_t)strtoull(ptr, (char **)NULL, 0);
739 return (ret_val);
740 }
741
742 int32_t
743 write_sunos_label(int32_t fd, int32_t media_type)
744 {
745
746 struct extvtoc v_toc;
747 int32_t ret;
748
749 (void) memset(&v_toc, 0, sizeof (struct extvtoc));
750
751 /* Initialize the vtoc information */
752
753 if (media_type == SM_FLOPPY) {
754 struct fd_char fdchar;
755 int32_t mult_factor;
756
757 if (ioctl(fd, FDIOGCHAR, &fdchar) < 0) {
758 PERROR("FDIOGCHAR failed");
759 return (-1);
760 }
761
762 /* SPARC and x86 fd drivers use fdc_medium differently */
763 #if defined(__sparc)
764 mult_factor = (fdchar.fdc_medium) ? 2 : 1;
765 #elif defined(__x86)
766 mult_factor = (fdchar.fdc_medium == 5) ? 2 : 1;
767 #else
768 #error No Platform defined
769 #endif /* defined(__sparc) */
770
771 /* initialize the vtoc structure */
772 v_toc.v_nparts = 3;
773
774 v_toc.v_part[0].p_start = 0;
775 v_toc.v_part[0].p_size = (fdchar.fdc_ncyl - 1) * 2 *
776 fdchar.fdc_secptrack * mult_factor;
777 v_toc.v_part[1].p_start = (fdchar.fdc_ncyl - 1) * 2 *
778 fdchar.fdc_secptrack * mult_factor;
779 v_toc.v_part[1].p_size = 2 * fdchar.fdc_secptrack * mult_factor;
780
781 v_toc.v_part[2].p_start = 0;
782 v_toc.v_part[2].p_size = fdchar.fdc_ncyl * 2 *
783 fdchar.fdc_secptrack * mult_factor;
784
785 } else if (media_type == SM_SCSI_FLOPPY) {
786
787 smedia_handle_t handle;
788 smmedium_prop_t med_info;
789 struct dk_geom dkgeom;
790
791
792 /*
793 * call smedia_get_medium_property to get the
794 * correct media information, since DKIOCGMEDIAINFO
795 * may fail for unformatted media.
796 */
797
798 handle = smedia_get_handle(fd);
799 if (handle == NULL) {
800 (void) fprintf(stderr,
801 gettext("Failed to get libsmedia handle.\n"));
802
803 (void) close(fd);
804 return (-1);
805 }
806
807
808 if (smedia_get_medium_property(handle, &med_info) < 0) {
809 (void) fprintf(stderr,
810 gettext("Get medium property failed \n"));
811
812 (void) smedia_release_handle(handle);
813 (void) close(fd);
814 return (-1);
815 }
816
817 /* Fill in our own geometry information */
818
819 dkgeom.dkg_pcyl = med_info.sm_pcyl;
820 dkgeom.dkg_ncyl = med_info.sm_pcyl;
821 dkgeom.dkg_nhead = med_info.sm_nhead;
822 dkgeom.dkg_nsect = med_info.sm_nsect;
823 dkgeom.dkg_acyl = 0;
824 dkgeom.dkg_bcyl = 0;
825 dkgeom.dkg_intrlv = 0;
826 dkgeom.dkg_apc = 0;
827
828 /*
829 * Try to set vtoc, if not successful we will
830 * continue to use the faked geometry information.
831 */
832
833 (void) ioctl(fd, DKIOCSGEOM, &dkgeom);
834
835 (void) smedia_release_handle(handle);
836
837 /* we want the same partitioning as used for normal floppies */
838
839 v_toc.v_part[0].p_start = 0;
840 v_toc.v_part[0].p_size = (diskaddr_t)(dkgeom.dkg_ncyl - 1) *
841 dkgeom.dkg_nhead * dkgeom.dkg_nsect;
842
843 v_toc.v_part[1].p_start = (diskaddr_t)(dkgeom.dkg_ncyl - 1) *
844 dkgeom.dkg_nhead * dkgeom.dkg_nsect;
845 v_toc.v_part[1].p_size = dkgeom.dkg_nhead * dkgeom.dkg_nsect;
846
847 v_toc.v_part[2].p_start = 0;
848 v_toc.v_part[2].p_size = (diskaddr_t)dkgeom.dkg_ncyl *
849 dkgeom.dkg_nhead * dkgeom.dkg_nsect;
850
851 /* both write_vtoc and DKIOCSVTOC require V_NUMPAR partitions */
852 v_toc.v_nparts = V_NUMPAR;
853
854 } else {
855
856 return (0);
857 }
858
859 v_toc.v_sanity = VTOC_SANE;
860 v_toc.v_version = V_VERSION;
861
862 /*
863 * The label structure is set up for DEV_BSIZE(512 byte) blocks,
864 * even though a medium density diskette has 1024 byte blocks
865 * See dklabel.h for more details.
866 */
867 v_toc.v_sectorsz = DEV_BSIZE;
868
869 /* let the fd driver finish constructing the label and writing it. */
870
871
872 /* Turn on the privileges. */
873 (void) __priv_bracket(PRIV_ON);
874
875 ret = write_extvtoc(fd, &v_toc);
876
877 /* Turn off the privileges. */
878 (void) __priv_bracket(PRIV_OFF);
879
880 if (ret < 0) {
881 PERROR("Write vtoc");
882 DPRINTF1("Write vtoc failed errno:%d\n", errno);
883 return (-1);
884 }
885
886 return (0);
887 }
888
889 static void
890 intr_sig_handler()
891 {
892 char c;
893
894 (void) fprintf(stderr, gettext(global_intr_msg));
895 (void) fprintf(stderr,
896 gettext("\nDo you want to stop formatting?(y/n)"));
897 (void) fflush(stdout);
898 rewind(stdin);
899 while ((c = getchar()) == -1)
900 ;
901 if (c == 'y' || c == 'Y') {
902 (void) fprintf(stderr, gettext("Format interrupted\n"));
903 exit(1);
904 } else if (c == 'n' || c == 'N')
905 return;
906 else {
907 (void) fprintf(stderr, gettext("Did not interrupt\n"));
908 return;
909 }
910 }
911
912 static struct sigaction act, oact;
913 void
914 trap_SIGINT()
915 {
916
917 act.sa_handler = intr_sig_handler;
918 (void) memset(&act.sa_mask, 0, sizeof (sigset_t));
919 act.sa_flags = SA_RESTART; /* | SA_NODEFER; */
920 if (sigaction(SIGINT, &act, &oact) < 0) {
921 DPRINTF("sigset failed\n");
922 return;
923 }
924 }
925
926 void
927 release_SIGINT()
928 {
929 if (sigaction(SIGINT, &oact, (struct sigaction *)NULL) < 0) {
930 DPRINTF("sigunset failed\n");
931 return;
932 }
933 }
934
935 int32_t
936 verify(smedia_handle_t handle, int32_t fd, diskaddr_t start_sector,
937 uint32_t nblocks, char *buf,
938 int32_t flag, int32_t blocksize, int32_t no_raw_rw)
939 {
940 uint64_t ret;
941
942 DPRINTF("ANALYSE MEDIA \n");
943
944
945 if ((flag == VERIFY_READ) && (!no_raw_rw)) {
946
947 /* Turn on the privileges. */
948 (void) __priv_bracket(PRIV_ON);
949
950 ret = smedia_raw_read(handle, start_sector, buf, nblocks *
951 blocksize);
952
953 /* Turn off the privileges. */
954 (void) __priv_bracket(PRIV_OFF);
955
956 if (ret != (nblocks * blocksize))
957 return (-1);
958 return (0);
959
960 } else if ((flag == VERIFY_WRITE) && (!no_raw_rw)) {
961
962 /* Turn on privileges. */
963 (void) __priv_bracket(PRIV_ON);
964
965 ret = smedia_raw_write(handle, start_sector, buf, nblocks *
966 blocksize);
967
968 /* Turn off the privileges. */
969 (void) __priv_bracket(PRIV_OFF);
970
971 if (ret != (blocksize * nblocks))
972 return (-1);
973 return (0);
974
975 } else if ((flag == VERIFY_READ) && (no_raw_rw)) {
976 ret = llseek(fd, start_sector * blocksize, SEEK_SET);
977 if (ret != start_sector * blocksize) {
978 (void) fprintf(stderr, gettext("Seek failed\n"));
979 return (-2);
980 }
981
982 /* Turn on the privileges. */
983 (void) __priv_bracket(PRIV_ON);
984
985 ret = read(fd, buf, nblocks * blocksize);
986
987 /* Turn off the privileges. */
988 (void) __priv_bracket(PRIV_OFF);
989
990 if (ret != nblocks * blocksize) {
991 return (-1);
992 }
993 return (0);
994 } else if ((flag == VERIFY_WRITE) && (no_raw_rw)) {
995 ret = llseek(fd, start_sector * blocksize, SEEK_SET);
996 if (ret != start_sector * blocksize) {
997 (void) fprintf(stderr, gettext("Seek failed\n"));
998 return (-2);
999 }
1000
1001 /* Turn on the privileges. */
1002 (void) __priv_bracket(PRIV_ON);
1003
1004 ret = write(fd, buf, nblocks * blocksize);
1005
1006 /* Turn off the privileges. */
1007 (void) __priv_bracket(PRIV_OFF);
1008
1009 if (ret != nblocks * blocksize) {
1010 return (-1);
1011 }
1012 return (0);
1013 } else {
1014 DPRINTF("Illegal parameter to verify_analysis!\n");
1015 return (-1);
1016 }
1017 }
1018
1019 static int
1020 my_umount(char *mountp)
1021 {
1022 pid_t pid; /* forked proc's pid */
1023 int rval; /* proc's return value */
1024
1025
1026 /* create a child to unmount the path */
1027
1028 /* Turn on the privileges */
1029 (void) __priv_bracket(PRIV_ON);
1030
1031 pid = fork();
1032
1033 /* Turn off the privileges. */
1034 (void) __priv_bracket(PRIV_OFF);
1035
1036 if (pid < 0) {
1037 PERROR("fork failed");
1038 exit(0);
1039 }
1040
1041 if (pid == 0) {
1042 /* the child */
1043 /* get rid of those nasty err messages */
1044 DPRINTF1("call_unmount_prog: calling %s \n", mountp);
1045
1046 /* Turn on the priviliges. */
1047 (void) __priv_bracket(PRIV_ON);
1048
1049 if (execl("/usr/sbin/umount", "/usr/sbin/umount", mountp,
1050 NULL) < 0) {
1051 perror("exec failed");
1052 /* Turn off the privileges */
1053 (void) __priv_bracket(PRIV_OFF);
1054 exit(-1);
1055 }
1056 }
1057
1058 /* wait for the umount command to exit */
1059 rval = 0;
1060 if (waitpid(pid, &rval, 0) == pid) {
1061 if (WIFEXITED(rval)) {
1062 if (WEXITSTATUS(rval) == 0) {
1063 DPRINTF("umount : Success\n");
1064 return (1);
1065 }
1066 }
1067 }
1068 return (-1);
1069 }
1070
1071 static int
1072 my_rmmount(char *real_name)
1073 {
1074 int pid, rval;
1075
1076 /* Turn on the privileges. */
1077 (void) __priv_bracket(PRIV_ON);
1078
1079 pid = fork();
1080
1081 /* Turn off the privileges. */
1082 (void) __priv_bracket(PRIV_OFF);
1083
1084 /* create a child to unmount the path */
1085 if (pid < 0) {
1086 PERROR("fork failed");
1087 exit(0);
1088 }
1089
1090 if (pid == 0) {
1091 /* the child */
1092 /* get rid of those nasty err messages */
1093 DPRINTF1("call_unmount_prog: calling %s\n",
1094 "/usr/bin/rmmount");
1095
1096 /* Turn on the privileges. */
1097 (void) __priv_bracket(PRIV_ON);
1098 if (execl("/usr/bin/rmmount", "/usr/bin/rmmount", "-u",
1099 real_name, NULL) < 0) {
1100 PERROR("rmmount exec failed");
1101 /* Turn off the privileges */
1102 (void) __priv_bracket(PRIV_OFF);
1103 exit(-1);
1104 }
1105 } else if (waitpid(pid, &rval, 0) == pid) {
1106 if (WIFEXITED(rval)) {
1107 if (WEXITSTATUS(rval) == 0) {
1108 DPRINTF("rmmount: Success\n");
1109 return (1);
1110 }
1111 }
1112 }
1113 return (-1);
1114 }
1115
1116 int
1117 find_device(int defer, char *tmpstr)
1118 {
1119 DIR *dir;
1120 struct dirent *dirent;
1121 char sdev[PATH_MAX], dev[PATH_MAX], *pname;
1122 device_t *t_dev;
1123 int removable = 0;
1124 int device_type = 0;
1125 int hotpluggable = 0;
1126 struct dk_minfo mediainfo;
1127 static int found = 0;
1128
1129 dir = opendir("/dev/rdsk");
1130 if (dir == NULL)
1131 return (-1);
1132
1133 total_devices_found = 0;
1134 while ((dirent = readdir(dir)) != NULL) {
1135 if (dirent->d_name[0] == '.') {
1136 continue;
1137 }
1138 (void) snprintf(sdev, PATH_MAX, "/dev/rdsk/%s",
1139 dirent->d_name);
1140 #ifdef sparc
1141 if (!strstr(sdev, "s2")) {
1142 continue;
1143 }
1144 #else /* x86 */
1145 if (vol_running) {
1146 if (!(strstr(sdev, "s2") || strstr(sdev, "p0"))) {
1147 continue;
1148 }
1149 } else {
1150 if (!strstr(sdev, "p0")) {
1151 continue;
1152 }
1153 }
1154 #endif
1155 if (!lookup_device(sdev, dev)) {
1156 continue;
1157 }
1158 if ((t_dev = get_device(NULL, dev)) == NULL) {
1159 continue;
1160 }
1161 total_devices_found++;
1162
1163 if ((!defer) && !found) {
1164 char *sn, *tmpbuf = NULL;
1165 /*
1166 * dev_name is an optional command line input.
1167 */
1168 if (dev_name) {
1169 if (strstr(dirent->d_name, tmpstr)) {
1170 found = 1;
1171 } else if (!vol_running) {
1172 continue;
1173 }
1174 }
1175 /*
1176 * volmgt_symname() returns NULL if the device
1177 * is not managed by volmgt.
1178 */
1179 sn = volmgt_symname(sdev);
1180
1181 if (vol_running && (sn != NULL)) {
1182 if (strstr(sn, "dev") == NULL) {
1183 tmpbuf = (char *)my_zalloc(PATH_MAX);
1184 (void) strcpy(tmpbuf,
1185 "/vol/dev/aliases/");
1186 (void) strcat(tmpbuf, sn);
1187 free(sn);
1188 sn = tmpbuf;
1189 }
1190 if (dev_name && !found) {
1191 if (!strstr(tmpbuf, tmpstr)) {
1192 continue;
1193 } else {
1194 found = 1;
1195 }
1196 }
1197 }
1198
1199 /*
1200 * Get device type information for CD/DVD devices.
1201 */
1202 if (is_cd(dev)) {
1203 if (check_device(t_dev,
1204 CHECK_DEVICE_IS_DVD_WRITABLE)) {
1205 device_type = DK_DVDR;
1206 } else if (check_device(t_dev,
1207 CHECK_DEVICE_IS_DVD_READABLE)) {
1208 device_type = DK_DVDROM;
1209 } else if (check_device(t_dev,
1210 CHECK_DEVICE_IS_CD_WRITABLE)) {
1211 device_type = DK_CDR;
1212 } else {
1213 device_type = DK_CDROM;
1214 }
1215 } else {
1216 device_type = ioctl(t_dev->d_fd,
1217 DKIOCGMEDIAINFO, &mediainfo);
1218 if (device_type < 0)
1219 device_type = 0;
1220 else
1221 device_type = mediainfo.dki_media_type;
1222 }
1223
1224 if (!ioctl(t_dev->d_fd, DKIOCREMOVABLE, &removable) &&
1225 !ioctl(t_dev->d_fd, DKIOCHOTPLUGGABLE,
1226 &hotpluggable)) {
1227 if (removable || hotpluggable) {
1228 removable_found++;
1229 pname = get_physical_name(sdev);
1230 if (sn) {
1231 (void) printf(" %4d. "
1232 "Volmgt Node: %s\n",
1233 removable_found, sn);
1234 (void) printf(" "
1235 "Logical Node: %s\n", sdev);
1236 (void) printf(" "
1237 "Physical Node: %s\n",
1238 pname);
1239 } else {
1240 (void) printf(" %4d. "
1241 "Logical Node: %s\n",
1242 removable_found, sdev);
1243 (void) printf(" "
1244 "Physical Node: %s\n",
1245 pname);
1246 }
1247 (void) printf(" Connected "
1248 "Device: %-8.8s %-16.16s "
1249 "%-4.4s\n",
1250 &t_dev->d_inq[8],
1251 &t_dev->d_inq[16],
1252 &t_dev->d_inq[32]);
1253 (void) printf(" Device "
1254 "Type: ");
1255 } else
1256 continue;
1257 } else
1258 continue;
1259
1260 switch (device_type) {
1261 case DK_CDROM:
1262 (void) printf("CD Reader\n");
1263 break;
1264 case DK_CDR:
1265 case DK_CDRW:
1266 (void) printf("CD Reader/Writer\n");
1267 break;
1268 case DK_DVDROM:
1269 (void) printf("DVD Reader\n");
1270 break;
1271 case DK_DVDR:
1272 case DK_DVDRAM:
1273 (void) printf("DVD Reader/Writer\n");
1274 break;
1275 case DK_FIXED_DISK:
1276 if (strstr((const char *)
1277 &t_dev->d_inq[16], "FD") ||
1278 strstr((const char *)
1279 &t_dev->d_inq[16], "LS-120"))
1280 (void) printf("Floppy "
1281 "drive\n");
1282 else
1283 (void) printf("Removable\n");
1284 break;
1285 case DK_FLOPPY:
1286 (void) printf("Floppy drive\n");
1287 break;
1288 case DK_ZIP:
1289 (void) printf("Zip drive\n");
1290 break;
1291 case DK_JAZ:
1292 (void) printf("Jaz drive\n");
1293 break;
1294 default:
1295 (void) printf("<Unknown>\n");
1296 DPRINTF1("\t %d\n", device_type);
1297 break;
1298 }
1299 get_media_info(t_dev, sdev, pname, sn);
1300 }
1301 fini_device(t_dev);
1302 }
1303
1304 (void) closedir(dir);
1305 return (removable_found);
1306 }
1307
1308 /*
1309 * Returns a device_t handle for a node returned by lookup_device()
1310 * and takes the user supplied name and stores it inside the node.
1311 */
1312 static device_t *
1313 get_device(char *user_supplied, char *node)
1314 {
1315 device_t *dev;
1316 int fd;
1317 char devnode[PATH_MAX];
1318 int size;
1319
1320 /*
1321 * we need to resolve any link paths to avoid fake files
1322 * such as /dev/rdsk/../../export/file.
1323 */
1324 size = resolvepath(node, devnode, PATH_MAX);
1325 if ((size <= 0) || (size >= (PATH_MAX - 1)))
1326 return (NULL);
1327
1328 /* resolvepath may not return a null terminated string */
1329 devnode[size] = '\0';
1330
1331
1332 /* the device node must be in /devices/ or /vol/dev/rdsk */
1333
1334 if ((strncmp(devnode, "/devices/", 9) != 0) &&
1335 (strncmp(devnode, "/vol/dev/rdsk", 13) != 0))
1336 return (NULL);
1337
1338 /* Turn on the privileges. */
1339 (void) __priv_bracket(PRIV_ON);
1340
1341 /*
1342 * Since we are currently running with the user euid it is
1343 * safe to try to open the file without checking access.
1344 */
1345
1346 fd = open(devnode, O_RDONLY|O_NDELAY);
1347
1348 /* Turn off the privileges. */
1349 (void) __priv_bracket(PRIV_OFF);
1350
1351 if (fd < 0) {
1352 return (NULL);
1353 }
1354
1355 dev = (device_t *)my_zalloc(sizeof (device_t));
1356
1357 dev->d_node = (char *)my_zalloc(strlen(devnode) + 1);
1358 (void) strcpy(dev->d_node, devnode);
1359
1360 dev->d_fd = fd;
1361
1362 dev->d_inq = (uchar_t *)my_zalloc(INQUIRY_DATA_LENGTH);
1363
1364 /* Turn on privileges. */
1365 (void) __priv_bracket(PRIV_ON);
1366 if (!inquiry(fd, dev->d_inq)) {
1367 DPRINTF1("USCSI ioctl failed %d\n",
1368 uscsi_error);
1369 free(dev->d_inq);
1370 free(dev->d_node);
1371 (void) close(dev->d_fd);
1372 free(dev);
1373 /* Turn off privileges. */
1374 (void) __priv_bracket(PRIV_OFF);
1375 return (NULL);
1376 }
1377 /* Turn off privileges. */
1378 (void) __priv_bracket(PRIV_OFF);
1379
1380 if (user_supplied) {
1381 dev->d_name = (char *)my_zalloc(strlen(user_supplied) + 1);
1382 (void) strcpy(dev->d_name, user_supplied);
1383 }
1384 return (dev);
1385 }
1386
1387 /*
1388 * Check for device specific characteristics.
1389 */
1390 int
1391 check_device(device_t *dev, int cond)
1392 {
1393 uchar_t page_code[4];
1394
1395 /* Look at the capabilities page for this information */
1396 if (cond & CHECK_DEVICE_IS_CD_WRITABLE) {
1397 if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1398 (page_code[3] & 1)) {
1399 return (1);
1400 }
1401 }
1402
1403 if (cond & CHECK_DEVICE_IS_DVD_WRITABLE) {
1404 if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1405 (page_code[3] & 0x10)) {
1406 return (1);
1407 }
1408 }
1409
1410 if (cond & CHECK_DEVICE_IS_DVD_READABLE) {
1411 if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1412 (page_code[2] & 0x8)) {
1413 return (1);
1414 }
1415 }
1416
1417 return (0);
1418 }
1419
1420 /*
1421 * Builds an open()able device path from a user supplied node which can be
1422 * of the * form of /dev/[r]dsk/cxtxdx[sx] or cxtxdx[sx] or volmgt-name like
1423 * cdrom[n].
1424 * Returns the path found in 'found' and returns 1. Otherwise returns 0.
1425 */
1426 int
1427 lookup_device(char *supplied, char *found)
1428 {
1429 struct stat statbuf;
1430 int fd;
1431 char tmpstr[PATH_MAX];
1432
1433 /* Turn on privileges */
1434 (void) __priv_bracket(PRIV_ON);
1435
1436 /* If everything is fine and proper, no need to analyze */
1437 if ((stat(supplied, &statbuf) == 0) && S_ISCHR(statbuf.st_mode) &&
1438 ((fd = open(supplied, O_RDONLY|O_NDELAY)) >= 0)) {
1439 (void) close(fd);
1440 (void) strlcpy(found, supplied, PATH_MAX);
1441 /* Turn off privilege */
1442 (void) __priv_bracket(PRIV_OFF);
1443 return (1);
1444 }
1445
1446 /* Turn off privileges. */
1447 (void) __priv_bracket(PRIV_OFF);
1448
1449 if (strncmp(supplied, "/dev/rdsk/", 10) == 0)
1450 return (vol_lookup(supplied, found));
1451 if (strncmp(supplied, "/dev/dsk/", 9) == 0) {
1452 (void) snprintf(tmpstr, PATH_MAX, "/dev/rdsk/%s",
1453 (char *)strrchr(supplied, '/'));
1454
1455 if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
1456 (void) close(fd);
1457 (void) strlcpy(found, supplied, PATH_MAX);
1458 return (1);
1459 }
1460 if ((access(tmpstr, F_OK) == 0) && vol_running)
1461 return (vol_lookup(tmpstr, found));
1462 else
1463 return (0);
1464 }
1465 if ((strncmp(supplied, "cdrom", 5) != 0) &&
1466 (strlen(supplied) < 32)) {
1467 (void) snprintf(tmpstr, sizeof (tmpstr), "/dev/rdsk/%s",
1468 supplied);
1469 if (access(tmpstr, F_OK) < 0) {
1470 (void) strcat(tmpstr, "s2");
1471 }
1472 if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
1473 (void) close(fd);
1474 (void) strlcpy(found, tmpstr, PATH_MAX);
1475 return (1);
1476 }
1477 if ((access(tmpstr, F_OK) == 0) && vol_running)
1478 return (vol_lookup(tmpstr, found));
1479 }
1480 return (vol_name_to_dev_node(supplied, found));
1481 }
1482
1483 int
1484 is_cd(char *node)
1485 {
1486 int fd;
1487 struct dk_cinfo cinfo;
1488
1489 fd = open(node, O_RDONLY|O_NDELAY);
1490 if (fd < 0)
1491 return (0);
1492 if (ioctl(fd, DKIOCINFO, &cinfo) < 0) {
1493 (void) close(fd);
1494 return (0);
1495 }
1496 if (cinfo.dki_ctype != DKC_CDROM)
1497 return (0);
1498 return (1);
1499 }
1500
1501 void
1502 print_header(void)
1503 {
1504 /* l10n_NOTE : Column spacing should be kept same */
1505 (void) printf(gettext(" Node "
1506 "Connected Device"));
1507 /* l10n_NOTE : Column spacing should be kept same */
1508 (void) printf(gettext(" Device type\n"));
1509 (void) printf(
1510 "---------------------------+---------------------------");
1511 (void) printf("-----+----------------\n");
1512 }
1513
1514 void
1515 print_divider(void)
1516 {
1517 (void) printf(
1518 "---------------------------+---------------------------");
1519 (void) printf("-----+----------------\n");
1520 }
1521
1522 static void
1523 fini_device(device_t *dev)
1524 {
1525 free(dev->d_inq);
1526 free(dev->d_node);
1527 (void) close(dev->d_fd);
1528 if (dev->d_name)
1529 free(dev->d_name);
1530 free(dev);
1531 }
1532
1533 void *
1534 my_zalloc(size_t size)
1535 {
1536 void *ret;
1537
1538 ret = malloc(size);
1539 if (ret == NULL) {
1540
1541 /* Lets wait a sec. and try again */
1542 if (errno == EAGAIN) {
1543 (void) sleep(1);
1544 ret = malloc(size);
1545 }
1546
1547 if (ret == NULL) {
1548 (void) err_msg("%s\n", gettext(strerror(errno)));
1549 (void) err_msg(gettext(
1550 "Memory allocation failure, Exiting...\n"));
1551 exit(1);
1552 }
1553 }
1554 (void) memset(ret, 0, size);
1555 return (ret);
1556 }
1557
1558 static int
1559 vol_name_to_dev_node(char *vname, char *found)
1560 {
1561 struct stat statbuf;
1562 char *p1;
1563 int i;
1564
1565 if (vname == NULL)
1566 return (0);
1567 if (vol_running)
1568 (void) volmgt_check(vname);
1569 p1 = media_findname(vname);
1570 if (p1 == NULL)
1571 return (0);
1572 if (stat(p1, &statbuf) < 0) {
1573 free(p1);
1574 return (0);
1575 }
1576 if (S_ISDIR(statbuf.st_mode)) {
1577 for (i = 0; i < 16; i++) {
1578 (void) snprintf(found, PATH_MAX, "%s/s%d", p1, i);
1579 if (access(found, F_OK) >= 0)
1580 break;
1581 }
1582 if (i == 16) {
1583 free(p1);
1584 return (0);
1585 }
1586 } else {
1587 (void) strlcpy(found, p1, PATH_MAX);
1588 }
1589 free(p1);
1590 return (1);
1591 }
1592
1593 /*
1594 * Searches for volume manager's equivalent char device for the
1595 * supplied pathname which is of the form of /dev/rdsk/cxtxdxsx
1596 */
1597 static int
1598 vol_lookup(char *supplied, char *found)
1599 {
1600 char tmpstr[PATH_MAX], tmpstr1[PATH_MAX], *p;
1601 int i, ret;
1602
1603 (void) strlcpy(tmpstr, supplied, PATH_MAX);
1604 if ((p = volmgt_symname(tmpstr)) == NULL) {
1605 if (strstr(tmpstr, "s2") != NULL) {
1606 *((char *)(strrchr(tmpstr, 's') + 1)) = 0;
1607 for (i = 0; i < 16; i++) {
1608 (void) snprintf(tmpstr1, PATH_MAX, "%s%d",
1609 tmpstr, i);
1610 if ((p = volmgt_symname(tmpstr1)) != NULL)
1611 break;
1612 }
1613 } else if (strstr(tmpstr, "p0") != NULL) {
1614 *((char *)(strrchr(tmpstr, 'p') + 1)) = 0;
1615 for (i = 0; i < 5; i++) {
1616 (void) snprintf(tmpstr1, PATH_MAX, "%s%d",
1617 tmpstr, i);
1618 if ((p = volmgt_symname(tmpstr1)) != NULL)
1619 break;
1620 }
1621 } else
1622 return (0);
1623 if (p == NULL)
1624 return (0);
1625 }
1626
1627 ret = vol_name_to_dev_node(p, found);
1628 free(p);
1629 return (ret);
1630 }
1631
1632 /*PRINTFLIKE1*/
1633 void
1634 err_msg(char *fmt, ...)
1635 {
1636 va_list ap;
1637
1638 va_start(ap, fmt);
1639 (void) vfprintf(stderr, fmt, ap);
1640 va_end(ap);
1641 }
1642
1643 int
1644 inquiry(int fd, uchar_t *inq)
1645 {
1646 struct uscsi_cmd *scmd;
1647
1648 scmd = get_uscsi_cmd();
1649 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
1650 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
1651 scmd->uscsi_cdb[0] = INQUIRY_CMD;
1652 scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH;
1653 scmd->uscsi_cdblen = 6;
1654 scmd->uscsi_bufaddr = (char *)inq;
1655 scmd->uscsi_buflen = INQUIRY_DATA_LENGTH;
1656 if ((uscsi_error = uscsi(fd, scmd)) < 0)
1657 return (0);
1658 return (1);
1659 }
1660
1661 struct uscsi_cmd *
1662 get_uscsi_cmd(void)
1663 {
1664 (void) memset(&uscmd, 0, sizeof (uscmd));
1665 (void) memset(ucdb, 0, 16);
1666 uscmd.uscsi_cdb = ucdb;
1667 return (&uscmd);
1668 }
1669
1670 int
1671 uscsi(int fd, struct uscsi_cmd *scmd)
1672 {
1673 int ret, global_rqsense;
1674 int retries, max_retries = 5;
1675 int i;
1676
1677 /* set up for request sense extensions */
1678 if (!(scmd->uscsi_flags & USCSI_RQENABLE)) {
1679 scmd->uscsi_flags |= USCSI_RQENABLE;
1680 scmd->uscsi_rqlen = RQBUFLEN;
1681 scmd->uscsi_rqbuf = rqbuf;
1682 global_rqsense = 1;
1683 } else {
1684 global_rqsense = 0;
1685 }
1686
1687 /*
1688 * The device may be busy or slow and fail with a not ready status.
1689 * we'll allow a limited number of retries to give the drive time
1690 * to recover.
1691 */
1692 for (retries = 0; retries < max_retries; retries++) {
1693
1694 scmd->uscsi_status = 0;
1695
1696 if (global_rqsense)
1697 (void) memset(rqbuf, 0, RQBUFLEN);
1698
1699 DPRINTF("cmd:[");
1700 for (i = 0; i < scmd->uscsi_cdblen; i++)
1701 DPRINTF1("0x%02x ",
1702 (uchar_t)scmd->uscsi_cdb[i]);
1703 DPRINTF("]\n");
1704
1705 /*
1706 * We need to have root privledges in order to use
1707 * uscsi commands on the device.
1708 */
1709
1710 ret = ioctl(fd, USCSICMD, scmd);
1711
1712 /* maintain consistency in case of sgen */
1713 if ((ret == 0) && (scmd->uscsi_status == 2)) {
1714 ret = -1;
1715 errno = EIO;
1716 }
1717
1718 /* if error and extended request sense, retrieve errors */
1719 if (global_rqsense && (ret < 0) && (scmd->uscsi_status == 2)) {
1720 /*
1721 * The drive is not ready to recieve commands but
1722 * may be in the process of becoming ready.
1723 * sleep for a short time then retry command.
1724 * SENSE/ASC = 2/4 : not ready
1725 * ASCQ = 0 Not Reportable.
1726 * ASCQ = 1 Becoming ready.
1727 */
1728 if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
1729 ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1))) {
1730 total_retries++;
1731 (void) sleep(3);
1732 continue;
1733 }
1734
1735 /*
1736 * Device is not ready to transmit or a device reset
1737 * has occurred. wait for a short period of time then
1738 * retry the command.
1739 */
1740 if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
1741 (ASC(rqbuf) == 0x29))) {
1742 (void) sleep(3);
1743 total_retries++;
1744 continue;
1745 }
1746
1747 DPRINTF3("cmd: 0x%02x ret:%i status:%02x ",
1748 (uchar_t)scmd->uscsi_cdb[0], ret,
1749 scmd->uscsi_status);
1750 DPRINTF3(" sense: %02x ASC: %02x ASCQ:%02x\n",
1751 (uchar_t)SENSE_KEY(rqbuf),
1752 (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf));
1753 }
1754
1755 /* no errors we'll return */
1756 break;
1757 }
1758
1759 /* store the error status for later debug printing */
1760 if ((ret < 0) && (global_rqsense)) {
1761 uscsi_status = scmd->uscsi_status;
1762 rqstatus = scmd->uscsi_rqstatus;
1763 rqresid = scmd->uscsi_rqresid;
1764
1765 }
1766
1767 DPRINTF1("total retries: %d\n", total_retries);
1768
1769 return (ret);
1770 }
1771
1772 /*
1773 * will get the mode page only i.e. will strip off the header.
1774 */
1775 int
1776 get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer)
1777 {
1778 int ret;
1779 uchar_t byte2, *buf;
1780 uint_t header_len, page_len, copy_cnt;
1781
1782 byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
1783 buf = (uchar_t *)my_zalloc(256);
1784
1785 /* Ask 254 bytes only to make our IDE driver happy */
1786 ret = mode_sense(fd, byte2, 1, 254, buf);
1787 if (ret == 0) {
1788 free(buf);
1789 return (0);
1790 }
1791
1792 header_len = 8 + read_scsi16(&buf[6]);
1793 page_len = buf[header_len + 1] + 2;
1794
1795 copy_cnt = (page_len > buf_len) ? buf_len : page_len;
1796 (void) memcpy(buffer, &buf[header_len], copy_cnt);
1797 free(buf);
1798
1799 return (1);
1800 }
1801
1802 int
1803 mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
1804 {
1805 struct uscsi_cmd *scmd;
1806
1807 scmd = get_uscsi_cmd();
1808 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
1809 scmd->uscsi_buflen = page_len;
1810 scmd->uscsi_bufaddr = (char *)buffer;
1811 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
1812 scmd->uscsi_cdblen = 0xa;
1813 scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD;
1814 if (dbd) {
1815 /* don't return any block descriptors */
1816 scmd->uscsi_cdb[1] = 0x8;
1817 }
1818 /* the page code we want */
1819 scmd->uscsi_cdb[2] = pc;
1820 /* allocation length */
1821 scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
1822 scmd->uscsi_cdb[8] = page_len & 0xff;
1823
1824 if ((uscsi_error = uscsi(fd, scmd)) < 0)
1825 return (0);
1826 return (1);
1827 }
1828
1829 uint16_t
1830 read_scsi16(void *addr)
1831 {
1832 uchar_t *ad = (uchar_t *)addr;
1833 uint16_t ret;
1834
1835 ret = ((((uint16_t)ad[0]) << 8) | ad[1]);
1836 return (ret);
1837 }
1838
1839 /*
1840 * Allocate space for and return a pointer to a string
1841 * on the stack. If the string is null, create
1842 * an empty string.
1843 * Use destroy_data() to free when no longer used.
1844 */
1845 char *
1846 alloc_string(s)
1847 char *s;
1848 {
1849 char *ns;
1850
1851 if (s == (char *)NULL) {
1852 ns = (char *)my_zalloc(1);
1853 } else {
1854 ns = (char *)my_zalloc(strlen(s) + 1);
1855 (void) strcpy(ns, s);
1856 }
1857 return (ns);
1858 }
1859
1860 /*
1861 * Follow symbolic links from the logical device name to
1862 * the /devfs physical device name. To be complete, we
1863 * handle the case of multiple links. This function
1864 * either returns NULL (no links, or some other error),
1865 * or the physical device name, alloc'ed on the heap.
1866 *
1867 * Note that the standard /devices prefix is stripped from
1868 * the final pathname, if present. The trailing options
1869 * are also removed (":c, raw").
1870 */
1871 static char *
1872 get_physical_name(char *path)
1873 {
1874 struct stat stbuf;
1875 int i;
1876 int level;
1877 char *p;
1878 char s[MAXPATHLEN];
1879 char buf[MAXPATHLEN];
1880 char dir[MAXPATHLEN];
1881 char savedir[MAXPATHLEN];
1882 char *result = NULL;
1883
1884 if (getcwd(savedir, sizeof (savedir)) == NULL) {
1885 DPRINTF1("getcwd() failed - %s\n", strerror(errno));
1886 return (NULL);
1887 }
1888
1889 (void) strcpy(s, path);
1890 if ((p = strrchr(s, '/')) != NULL) {
1891 *p = 0;
1892 }
1893 if (s[0] == 0) {
1894 (void) strcpy(s, "/");
1895 }
1896 if (chdir(s) == -1) {
1897 DPRINTF2("cannot chdir() to %s - %s\n",
1898 s, strerror(errno));
1899 goto exit;
1900 }
1901
1902 level = 0;
1903 (void) strcpy(s, path);
1904 for (;;) {
1905 /*
1906 * See if there's a real file out there. If not,
1907 * we have a dangling link and we ignore it.
1908 */
1909 if (stat(s, &stbuf) == -1) {
1910 goto exit;
1911 }
1912 if (lstat(s, &stbuf) == -1) {
1913 DPRINTF2("%s: lstat() failed - %s\n",
1914 s, strerror(errno));
1915 goto exit;
1916 }
1917 /*
1918 * If the file is not a link, we're done one
1919 * way or the other. If there were links,
1920 * return the full pathname of the resulting
1921 * file.
1922 */
1923 if (!S_ISLNK(stbuf.st_mode)) {
1924 if (level > 0) {
1925 /*
1926 * Strip trailing options from the
1927 * physical device name
1928 */
1929 if ((p = strrchr(s, ':')) != NULL) {
1930 *p = 0;
1931 }
1932 /*
1933 * Get the current directory, and
1934 * glue the pieces together.
1935 */
1936 if (getcwd(dir, sizeof (dir)) == NULL) {
1937 DPRINTF1("getcwd() failed - %s\n",
1938 strerror(errno));
1939 goto exit;
1940 }
1941 (void) strcat(dir, "/");
1942 (void) strcat(dir, s);
1943 /*
1944 * If we have the standard fixed
1945 * /devices prefix, remove it.
1946 */
1947 p = (strstr(dir, DEVFS_PREFIX) == dir) ?
1948 dir+strlen(DEVFS_PREFIX) : dir;
1949 result = alloc_string(p);
1950 }
1951 goto exit;
1952 }
1953 i = readlink(s, buf, sizeof (buf));
1954 if (i == -1) {
1955 DPRINTF2("%s: readlink() failed - %s\n",
1956 s, strerror(errno));
1957 goto exit;
1958 }
1959 level++;
1960 buf[i] = 0;
1961
1962 /*
1963 * Break up the pathname into the directory
1964 * reference, if applicable and simple filename.
1965 * chdir()'ing to the directory allows us to
1966 * handle links with relative pathnames correctly.
1967 */
1968 (void) strcpy(dir, buf);
1969 if ((p = strrchr(dir, '/')) != NULL) {
1970 *p = 0;
1971 if (chdir(dir) == -1) {
1972 DPRINTF2("cannot chdir() to %s - %s\n",
1973 dir, strerror(errno));
1974 goto exit;
1975 }
1976 (void) strcpy(s, p+1);
1977 } else {
1978 (void) strcpy(s, buf);
1979 }
1980 }
1981
1982 exit:
1983 if (chdir(savedir) == -1) {
1984 (void) printf("cannot chdir() to %s - %s\n",
1985 savedir, strerror(errno));
1986 }
1987
1988 return (result);
1989 }
1990
1991 static void
1992 get_media_info(device_t *t_dev, char *sdev, char *pname, char *sn)
1993 {
1994 struct dk_cinfo cinfo;
1995 struct extvtoc vtocinfo;
1996 float size;
1997 int32_t fd;
1998 smedia_handle_t handle;
1999 struct dk_minfo mediainfo;
2000 int device_type;
2001
2002 device_type = ioctl(t_dev->d_fd, DKIOCGMEDIAINFO, &mediainfo);
2003
2004 /*
2005 * Determine bus type.
2006 */
2007 if (!ioctl(t_dev->d_fd, DKIOCINFO, &cinfo)) {
2008 if (strstr(cinfo.dki_cname, "usb") || strstr(pname, "usb")) {
2009 (void) printf("\tBus: USB\n");
2010 } else if (strstr(cinfo.dki_cname, "firewire") ||
2011 strstr(pname, "firewire")) {
2012 (void) printf("\tBus: Firewire\n");
2013 } else if (strstr(cinfo.dki_cname, "ide") ||
2014 strstr(pname, "ide")) {
2015 (void) printf("\tBus: IDE\n");
2016 } else if (strstr(cinfo.dki_cname, "scsi") ||
2017 strstr(pname, "scsi")) {
2018 (void) printf("\tBus: SCSI\n");
2019 } else {
2020 (void) printf("\tBus: <Unknown>\n");
2021 }
2022 } else {
2023 (void) printf("\tBus: <Unknown>\n");
2024 }
2025
2026 /*
2027 * Calculate size of media.
2028 */
2029 if (!device_type &&
2030 (!ioctl(t_dev->d_fd, DKIOCGMEDIAINFO, &mediainfo))) {
2031 size = (mediainfo.dki_lbsize*
2032 mediainfo.dki_capacity)/(1024.0*1024.0);
2033 if (size < 1000) {
2034 (void) printf("\tSize: %.1f MB\n", size);
2035 } else {
2036 size = size/1000;
2037 (void) printf("\tSize: %.1f GB\n", size);
2038 }
2039 } else {
2040 (void) printf("\tSize: <Unknown>\n");
2041 }
2042
2043 /*
2044 * Print label.
2045 */
2046 if (!device_type && (read_extvtoc(t_dev->d_fd, &vtocinfo) >= 0)) {
2047 if (*vtocinfo.v_volume) {
2048 (void) printf("\tLabel: %s\n", vtocinfo.v_volume);
2049 } else {
2050 (void) printf("\tLabel: <None>\n");
2051 }
2052 } else {
2053 (void) printf("\tLabel: <Unknown>\n");
2054 }
2055
2056 /*
2057 * Acess permissions.
2058 */
2059 if (device_type) {
2060 (void) printf("\tAccess permissions: <Unknown>\n");
2061 return;
2062 }
2063
2064 (void) fprintf(stdout, gettext("\tAccess permissions: "));
2065 if (sn) {
2066 /*
2067 * Set dev_name for process_p_flag().
2068 */
2069 dev_name = sn;
2070 fd = my_open(sn, O_RDONLY|O_NDELAY);
2071 } else {
2072 dev_name = sdev;
2073 fd = my_open(sdev, O_RDONLY|O_NDELAY);
2074 }
2075 if (fd < 0) {
2076 (void) printf("<Unknown>\n");
2077 DPRINTF("Could not open device.\n");
2078 (void) close(fd);
2079 } else {
2080 /* register the fd with the libsmedia */
2081 handle = smedia_get_handle(fd);
2082 if (handle == NULL) {
2083 (void) printf("<Unknown>\n");
2084 DPRINTF("Failed to get libsmedia handle.\n");
2085 (void) close(fd);
2086 } else {
2087 process_p_flag(handle, fd);
2088 }
2089 }
2090 /* Clear dev_name */
2091 dev_name = NULL;
2092 }