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