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 size_t len = strlen(tmp_path_name);
665
666 (void) snprintf(tmp_path_name + len,
667 PATH_MAX - len, "/%s", dp->d_name);
668
669 DPRINTF1("tmp_pathname is %s\n", tmp_path_name);
670 break;
671 }
672
673 /* Turn on the privileges. */
674 (void) __priv_bracket(PRIV_ON);
675 have_read_priv = 1;
676 }
677
678 if (have_read_priv) {
679 /* drop the file_dac_read privilege */
680 (void) __priv_bracket(PRIV_OFF);
681 have_read_priv = 0;
682 }
683
684 (void) closedir(dirp);
685 }
686
687
688 if (volmgt_running() == 0) {
689 /* Turn on privileges. */
690 (void) __priv_bracket(PRIV_ON);
691 have_read_priv = 1;
692 }
693
694 fd = open(tmp_path_name, flags);
695
696 if (have_read_priv) {
697 /* Turn off privileges. */
698 (void) __priv_bracket(PRIV_OFF);
699 have_read_priv = 0;
700 }
701
702 DPRINTF1("path opened %s\n", tmp_path_name);
703
704 return (fd);
705 }
706
707 uint64_t
my_atoll(char * ptr)708 my_atoll(char *ptr)
709 {
710 char *tmp_ptr = ptr;
711 int32_t base = 10;
712 uint64_t ret_val;
713
714 while (*tmp_ptr) {
715 if (isdigit(*tmp_ptr))
716 tmp_ptr++;
717 else {
718 base = 16;
719 break;
720 }
721 }
722 tmp_ptr = ptr;
723 if (base == 16) {
724 if (strlen(tmp_ptr) < 3) {
725 return (-1);
726 }
727 if (*tmp_ptr++ != '0' || (*tmp_ptr != 'x' && *tmp_ptr != 'X')) {
728 return (-1);
729 }
730 tmp_ptr++;
731 while (*tmp_ptr) {
732 if (isxdigit(*tmp_ptr))
733 tmp_ptr++;
734 else {
735 return (-1);
736 }
737 }
738 }
739 ret_val = (uint64_t)strtoull(ptr, (char **)NULL, 0);
740 return (ret_val);
741 }
742
743 int32_t
write_sunos_label(int32_t fd,int32_t media_type)744 write_sunos_label(int32_t fd, int32_t media_type)
745 {
746
747 struct extvtoc v_toc;
748 int32_t ret;
749
750 (void) memset(&v_toc, 0, sizeof (struct extvtoc));
751
752 /* Initialize the vtoc information */
753
754 if (media_type == SM_FLOPPY) {
755 struct fd_char fdchar;
756 int32_t mult_factor;
757
758 if (ioctl(fd, FDIOGCHAR, &fdchar) < 0) {
759 PERROR("FDIOGCHAR failed");
760 return (-1);
761 }
762
763 /* SPARC and x86 fd drivers use fdc_medium differently */
764 #if defined(__sparc)
765 mult_factor = (fdchar.fdc_medium) ? 2 : 1;
766 #elif defined(__x86)
767 mult_factor = (fdchar.fdc_medium == 5) ? 2 : 1;
768 #else
769 #error No Platform defined
770 #endif /* defined(__sparc) */
771
772 /* initialize the vtoc structure */
773 v_toc.v_nparts = 3;
774
775 v_toc.v_part[0].p_start = 0;
776 v_toc.v_part[0].p_size = (fdchar.fdc_ncyl - 1) * 2 *
777 fdchar.fdc_secptrack * mult_factor;
778 v_toc.v_part[1].p_start = (fdchar.fdc_ncyl - 1) * 2 *
779 fdchar.fdc_secptrack * mult_factor;
780 v_toc.v_part[1].p_size = 2 * fdchar.fdc_secptrack * mult_factor;
781
782 v_toc.v_part[2].p_start = 0;
783 v_toc.v_part[2].p_size = fdchar.fdc_ncyl * 2 *
784 fdchar.fdc_secptrack * mult_factor;
785
786 } else if (media_type == SM_SCSI_FLOPPY) {
787
788 smedia_handle_t handle;
789 smmedium_prop_t med_info;
790 struct dk_geom dkgeom;
791
792
793 /*
794 * call smedia_get_medium_property to get the
795 * correct media information, since DKIOCGMEDIAINFO
796 * may fail for unformatted media.
797 */
798
799 handle = smedia_get_handle(fd);
800 if (handle == NULL) {
801 (void) fprintf(stderr,
802 gettext("Failed to get libsmedia handle.\n"));
803
804 (void) close(fd);
805 return (-1);
806 }
807
808
809 if (smedia_get_medium_property(handle, &med_info) < 0) {
810 (void) fprintf(stderr,
811 gettext("Get medium property failed \n"));
812
813 (void) smedia_release_handle(handle);
814 (void) close(fd);
815 return (-1);
816 }
817
818 /* Fill in our own geometry information */
819
820 dkgeom.dkg_pcyl = med_info.sm_pcyl;
821 dkgeom.dkg_ncyl = med_info.sm_pcyl;
822 dkgeom.dkg_nhead = med_info.sm_nhead;
823 dkgeom.dkg_nsect = med_info.sm_nsect;
824 dkgeom.dkg_acyl = 0;
825 dkgeom.dkg_bcyl = 0;
826 dkgeom.dkg_intrlv = 0;
827 dkgeom.dkg_apc = 0;
828
829 /*
830 * Try to set vtoc, if not successful we will
831 * continue to use the faked geometry information.
832 */
833
834 (void) ioctl(fd, DKIOCSGEOM, &dkgeom);
835
836 (void) smedia_release_handle(handle);
837
838 /* we want the same partitioning as used for normal floppies */
839
840 v_toc.v_part[0].p_start = 0;
841 v_toc.v_part[0].p_size = (diskaddr_t)(dkgeom.dkg_ncyl - 1) *
842 dkgeom.dkg_nhead * dkgeom.dkg_nsect;
843
844 v_toc.v_part[1].p_start = (diskaddr_t)(dkgeom.dkg_ncyl - 1) *
845 dkgeom.dkg_nhead * dkgeom.dkg_nsect;
846 v_toc.v_part[1].p_size = dkgeom.dkg_nhead * dkgeom.dkg_nsect;
847
848 v_toc.v_part[2].p_start = 0;
849 v_toc.v_part[2].p_size = (diskaddr_t)dkgeom.dkg_ncyl *
850 dkgeom.dkg_nhead * dkgeom.dkg_nsect;
851
852 /* both write_vtoc and DKIOCSVTOC require V_NUMPAR partitions */
853 v_toc.v_nparts = V_NUMPAR;
854
855 } else {
856
857 return (0);
858 }
859
860 v_toc.v_sanity = VTOC_SANE;
861 v_toc.v_version = V_VERSION;
862
863 /*
864 * The label structure is set up for DEV_BSIZE(512 byte) blocks,
865 * even though a medium density diskette has 1024 byte blocks
866 * See dklabel.h for more details.
867 */
868 v_toc.v_sectorsz = DEV_BSIZE;
869
870 /* let the fd driver finish constructing the label and writing it. */
871
872
873 /* Turn on the privileges. */
874 (void) __priv_bracket(PRIV_ON);
875
876 ret = write_extvtoc(fd, &v_toc);
877
878 /* Turn off the privileges. */
879 (void) __priv_bracket(PRIV_OFF);
880
881 if (ret < 0) {
882 PERROR("Write vtoc");
883 DPRINTF1("Write vtoc failed errno:%d\n", errno);
884 return (-1);
885 }
886
887 return (0);
888 }
889
890 static void
intr_sig_handler()891 intr_sig_handler()
892 {
893 char c;
894
895 (void) fprintf(stderr, gettext(global_intr_msg));
896 (void) fprintf(stderr,
897 gettext("\nDo you want to stop formatting?(y/n)"));
898 (void) fflush(stdout);
899 rewind(stdin);
900 while ((c = getchar()) == -1)
901 ;
902 if (c == 'y' || c == 'Y') {
903 (void) fprintf(stderr, gettext("Format interrupted\n"));
904 exit(1);
905 } else if (c == 'n' || c == 'N')
906 return;
907 else {
908 (void) fprintf(stderr, gettext("Did not interrupt\n"));
909 return;
910 }
911 }
912
913 static struct sigaction act, oact;
914 void
trap_SIGINT(void)915 trap_SIGINT(void)
916 {
917
918 act.sa_handler = intr_sig_handler;
919 (void) memset(&act.sa_mask, 0, sizeof (sigset_t));
920 act.sa_flags = SA_RESTART; /* | SA_NODEFER; */
921 if (sigaction(SIGINT, &act, &oact) < 0) {
922 DPRINTF("sigset failed\n");
923 return;
924 }
925 }
926
927 void
release_SIGINT(void)928 release_SIGINT(void)
929 {
930 if (sigaction(SIGINT, &oact, (struct sigaction *)NULL) < 0) {
931 DPRINTF("sigunset failed\n");
932 return;
933 }
934 }
935
936 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)937 verify(smedia_handle_t handle, int32_t fd, diskaddr_t start_sector,
938 uint32_t nblocks, char *buf,
939 int32_t flag, int32_t blocksize, int32_t no_raw_rw)
940 {
941 uint64_t ret;
942
943 DPRINTF("ANALYSE MEDIA \n");
944
945
946 if ((flag == VERIFY_READ) && (!no_raw_rw)) {
947
948 /* Turn on the privileges. */
949 (void) __priv_bracket(PRIV_ON);
950
951 ret = smedia_raw_read(handle, start_sector, buf, nblocks *
952 blocksize);
953
954 /* Turn off the privileges. */
955 (void) __priv_bracket(PRIV_OFF);
956
957 if (ret != (nblocks * blocksize))
958 return (-1);
959 return (0);
960
961 } else if ((flag == VERIFY_WRITE) && (!no_raw_rw)) {
962
963 /* Turn on privileges. */
964 (void) __priv_bracket(PRIV_ON);
965
966 ret = smedia_raw_write(handle, start_sector, buf, nblocks *
967 blocksize);
968
969 /* Turn off the privileges. */
970 (void) __priv_bracket(PRIV_OFF);
971
972 if (ret != (blocksize * nblocks))
973 return (-1);
974 return (0);
975
976 } else if ((flag == VERIFY_READ) && (no_raw_rw)) {
977 ret = llseek(fd, start_sector * blocksize, SEEK_SET);
978 if (ret != start_sector * blocksize) {
979 (void) fprintf(stderr, gettext("Seek failed\n"));
980 return (-2);
981 }
982
983 /* Turn on the privileges. */
984 (void) __priv_bracket(PRIV_ON);
985
986 ret = read(fd, buf, nblocks * blocksize);
987
988 /* Turn off the privileges. */
989 (void) __priv_bracket(PRIV_OFF);
990
991 if (ret != nblocks * blocksize) {
992 return (-1);
993 }
994 return (0);
995 } else if ((flag == VERIFY_WRITE) && (no_raw_rw)) {
996 ret = llseek(fd, start_sector * blocksize, SEEK_SET);
997 if (ret != start_sector * blocksize) {
998 (void) fprintf(stderr, gettext("Seek failed\n"));
999 return (-2);
1000 }
1001
1002 /* Turn on the privileges. */
1003 (void) __priv_bracket(PRIV_ON);
1004
1005 ret = write(fd, buf, nblocks * blocksize);
1006
1007 /* Turn off the privileges. */
1008 (void) __priv_bracket(PRIV_OFF);
1009
1010 if (ret != nblocks * blocksize) {
1011 return (-1);
1012 }
1013 return (0);
1014 } else {
1015 DPRINTF("Illegal parameter to verify_analysis!\n");
1016 return (-1);
1017 }
1018 }
1019
1020 static int
my_umount(char * mountp)1021 my_umount(char *mountp)
1022 {
1023 pid_t pid; /* forked proc's pid */
1024 int rval; /* proc's return value */
1025
1026
1027 /* create a child to unmount the path */
1028
1029 /* Turn on the privileges */
1030 (void) __priv_bracket(PRIV_ON);
1031
1032 pid = fork();
1033
1034 /* Turn off the privileges. */
1035 (void) __priv_bracket(PRIV_OFF);
1036
1037 if (pid < 0) {
1038 PERROR("fork failed");
1039 exit(0);
1040 }
1041
1042 if (pid == 0) {
1043 /* the child */
1044 /* get rid of those nasty err messages */
1045 DPRINTF1("call_unmount_prog: calling %s \n", mountp);
1046
1047 /* Turn on the priviliges. */
1048 (void) __priv_bracket(PRIV_ON);
1049
1050 if (execl("/usr/sbin/umount", "/usr/sbin/umount", mountp,
1051 NULL) < 0) {
1052 perror("exec failed");
1053 /* Turn off the privileges */
1054 (void) __priv_bracket(PRIV_OFF);
1055 exit(-1);
1056 }
1057 }
1058
1059 /* wait for the umount command to exit */
1060 rval = 0;
1061 if (waitpid(pid, &rval, 0) == pid) {
1062 if (WIFEXITED(rval)) {
1063 if (WEXITSTATUS(rval) == 0) {
1064 DPRINTF("umount : Success\n");
1065 return (1);
1066 }
1067 }
1068 }
1069 return (-1);
1070 }
1071
1072 static int
my_volrmmount(char * real_name)1073 my_volrmmount(char *real_name)
1074 {
1075 int pid, rval;
1076
1077 /* Turn on the privileges. */
1078 (void) __priv_bracket(PRIV_ON);
1079
1080 pid = fork();
1081
1082 /* Turn off the privileges. */
1083 (void) __priv_bracket(PRIV_OFF);
1084
1085 /* create a child to unmount the path */
1086 if (pid < 0) {
1087 PERROR("fork failed");
1088 exit(0);
1089 }
1090
1091 if (pid == 0) {
1092 /* the child */
1093 /* get rid of those nasty err messages */
1094 DPRINTF1("call_unmount_prog: calling %s \n",
1095 "/usr/bin/volrmmount");
1096
1097 /* Turn on the privileges. */
1098 (void) __priv_bracket(PRIV_ON);
1099 if (execl("/usr/bin/volrmmount", "/usr/bin/volrmmount", "-e",
1100 real_name, NULL) < 0) {
1101 PERROR("volrmmount exec failed");
1102 /* Turn off the privileges */
1103 (void) __priv_bracket(PRIV_OFF);
1104 exit(-1);
1105 }
1106 } else if (waitpid(pid, &rval, 0) == pid) {
1107 if (WIFEXITED(rval)) {
1108 if (WEXITSTATUS(rval) == 0) {
1109 DPRINTF("volrmmount: Success\n");
1110 return (1);
1111 }
1112 }
1113 }
1114 return (-1);
1115 }
1116
1117 int
find_device(int defer,char * tmpstr)1118 find_device(int defer, char *tmpstr)
1119 {
1120 DIR *dir;
1121 struct dirent *dirent;
1122 char sdev[PATH_MAX], dev[PATH_MAX], *pname;
1123 device_t *t_dev;
1124 int removable = 0;
1125 int device_type = 0;
1126 int hotpluggable = 0;
1127 struct dk_minfo mediainfo;
1128 static int found = 0;
1129
1130 dir = opendir("/dev/rdsk");
1131 if (dir == NULL)
1132 return (-1);
1133
1134 total_devices_found = 0;
1135 while ((dirent = readdir(dir)) != NULL) {
1136 if (dirent->d_name[0] == '.') {
1137 continue;
1138 }
1139 (void) snprintf(sdev, PATH_MAX, "/dev/rdsk/%s",
1140 dirent->d_name);
1141 #ifdef sparc
1142 if (!strstr(sdev, "s2")) {
1143 continue;
1144 }
1145 #else /* x86 */
1146 if (vol_running) {
1147 if (!(strstr(sdev, "s2") || strstr(sdev, "p0"))) {
1148 continue;
1149 }
1150 } else {
1151 if (!strstr(sdev, "p0")) {
1152 continue;
1153 }
1154 }
1155 #endif
1156 if (!lookup_device(sdev, dev)) {
1157 continue;
1158 }
1159 if ((t_dev = get_device(NULL, dev)) == NULL) {
1160 continue;
1161 }
1162 total_devices_found++;
1163
1164 if ((!defer) && !found) {
1165 char *sn, *tmpbuf;
1166 /*
1167 * dev_name is an optional command line input.
1168 */
1169 if (dev_name) {
1170 if (strstr(dirent->d_name, tmpstr)) {
1171 found = 1;
1172 } else if (!vol_running) {
1173 continue;
1174 }
1175 }
1176 /*
1177 * volmgt_symname() returns NULL if the device
1178 * is not managed by volmgt.
1179 */
1180 sn = volmgt_symname(sdev);
1181
1182 if (vol_running && (sn != NULL)) {
1183 if (strstr(sn, "dev") == NULL) {
1184 tmpbuf = (char *)my_zalloc(PATH_MAX);
1185 (void) strcpy(tmpbuf,
1186 "/vol/dev/aliases/");
1187 (void) strcat(tmpbuf, sn);
1188 free(sn);
1189 sn = tmpbuf;
1190 }
1191 if (dev_name && !found) {
1192 if (!strstr(tmpbuf, tmpstr)) {
1193 continue;
1194 } else {
1195 found = 1;
1196 }
1197 }
1198 }
1199
1200 /*
1201 * Get device type information for CD/DVD devices.
1202 */
1203 if (is_cd(dev)) {
1204 if (check_device(t_dev,
1205 CHECK_DEVICE_IS_DVD_WRITABLE)) {
1206 device_type = DK_DVDR;
1207 } else if (check_device(t_dev,
1208 CHECK_DEVICE_IS_DVD_READABLE)) {
1209 device_type = DK_DVDROM;
1210 } else if (check_device(t_dev,
1211 CHECK_DEVICE_IS_CD_WRITABLE)) {
1212 device_type = DK_CDR;
1213 } else {
1214 device_type = DK_CDROM;
1215 }
1216 } else {
1217 device_type = ioctl(t_dev->d_fd,
1218 DKIOCGMEDIAINFO, &mediainfo);
1219 if (device_type < 0)
1220 device_type = 0;
1221 else
1222 device_type = mediainfo.dki_media_type;
1223 }
1224
1225 if (!ioctl(t_dev->d_fd, DKIOCREMOVABLE, &removable) &&
1226 !ioctl(t_dev->d_fd, DKIOCHOTPLUGGABLE,
1227 &hotpluggable)) {
1228 if (removable || hotpluggable) {
1229 removable_found++;
1230 pname = get_physical_name(sdev);
1231 if (sn) {
1232 (void) printf(" %4d. "
1233 "Volmgt Node: %s\n",
1234 removable_found, sn);
1235 (void) printf(" "
1236 "Logical Node: %s\n", sdev);
1237 (void) printf(" "
1238 "Physical Node: %s\n",
1239 pname);
1240 } else {
1241 (void) printf(" %4d. "
1242 "Logical Node: %s\n",
1243 removable_found, sdev);
1244 (void) printf(" "
1245 "Physical Node: %s\n",
1246 pname);
1247 }
1248 (void) printf(" Connected "
1249 "Device: %-8.8s %-16.16s "
1250 "%-4.4s\n",
1251 &t_dev->d_inq[8],
1252 &t_dev->d_inq[16],
1253 &t_dev->d_inq[32]);
1254 (void) printf(" Device "
1255 "Type: ");
1256 } else
1257 continue;
1258 } else
1259 continue;
1260
1261 switch (device_type) {
1262 case DK_CDROM:
1263 (void) printf("CD Reader\n");
1264 break;
1265 case DK_CDR:
1266 case DK_CDRW:
1267 (void) printf("CD Reader/Writer\n");
1268 break;
1269 case DK_DVDROM:
1270 (void) printf("DVD Reader\n");
1271 break;
1272 case DK_DVDR:
1273 case DK_DVDRAM:
1274 (void) printf("DVD Reader/Writer\n");
1275 break;
1276 case DK_FIXED_DISK:
1277 if (strstr((const char *)
1278 &t_dev->d_inq[16], "FD") ||
1279 strstr((const char *)
1280 &t_dev->d_inq[16], "LS-120"))
1281 (void) printf("Floppy "
1282 "drive\n");
1283 else
1284 (void) printf("Removable\n");
1285 break;
1286 case DK_FLOPPY:
1287 (void) printf("Floppy drive\n");
1288 break;
1289 case DK_ZIP:
1290 (void) printf("Zip drive\n");
1291 break;
1292 case DK_JAZ:
1293 (void) printf("Jaz drive\n");
1294 break;
1295 default:
1296 (void) printf("<Unknown>\n");
1297 DPRINTF1("\t %d\n", device_type);
1298 break;
1299 }
1300 get_media_info(t_dev, sdev, pname, sn);
1301 }
1302 fini_device(t_dev);
1303 }
1304
1305 (void) closedir(dir);
1306 return (removable_found);
1307 }
1308
1309 /*
1310 * Returns a device_t handle for a node returned by lookup_device()
1311 * and takes the user supplied name and stores it inside the node.
1312 */
1313 static device_t *
get_device(char * user_supplied,char * node)1314 get_device(char *user_supplied, char *node)
1315 {
1316 device_t *dev;
1317 int fd;
1318 char devnode[PATH_MAX];
1319 int size;
1320
1321 /*
1322 * we need to resolve any link paths to avoid fake files
1323 * such as /dev/rdsk/../../export/file.
1324 */
1325 size = resolvepath(node, devnode, PATH_MAX);
1326 if ((size <= 0) || (size >= (PATH_MAX - 1)))
1327 return (NULL);
1328
1329 /* resolvepath may not return a null terminated string */
1330 devnode[size] = '\0';
1331
1332
1333 /* the device node must be in /devices/ or /vol/dev/rdsk */
1334
1335 if ((strncmp(devnode, "/devices/", 9) != 0) &&
1336 (strncmp(devnode, "/vol/dev/rdsk", 13) != 0))
1337 return (NULL);
1338
1339 /* Turn on the privileges. */
1340 (void) __priv_bracket(PRIV_ON);
1341
1342 /*
1343 * Since we are currently running with the user euid it is
1344 * safe to try to open the file without checking access.
1345 */
1346
1347 fd = open(devnode, O_RDONLY|O_NDELAY);
1348
1349 /* Turn off the privileges. */
1350 (void) __priv_bracket(PRIV_OFF);
1351
1352 if (fd < 0) {
1353 return (NULL);
1354 }
1355
1356 dev = (device_t *)my_zalloc(sizeof (device_t));
1357
1358 dev->d_node = (char *)my_zalloc(strlen(devnode) + 1);
1359 (void) strcpy(dev->d_node, devnode);
1360
1361 dev->d_fd = fd;
1362
1363 dev->d_inq = (uchar_t *)my_zalloc(INQUIRY_DATA_LENGTH);
1364
1365 /* Turn on privileges. */
1366 (void) __priv_bracket(PRIV_ON);
1367 if (!inquiry(fd, dev->d_inq)) {
1368 DPRINTF1("USCSI ioctl failed %d\n",
1369 uscsi_error);
1370 free(dev->d_inq);
1371 free(dev->d_node);
1372 (void) close(dev->d_fd);
1373 free(dev);
1374 /* Turn off privileges. */
1375 (void) __priv_bracket(PRIV_OFF);
1376 return (NULL);
1377 }
1378 /* Turn off privileges. */
1379 (void) __priv_bracket(PRIV_OFF);
1380
1381 if (user_supplied) {
1382 dev->d_name = (char *)my_zalloc(strlen(user_supplied) + 1);
1383 (void) strcpy(dev->d_name, user_supplied);
1384 }
1385 return (dev);
1386 }
1387
1388 /*
1389 * Check for device specific characteristics.
1390 */
1391 int
check_device(device_t * dev,int cond)1392 check_device(device_t *dev, int cond)
1393 {
1394 uchar_t page_code[4];
1395
1396 /* Look at the capabilities page for this information */
1397 if (cond & CHECK_DEVICE_IS_CD_WRITABLE) {
1398 if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1399 (page_code[3] & 1)) {
1400 return (1);
1401 }
1402 }
1403
1404 if (cond & CHECK_DEVICE_IS_DVD_WRITABLE) {
1405 if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1406 (page_code[3] & 0x10)) {
1407 return (1);
1408 }
1409 }
1410
1411 if (cond & CHECK_DEVICE_IS_DVD_READABLE) {
1412 if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1413 (page_code[2] & 0x8)) {
1414 return (1);
1415 }
1416 }
1417
1418 return (0);
1419 }
1420
1421 /*
1422 * Builds an open()able device path from a user supplied node which can be
1423 * of the * form of /dev/[r]dsk/cxtxdx[sx] or cxtxdx[sx] or volmgt-name like
1424 * cdrom[n].
1425 * Returns the path found in 'found' and returns 1. Otherwise returns 0.
1426 */
1427 int
lookup_device(char * supplied,char * found)1428 lookup_device(char *supplied, char *found)
1429 {
1430 struct stat statbuf;
1431 int fd;
1432 char tmpstr[PATH_MAX];
1433
1434 /* Turn on privileges */
1435 (void) __priv_bracket(PRIV_ON);
1436
1437 /* If everything is fine and proper, no need to analyze */
1438 if ((stat(supplied, &statbuf) == 0) && S_ISCHR(statbuf.st_mode) &&
1439 ((fd = open(supplied, O_RDONLY|O_NDELAY)) >= 0)) {
1440 (void) close(fd);
1441 (void) strlcpy(found, supplied, PATH_MAX);
1442 /* Turn off privilege */
1443 (void) __priv_bracket(PRIV_OFF);
1444 return (1);
1445 }
1446
1447 /* Turn off privileges. */
1448 (void) __priv_bracket(PRIV_OFF);
1449
1450 if (strncmp(supplied, "/dev/rdsk/", 10) == 0)
1451 return (vol_lookup(supplied, found));
1452 if (strncmp(supplied, "/dev/dsk/", 9) == 0) {
1453 (void) snprintf(tmpstr, PATH_MAX, "/dev/rdsk/%s",
1454 (char *)strrchr(supplied, '/'));
1455
1456 if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
1457 (void) close(fd);
1458 (void) strlcpy(found, supplied, PATH_MAX);
1459 return (1);
1460 }
1461 if ((access(tmpstr, F_OK) == 0) && vol_running)
1462 return (vol_lookup(tmpstr, found));
1463 else
1464 return (0);
1465 }
1466 if ((strncmp(supplied, "cdrom", 5) != 0) &&
1467 (strlen(supplied) < 32)) {
1468 (void) snprintf(tmpstr, sizeof (tmpstr), "/dev/rdsk/%s",
1469 supplied);
1470 if (access(tmpstr, F_OK) < 0) {
1471 (void) strcat(tmpstr, "s2");
1472 }
1473 if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
1474 (void) close(fd);
1475 (void) strlcpy(found, tmpstr, PATH_MAX);
1476 return (1);
1477 }
1478 if ((access(tmpstr, F_OK) == 0) && vol_running)
1479 return (vol_lookup(tmpstr, found));
1480 }
1481 return (vol_name_to_dev_node(supplied, found));
1482 }
1483
1484 int
is_cd(char * node)1485 is_cd(char *node)
1486 {
1487 int fd;
1488 struct dk_cinfo cinfo;
1489
1490 fd = open(node, O_RDONLY|O_NDELAY);
1491 if (fd < 0)
1492 return (0);
1493 if (ioctl(fd, DKIOCINFO, &cinfo) < 0) {
1494 (void) close(fd);
1495 return (0);
1496 }
1497 if (cinfo.dki_ctype != DKC_CDROM)
1498 return (0);
1499 return (1);
1500 }
1501
1502 void
print_header(void)1503 print_header(void)
1504 {
1505 /* l10n_NOTE : Column spacing should be kept same */
1506 (void) printf(gettext(" Node "
1507 "Connected Device"));
1508 /* l10n_NOTE : Column spacing should be kept same */
1509 (void) printf(gettext(" Device type\n"));
1510 (void) printf(
1511 "---------------------------+---------------------------");
1512 (void) printf("-----+----------------\n");
1513 }
1514
1515 void
print_divider(void)1516 print_divider(void)
1517 {
1518 (void) printf(
1519 "---------------------------+---------------------------");
1520 (void) printf("-----+----------------\n");
1521 }
1522
1523 static void
fini_device(device_t * dev)1524 fini_device(device_t *dev)
1525 {
1526 free(dev->d_inq);
1527 free(dev->d_node);
1528 (void) close(dev->d_fd);
1529 if (dev->d_name)
1530 free(dev->d_name);
1531 free(dev);
1532 }
1533
1534 void *
my_zalloc(size_t size)1535 my_zalloc(size_t size)
1536 {
1537 void *ret;
1538
1539 ret = malloc(size);
1540 if (ret == NULL) {
1541
1542 /* Lets wait a sec. and try again */
1543 if (errno == EAGAIN) {
1544 (void) sleep(1);
1545 ret = malloc(size);
1546 }
1547
1548 if (ret == NULL) {
1549 (void) err_msg("%s\n", gettext(strerror(errno)));
1550 (void) err_msg(gettext(
1551 "Memory allocation failure, Exiting...\n"));
1552 exit(1);
1553 }
1554 }
1555 (void) memset(ret, 0, size);
1556 return (ret);
1557 }
1558
1559 static int
vol_name_to_dev_node(char * vname,char * found)1560 vol_name_to_dev_node(char *vname, char *found)
1561 {
1562 struct stat statbuf;
1563 char *p1;
1564 int i;
1565
1566 if (vname == NULL)
1567 return (0);
1568 if (vol_running)
1569 (void) volmgt_check(vname);
1570 p1 = media_findname(vname);
1571 if (p1 == NULL)
1572 return (0);
1573 if (stat(p1, &statbuf) < 0) {
1574 free(p1);
1575 return (0);
1576 }
1577 if (S_ISDIR(statbuf.st_mode)) {
1578 for (i = 0; i < 16; i++) {
1579 (void) snprintf(found, PATH_MAX, "%s/s%d", p1, i);
1580 if (access(found, F_OK) >= 0)
1581 break;
1582 }
1583 if (i == 16) {
1584 free(p1);
1585 return (0);
1586 }
1587 } else {
1588 (void) strlcpy(found, p1, PATH_MAX);
1589 }
1590 free(p1);
1591 return (1);
1592 }
1593
1594 /*
1595 * Searches for volume manager's equivalent char device for the
1596 * supplied pathname which is of the form of /dev/rdsk/cxtxdxsx
1597 */
1598 static int
vol_lookup(char * supplied,char * found)1599 vol_lookup(char *supplied, char *found)
1600 {
1601 char tmpstr[PATH_MAX], tmpstr1[PATH_MAX], *p;
1602 int i, ret;
1603
1604 (void) strlcpy(tmpstr, supplied, PATH_MAX);
1605 if ((p = volmgt_symname(tmpstr)) == NULL) {
1606 if (strstr(tmpstr, "s2") != NULL) {
1607 *((char *)(strrchr(tmpstr, 's') + 1)) = 0;
1608 for (i = 0; i < 16; i++) {
1609 (void) snprintf(tmpstr1, PATH_MAX, "%s%d",
1610 tmpstr, i);
1611 if ((p = volmgt_symname(tmpstr1)) != NULL)
1612 break;
1613 }
1614 } else if (strstr(tmpstr, "p0") != NULL) {
1615 *((char *)(strrchr(tmpstr, 'p') + 1)) = 0;
1616 for (i = 0; i < 5; i++) {
1617 (void) snprintf(tmpstr1, PATH_MAX, "%s%d",
1618 tmpstr, i);
1619 if ((p = volmgt_symname(tmpstr1)) != NULL)
1620 break;
1621 }
1622 } else
1623 return (0);
1624 if (p == NULL)
1625 return (0);
1626 }
1627
1628 ret = vol_name_to_dev_node(p, found);
1629 free(p);
1630 return (ret);
1631 }
1632
1633 /*PRINTFLIKE1*/
1634 void
err_msg(char * fmt,...)1635 err_msg(char *fmt, ...)
1636 {
1637 va_list ap;
1638
1639 va_start(ap, fmt);
1640 (void) vfprintf(stderr, fmt, ap);
1641 va_end(ap);
1642 }
1643
1644 int
inquiry(int fd,uchar_t * inq)1645 inquiry(int fd, uchar_t *inq)
1646 {
1647 struct uscsi_cmd *scmd;
1648
1649 scmd = get_uscsi_cmd();
1650 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
1651 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
1652 scmd->uscsi_cdb[0] = INQUIRY_CMD;
1653 scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH;
1654 scmd->uscsi_cdblen = 6;
1655 scmd->uscsi_bufaddr = (char *)inq;
1656 scmd->uscsi_buflen = INQUIRY_DATA_LENGTH;
1657 if ((uscsi_error = uscsi(fd, scmd)) < 0)
1658 return (0);
1659 return (1);
1660 }
1661
1662 struct uscsi_cmd *
get_uscsi_cmd(void)1663 get_uscsi_cmd(void)
1664 {
1665 (void) memset(&uscmd, 0, sizeof (uscmd));
1666 (void) memset(ucdb, 0, 16);
1667 uscmd.uscsi_cdb = ucdb;
1668 return (&uscmd);
1669 }
1670
1671 int
uscsi(int fd,struct uscsi_cmd * scmd)1672 uscsi(int fd, struct uscsi_cmd *scmd)
1673 {
1674 int ret, global_rqsense;
1675 int retries, max_retries = 5;
1676 int i;
1677
1678 /* set up for request sense extensions */
1679 if (!(scmd->uscsi_flags & USCSI_RQENABLE)) {
1680 scmd->uscsi_flags |= USCSI_RQENABLE;
1681 scmd->uscsi_rqlen = RQBUFLEN;
1682 scmd->uscsi_rqbuf = rqbuf;
1683 global_rqsense = 1;
1684 } else {
1685 global_rqsense = 0;
1686 }
1687
1688 /*
1689 * The device may be busy or slow and fail with a not ready status.
1690 * we'll allow a limited number of retries to give the drive time
1691 * to recover.
1692 */
1693 for (retries = 0; retries < max_retries; retries++) {
1694
1695 scmd->uscsi_status = 0;
1696
1697 if (global_rqsense)
1698 (void) memset(rqbuf, 0, RQBUFLEN);
1699
1700 DPRINTF("cmd:[");
1701 for (i = 0; i < scmd->uscsi_cdblen; i++)
1702 DPRINTF1("0x%02x ",
1703 (uchar_t)scmd->uscsi_cdb[i]);
1704 DPRINTF("]\n");
1705
1706 /*
1707 * We need to have root privledges in order to use
1708 * uscsi commands on the device.
1709 */
1710
1711 ret = ioctl(fd, USCSICMD, scmd);
1712
1713 /* maintain consistency in case of sgen */
1714 if ((ret == 0) && (scmd->uscsi_status == 2)) {
1715 ret = -1;
1716 errno = EIO;
1717 }
1718
1719 /* if error and extended request sense, retrieve errors */
1720 if (global_rqsense && (ret < 0) && (scmd->uscsi_status == 2)) {
1721 /*
1722 * The drive is not ready to recieve commands but
1723 * may be in the process of becoming ready.
1724 * sleep for a short time then retry command.
1725 * SENSE/ASC = 2/4 : not ready
1726 * ASCQ = 0 Not Reportable.
1727 * ASCQ = 1 Becoming ready.
1728 */
1729 if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
1730 ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1))) {
1731 total_retries++;
1732 (void) sleep(3);
1733 continue;
1734 }
1735
1736 /*
1737 * Device is not ready to transmit or a device reset
1738 * has occurred. wait for a short period of time then
1739 * retry the command.
1740 */
1741 if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
1742 (ASC(rqbuf) == 0x29))) {
1743 (void) sleep(3);
1744 total_retries++;
1745 continue;
1746 }
1747
1748 DPRINTF3("cmd: 0x%02x ret:%i status:%02x ",
1749 (uchar_t)scmd->uscsi_cdb[0], ret,
1750 scmd->uscsi_status);
1751 DPRINTF3(" sense: %02x ASC: %02x ASCQ:%02x\n",
1752 (uchar_t)SENSE_KEY(rqbuf),
1753 (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf));
1754 }
1755
1756 /* no errors we'll return */
1757 break;
1758 }
1759
1760 /* store the error status for later debug printing */
1761 if ((ret < 0) && (global_rqsense)) {
1762 uscsi_status = scmd->uscsi_status;
1763 rqstatus = scmd->uscsi_rqstatus;
1764 rqresid = scmd->uscsi_rqresid;
1765
1766 }
1767
1768 DPRINTF1("total retries: %d\n", total_retries);
1769
1770 return (ret);
1771 }
1772
1773 /*
1774 * will get the mode page only i.e. will strip off the header.
1775 */
1776 int
get_mode_page(int fd,int page_no,int pc,int buf_len,uchar_t * buffer)1777 get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer)
1778 {
1779 int ret;
1780 uchar_t byte2, *buf;
1781 uint_t header_len, page_len, copy_cnt;
1782
1783 byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
1784 buf = (uchar_t *)my_zalloc(256);
1785
1786 /* Ask 254 bytes only to make our IDE driver happy */
1787 ret = mode_sense(fd, byte2, 1, 254, buf);
1788 if (ret == 0) {
1789 free(buf);
1790 return (0);
1791 }
1792
1793 header_len = 8 + read_scsi16(&buf[6]);
1794 page_len = buf[header_len + 1] + 2;
1795
1796 copy_cnt = (page_len > buf_len) ? buf_len : page_len;
1797 (void) memcpy(buffer, &buf[header_len], copy_cnt);
1798 free(buf);
1799
1800 return (1);
1801 }
1802
1803 int
mode_sense(int fd,uchar_t pc,int dbd,int page_len,uchar_t * buffer)1804 mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
1805 {
1806 struct uscsi_cmd *scmd;
1807
1808 scmd = get_uscsi_cmd();
1809 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
1810 scmd->uscsi_buflen = page_len;
1811 scmd->uscsi_bufaddr = (char *)buffer;
1812 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
1813 scmd->uscsi_cdblen = 0xa;
1814 scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD;
1815 if (dbd) {
1816 /* don't return any block descriptors */
1817 scmd->uscsi_cdb[1] = 0x8;
1818 }
1819 /* the page code we want */
1820 scmd->uscsi_cdb[2] = pc;
1821 /* allocation length */
1822 scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
1823 scmd->uscsi_cdb[8] = page_len & 0xff;
1824
1825 if ((uscsi_error = uscsi(fd, scmd)) < 0)
1826 return (0);
1827 return (1);
1828 }
1829
1830 uint16_t
read_scsi16(void * addr)1831 read_scsi16(void *addr)
1832 {
1833 uchar_t *ad = (uchar_t *)addr;
1834 uint16_t ret;
1835
1836 ret = ((((uint16_t)ad[0]) << 8) | ad[1]);
1837 return (ret);
1838 }
1839
1840 /*
1841 * Allocate space for and return a pointer to a string
1842 * on the stack. If the string is null, create
1843 * an empty string.
1844 * Use destroy_data() to free when no longer used.
1845 */
1846 char *
alloc_string(char * s)1847 alloc_string(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 *
get_physical_name(char * path)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
get_media_info(device_t * t_dev,char * sdev,char * pname,char * sn)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 }
2093