1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 * rmf_menu.c :
28 *	Command line options to rmformat are processed in this file.
29 */
30
31#include "rmformat.h"
32#include <sys/smedia.h>
33#include <priv_utils.h>
34
35extern int32_t D_flag;
36extern int32_t e_flag;
37extern int32_t H_flag;
38extern int32_t U_flag;
39extern int32_t V_flag;
40extern int32_t b_flag;
41extern int32_t w_flag;
42extern int32_t W_flag;
43extern int32_t s_flag;
44extern int32_t c_flag;
45extern int32_t F_flag;
46extern int32_t R_flag;
47extern int32_t p_flag;
48extern int32_t l_flag;
49
50extern char *myname;
51extern char *slice_file;
52extern diskaddr_t repair_blk_no;
53extern int32_t quick_format;
54extern int32_t long_format;
55extern int32_t force_format;
56extern int32_t rw_protect_enable;
57extern int32_t rw_protect_disable;
58extern int32_t wp_enable_passwd;
59extern int32_t wp_disable_passwd;
60extern int32_t wp_enable;
61extern int32_t wp_disable;
62extern int32_t verify_write;
63extern char *dev_name;
64extern char *label;
65extern int total_devices_found;
66extern int removable_found;
67char *global_intr_msg;
68smmedium_prop_t med_info;
69int vol_running;
70
71extern void check_invalid_combinations();
72extern void check_invalid_combinations_again(int32_t);
73extern void process_options();
74extern void get_passwd(struct smwp_state *wp, int32_t confirm);
75extern int32_t valid_slice_file(smedia_handle_t, int32_t, char *,
76	struct extvtoc *);
77extern void trap_SIGINT();
78extern void release_SIGINT();
79extern int32_t verify(smedia_handle_t handle, int32_t fd,
80	diskaddr_t start_sector, uint32_t nblocks,
81	char *buf, int32_t flag, int32_t blocksize, int32_t no_raw_rw);
82extern void my_perror(char *err_string);
83extern void write_default_label(smedia_handle_t, int32_t fd);
84extern int find_device(int defer, char *tmpstr);
85
86void overwrite_metadata(int32_t fd, smedia_handle_t handle);
87
88int32_t write_sunos_label(int32_t fd, int32_t media_type);
89
90int32_t my_open(char *device_name, int32_t flags);
91int32_t check_and_unmount_vold(char *device_name, int32_t flag);
92int32_t check_and_unmount_scsi(char *device_name, int32_t flag);
93
94int32_t check_and_unmount_floppy(int32_t fd, int32_t flag);
95int32_t get_confirmation(void);
96
97
98static void	process_F_flag(smedia_handle_t handle, int32_t fd);
99static void	process_w_flag(smedia_handle_t handle);
100static void	process_W_flag(smedia_handle_t handle);
101static void	process_R_flag(smedia_handle_t handle);
102void		process_p_flag(smedia_handle_t handle, int32_t fd);
103static void	process_c_flag(smedia_handle_t handle);
104static void	process_V_flag(smedia_handle_t handle, int32_t fd);
105static void	process_s_flag(smedia_handle_t, int32_t fd);
106static void	process_e_flag(smedia_handle_t handle);
107static void	process_H_flag(smedia_handle_t handle, int32_t fd);
108static void	process_D_flag(smedia_handle_t handle, int32_t fd);
109static void	process_b_flag(int32_t fd);
110static void	process_l_flag(void);
111
112void
113process_options()
114{
115	int32_t fd;
116	smedia_handle_t handle;
117	int32_t m_scsi_umount = 0;
118	int32_t m_flp_umount = 0;
119	int32_t v_device_umount = 0;
120	int32_t umount_required = 0;
121	int32_t removable;
122	int32_t umount_failed = 0;
123	struct dk_minfo media;
124
125	check_invalid_combinations();
126
127	if (l_flag && !dev_name) {
128		process_l_flag();
129		return;
130	}
131
132	if (U_flag) {
133		if (!(F_flag || H_flag || D_flag)) {
134			F_flag = 1;
135			long_format = 1;
136		}
137	}
138
139	if (F_flag || w_flag || W_flag || R_flag || D_flag || H_flag ||
140	    V_flag || c_flag || b_flag || s_flag || e_flag) {
141		umount_required = 1;
142	}
143
144	fd = my_open(dev_name, O_RDONLY|O_NDELAY);
145	if (fd < 0)  {
146		PERROR("Could not open device");
147		(void) close(fd);
148		exit(1);
149	}
150
151	if (ioctl(fd, DKIOCREMOVABLE, &removable) < 0) {
152		PERROR("DKIOCREMOVABLE ioctl failed");
153		(void) close(fd);
154		exit(1);
155	}
156	if (!removable) {
157		(void) fprintf(stderr,
158		    gettext("Not a removable media device\n"));
159		(void) close(fd);
160		exit(1);
161	}
162
163	if (ioctl(fd, DKIOCGMEDIAINFO, &media) < 0) {
164		(void) fprintf(stderr,
165		    gettext("No media in specified device\n"));
166		(void) close(fd);
167		exit(1);
168	}
169
170	/* Check if volume manager has mounted this */
171	if (umount_required) {
172		v_device_umount = check_and_unmount_vold(dev_name, U_flag);
173		if (v_device_umount != 1) {
174			m_scsi_umount = check_and_unmount_scsi(dev_name,
175			    U_flag);
176			if (m_scsi_umount != 1) {
177				m_flp_umount = check_and_unmount_floppy(fd,
178				    U_flag);
179				if (m_flp_umount != 1) {
180					umount_failed = 1;
181				}
182			}
183		}
184	}
185
186	if (umount_required && U_flag && umount_failed) {
187		if (v_device_umount || m_scsi_umount || m_flp_umount) {
188			(void) fprintf(stderr,
189			    gettext("Could not unmount device.\n"));
190			(void) close(fd);
191			exit(1);
192		}
193	}
194
195	if (umount_required && !U_flag) {
196		if (v_device_umount || m_scsi_umount || m_flp_umount) {
197			(void) fprintf(stderr, gettext("Device mounted.\n"));
198			(void) fprintf(stderr,
199			    gettext("Requested operation can not be \
200performed on a mounted device.\n"));
201			(void) close(fd);
202			exit(1);
203		}
204	}
205	/* register the fd with the libsmedia */
206	handle = smedia_get_handle(fd);
207	if (handle == NULL) {
208		(void) fprintf(stderr,
209		    gettext("Failed to get libsmedia handle.\n"));
210		(void) close(fd);
211		exit(1);
212	}
213
214	if (smedia_get_medium_property(handle, &med_info) < 0) {
215		(void) fprintf(stderr,
216		    gettext("Get medium property failed \n"));
217		(void) smedia_release_handle(handle);
218		(void) close(fd);
219		exit(1);
220	}
221
222	DPRINTF1("media type %x\n", med_info.sm_media_type);
223	DPRINTF1("media block size %x\n", med_info.sm_blocksize);
224	DPRINTF1("media capacity %u\n", (uint32_t)med_info.sm_capacity);
225	DPRINTF3("media cyl %d head %d sect %d\n",
226	    med_info.sm_pcyl, med_info.sm_nhead, med_info.sm_nsect);
227	check_invalid_combinations_again(med_info.sm_media_type);
228
229	/*
230	 * Special handling for pcmcia, sometimes open the file in
231	 * read-write mode.
232	 */
233
234	if (med_info.sm_media_type == SM_PCMCIA_MEM) {
235		if (F_flag || H_flag || D_flag || (V_flag && verify_write)) {
236			(void) close(fd);
237			DPRINTF("Reopening device\n");
238			fd = my_open(dev_name, O_RDWR|O_NDELAY);
239			if (fd < 0)  {
240				PERROR("Could not open device");
241				(void) smedia_release_handle(handle);
242				(void) close(fd);
243				exit(1);
244			}
245		}
246	}
247
248	if (med_info.sm_media_type == SM_PCMCIA_ATA) {
249		if (V_flag || c_flag) {
250			(void) fprintf(stderr,
251			    gettext("Option not supported on PC ATA cards\n"));
252			(void) smedia_release_handle(handle);
253			(void) close(fd);
254			exit(1);
255		}
256		if (F_flag) {
257			/* same text as used by the format command */
258			(void) fprintf(stderr,
259			    gettext("Cannot format this drive. Please use your \
260Manufacturer supplied formatting utility.\n"));
261			(void) smedia_release_handle(handle);
262			(void) close(fd);
263			exit(1);
264		}
265	}
266
267	if (F_flag)
268		process_F_flag(handle, fd);
269	if (w_flag)
270		process_w_flag(handle);
271	if (W_flag)
272		process_W_flag(handle);
273	if (R_flag)
274		process_R_flag(handle);
275	if (p_flag)
276		process_p_flag(handle, fd);
277	if (D_flag)
278		process_D_flag(handle, fd);
279	if (H_flag)
280		process_H_flag(handle, fd);
281	if (V_flag)
282		process_V_flag(handle, fd);
283	if (c_flag)
284		process_c_flag(handle);
285	if (b_flag)
286		process_b_flag(fd);
287	if (s_flag)
288		process_s_flag(handle, fd);
289	if (e_flag)
290		process_e_flag(handle);
291	if (l_flag) {
292		process_l_flag();
293	}
294
295	(void) smedia_release_handle(handle);
296	(void) close(fd);
297}
298
299/*
300 * This routine handles the F_flag.
301 * This options should not be used for floppy. However,
302 * if this option is used for floppy, the option will
303 * be forced to SM_FORMAT_HD and smedia_format is called.
304 * Note that smedia_format is a blocked mode format and it
305 * returns only after the complete formatting is over.
306 */
307
308static void
309process_F_flag(smedia_handle_t handle, int32_t fd)
310{
311	uint32_t format_flag;
312	int32_t old_per = 0;
313	int32_t new_per, ret_val;
314
315	if (force_format) {
316		(void) fprintf(stderr,
317		    gettext("Formatting disk.\n"));
318	} else {
319		(void) fprintf(stderr,
320		    gettext("Formatting will erase all the data on disk.\n"));
321		if (!get_confirmation())
322			return;
323	}
324
325	if (quick_format)
326		format_flag = SM_FORMAT_QUICK;
327	else if (long_format)
328		format_flag = SM_FORMAT_LONG;
329	else if (force_format)
330		format_flag = SM_FORMAT_FORCE;
331
332	if (med_info.sm_media_type == SM_FLOPPY)
333		format_flag = SM_FORMAT_HD;
334
335	if ((med_info.sm_media_type != SM_FLOPPY) &&
336	    (med_info.sm_media_type != SM_PCMCIA_MEM) &&
337	    (med_info.sm_media_type != SM_SCSI_FLOPPY)) {
338		global_intr_msg = "Interrupting format may render the \
339medium useless";
340	} else {
341		global_intr_msg = "";
342	}
343		trap_SIGINT();
344
345	if (smedia_format(handle, format_flag, SM_FORMAT_IMMEDIATE) != 0) {
346		if (errno == EINVAL) {
347			(void) fprintf(stderr, gettext("Format failed.\n"));
348			(void) fprintf(stderr, gettext("The medium may not \
349be compatible for format operation.\n"));
350			(void) fprintf(stderr, gettext("read/write surface \
351scan may be used to get the effect of formatting.\n"));
352		} else {
353			PERROR("Format failed");
354		}
355		(void) smedia_release_handle(handle);
356		(void) close(fd);
357		exit(1);
358	}
359
360	/* CONSTCOND */
361	while (1) {
362		ret_val = smedia_check_format_status(handle);
363		if (ret_val == -1) {
364			if (errno != ENOTSUP) {
365				PERROR("Format failed");
366				(void) smedia_release_handle(handle);
367				(void) close(fd);
368				exit(1);
369			} else {
370				/* Background formatting is not supported */
371				break;
372			}
373		}
374		if (ret_val == 100) {
375			(void) printf("\n");
376			(void) fflush(stdout);
377			break;
378		}
379		new_per = (ret_val * 80)/100;
380		while (new_per >= old_per) {
381			(void) printf(".");
382			(void) fflush(stdout);
383			old_per++;
384		}
385		(void) sleep(6);
386	}
387
388	if ((med_info.sm_media_type == SM_FLOPPY) ||
389	    (med_info.sm_media_type == SM_PCMCIA_MEM) ||
390	    (med_info.sm_media_type == SM_SCSI_FLOPPY)) {
391		(void) write_sunos_label(fd, med_info.sm_media_type);
392	} else {
393
394		/*
395		 * Iomega drives don't destroy the data in quick format.
396		 * Do a best effort write to first 1024 sectors.
397		 */
398
399		if (quick_format)
400			overwrite_metadata(fd, handle);
401
402		(void) write_default_label(handle, fd);
403	}
404
405	release_SIGINT();
406}
407
408/*
409 * List removable devices.
410 */
411static void
412process_l_flag()
413{
414	int retry;
415	int removable;
416	int total_devices_found_last_time;
417	int defer = 0;
418	char *tmpstr;
419
420#define	MAX_RETRIES_FOR_SCANNING 3
421
422	vol_running = volmgt_running();
423	if (vol_running)
424		defer = 1;
425	(void) printf(gettext("Looking for devices...\n"));
426	total_devices_found_last_time = 0;
427
428	/*
429	 * Strip out any leading path.  For example, /dev/rdsk/c3t0d0s2
430	 * will result in tmpstr = c3t0d0s2.  dev_name is given as input
431	 * argument.
432	 */
433	if (dev_name) {
434		if ((tmpstr = strrchr(dev_name, '/')) != NULL) {
435			tmpstr += sizeof (char);
436		} else {
437			tmpstr = dev_name;
438		}
439	}
440
441	for (retry = 0; retry < MAX_RETRIES_FOR_SCANNING; retry++) {
442		removable = find_device(defer, tmpstr);
443		if (removable == -1)
444			break;
445
446		/*
447		 * We'll do a small sleep and retry the command if volume
448		 * manager is running and no removable devices are found.
449		 * This is because the device may be busy.
450		 */
451		if (defer || (vol_running && (removable == 0))) {
452			if ((total_devices_found == 0) ||
453			    (total_devices_found !=
454			    total_devices_found_last_time)) {
455				total_devices_found_last_time =
456				    total_devices_found;
457				(void) sleep(2);
458			} else {
459				/* Do the printing this time */
460				defer = 0;
461				removable_found = 0;
462			}
463
464		} else
465			break;
466	}
467	if (removable_found == 0)
468		(void) printf(gettext("No removables found.\n"));
469}
470
471/*
472 * The following three routines handle the write protect
473 * options. These options are mostly Iomega ZIP/Jaz centric.
474 * The following options are allowed :
475 *  No write protect <=> write protect without passwd : use -w flag
476 *  from any state to WP with passwd : use -W flag
477 *  from WP with passwd to no write protect : use -W flag
478 *  from any state to RWP with passwd : use -R flag
479 *  from RWP with passwd to no write protect : use -R flag
480 *
481 * The following transitions is not allowed
482 * WP with passwd or RWP to WP without passwd.
483 */
484
485static void
486process_w_flag(smedia_handle_t handle)
487{
488	int32_t rval;
489	int32_t med_status;
490	struct smwp_state wps;
491
492	if ((rval = smedia_get_protection_status((handle), &wps)) < 0) {
493		(void) fprintf(stderr,
494		    gettext("Could not get medium status \n"));
495		return;
496	}
497	med_status = wps.sm_new_state;
498
499	wps.sm_version = SMWP_STATE_V_1;
500
501	if (wp_enable) {	/* Enable write protect no password */
502
503		switch (med_status) {
504			case SM_WRITE_PROTECT_DISABLE  :
505				wps.sm_new_state =
506				    SM_WRITE_PROTECT_NOPASSWD;
507				wps.sm_passwd_len = 0;
508				rval = smedia_set_protection_status(handle,
509				    &wps);
510				if (rval == -1)
511					PERROR(WP_ERROR);
512				break;
513			case SM_WRITE_PROTECT_NOPASSWD :
514				(void) fprintf(stderr, gettext(WP_MSG_0));
515				break;
516			case SM_WRITE_PROTECT_PASSWD :
517				(void) fprintf(stderr, gettext(WP_MSG_1));
518				break;
519			case SM_READ_WRITE_PROTECT :
520				(void) fprintf(stderr, gettext(WP_MSG_2));
521				break;
522			case SM_STATUS_UNKNOWN :
523				default :
524				(void) fprintf(stderr, gettext(WP_UNKNOWN));
525				break;
526		}
527	} else if (wp_disable) {
528		switch (med_status) {
529			case SM_WRITE_PROTECT_NOPASSWD :
530				wps.sm_new_state =
531				    SM_WRITE_PROTECT_DISABLE;
532				wps.sm_passwd_len = 0;
533				rval = smedia_set_protection_status(handle,
534				    &wps);
535				if (rval == -1)
536					PERROR(WP_ERROR);
537				break;
538			case SM_WRITE_PROTECT_DISABLE  :
539				(void) fprintf(stderr, gettext(WP_MSG_3));
540				break;
541			case SM_WRITE_PROTECT_PASSWD :
542				(void) fprintf(stderr, gettext(WP_MSG_1));
543				break;
544			case SM_READ_WRITE_PROTECT :
545				(void) fprintf(stderr, gettext(WP_MSG_2));
546				break;
547			case SM_STATUS_UNKNOWN :
548				default :
549				(void) fprintf(stderr, gettext(WP_UNKNOWN));
550				break;
551		}
552	}
553}
554
555static void
556process_W_flag(smedia_handle_t handle)
557{
558	int32_t rval;
559	int32_t med_status;
560	struct smwp_state wps;
561
562	DPRINTF("Write protect with password\n");
563
564	if ((rval = smedia_get_protection_status((handle), &wps)) < 0) {
565		(void) fprintf(stderr,
566		    gettext("Could not get medium status \n"));
567		return;
568	}
569	med_status = wps.sm_new_state;
570
571	wps.sm_version = SMWP_STATE_V_1;
572
573	if (wp_enable_passwd) {	/* Enable write protect  */
574		switch (med_status) {
575			case SM_WRITE_PROTECT_DISABLE  :
576			case SM_WRITE_PROTECT_NOPASSWD :
577				DPRINTF("Getting passwd\n");
578				get_passwd(&wps, 1);
579				wps.sm_new_state =
580				    SM_WRITE_PROTECT_PASSWD;
581				rval = smedia_set_protection_status(handle,
582				    &wps);
583				if (rval == -1) {
584					PERROR(WP_ERROR);
585				}
586				break;
587			case SM_READ_WRITE_PROTECT :
588				(void) fprintf(stderr, gettext(WP_MSG_4));
589				(void) fprintf(stderr, gettext(WP_MSG_5));
590				get_passwd(&wps, 0);
591				wps.sm_new_state =
592				    SM_WRITE_PROTECT_PASSWD;
593				rval = smedia_set_protection_status(handle,
594				    &wps);
595				if (rval == -1) {
596					if (errno == EACCES) {
597						(void) fprintf(stderr,
598						    gettext(WP_MSG_10));
599					} else {
600						PERROR(WP_ERROR);
601					}
602				}
603				break;
604			case SM_WRITE_PROTECT_PASSWD :
605				(void) fprintf(stderr, gettext(WP_MSG_6));
606				break;
607			case SM_STATUS_UNKNOWN :
608				default :
609				(void) fprintf(stderr,
610				    gettext(WP_UNKNOWN));
611				break;
612		}
613	} else if (wp_disable_passwd) {
614		switch (med_status) {
615			case SM_WRITE_PROTECT_PASSWD :
616				get_passwd(&wps, 0);
617				wps.sm_new_state =
618				    SM_WRITE_PROTECT_DISABLE;
619				rval = smedia_set_protection_status(handle,
620				    &wps);
621				if (rval == -1) {
622					if (errno == EACCES) {
623						(void) fprintf(stderr,
624						    gettext(WP_MSG_10));
625					} else {
626						PERROR(WP_ERROR);
627					}
628				}
629				break;
630			case SM_READ_WRITE_PROTECT :
631				(void) fprintf(stderr, gettext(WP_MSG_2));
632				break;
633			case SM_WRITE_PROTECT_NOPASSWD :
634				(void) fprintf(stderr, gettext(WP_MSG_7));
635				break;
636			case SM_WRITE_PROTECT_DISABLE  :
637				(void) fprintf(stderr, gettext(WP_MSG_3));
638				break;
639			case SM_STATUS_UNKNOWN :
640				default :
641				(void) fprintf(stderr, gettext(WP_UNKNOWN));
642				break;
643		}
644	}
645}
646
647static void
648process_R_flag(smedia_handle_t handle)
649{
650	int32_t rval;
651	int32_t med_status;
652	struct smwp_state wps;
653
654	DPRINTF("Read Write protect \n");
655
656	if ((rval = smedia_get_protection_status((handle), &wps)) < 0) {
657		(void) fprintf(stderr,
658		    gettext("Could not get medium status \n"));
659		return;
660	}
661	med_status = wps.sm_new_state;
662
663	wps.sm_version = SMWP_STATE_V_1;
664
665	if (rw_protect_enable) {	/* Enable write protect  */
666		switch (med_status) {
667			case SM_WRITE_PROTECT_DISABLE  :
668			case SM_WRITE_PROTECT_NOPASSWD :
669				DPRINTF("Getting passwd\n");
670				get_passwd(&wps, 1);
671				wps.sm_new_state =
672				    SM_READ_WRITE_PROTECT;
673				rval = smedia_set_protection_status(handle,
674				    &wps);
675				if (rval == -1)
676					PERROR(WP_ERROR);
677				break;
678			case SM_WRITE_PROTECT_PASSWD :
679				(void) fprintf(stderr, gettext(WP_MSG_8));
680				(void) fprintf(stderr, gettext(WP_MSG_9));
681				get_passwd(&wps, 0);
682				wps.sm_new_state =
683				    SM_READ_WRITE_PROTECT;
684				rval = smedia_set_protection_status(handle,
685				    &wps);
686				if (rval == -1) {
687					if (errno == EACCES) {
688						(void) fprintf(stderr,
689						    gettext(WP_MSG_10));
690					} else {
691						PERROR(WP_ERROR);
692					}
693				}
694				break;
695			case SM_READ_WRITE_PROTECT :
696				(void) fprintf(stderr, gettext(WP_MSG_4));
697				break;
698			case SM_STATUS_UNKNOWN :
699				default :
700				(void) fprintf(stderr, gettext(WP_UNKNOWN));
701				break;
702		}
703	} else if (rw_protect_disable) {
704		switch (med_status) {
705			case SM_READ_WRITE_PROTECT :
706			case SM_STATUS_UNKNOWN :
707				get_passwd(&wps, 0);
708				wps.sm_new_state =
709				    SM_WRITE_PROTECT_DISABLE;
710				rval = smedia_set_protection_status(handle,
711				    &wps);
712				if (rval == -1) {
713					if (errno == EACCES) {
714						(void) fprintf(stderr,
715						    gettext(WP_MSG_10));
716					} else {
717						PERROR(WP_ERROR);
718					}
719				}
720				break;
721			case SM_WRITE_PROTECT_PASSWD :
722				(void) fprintf(stderr, gettext(WP_MSG_1));
723					break;
724			case SM_WRITE_PROTECT_NOPASSWD :
725				(void) fprintf(stderr, gettext(WP_MSG_7));
726				break;
727			case SM_WRITE_PROTECT_DISABLE  :
728				(void) fprintf(stderr, gettext(WP_MSG_3));
729				break;
730			default :
731				(void) fprintf(stderr, gettext(WP_UNKNOWN));
732				break;
733		}
734	}
735}
736
737void
738process_p_flag(smedia_handle_t handle, int32_t fd)
739{
740	int32_t med_status;
741	smwp_state_t	wps;
742
743	med_status = smedia_get_protection_status((handle), &wps);
744	DPRINTF("Could not get medium status \n");
745
746	/*
747	 * Workaround in case mode sense fails.
748	 *
749	 * Also, special handling for PCMCIA. PCMCIA does not have any
750	 * ioctl to find out the write protect status. So, open the
751	 * device with O_RDWR. If it passes, it is not write protected,
752	 * otherwise it is write protected.
753	 * If it fails, reopen with O_RDONLY, may be some other
754	 * operation can go through.
755	 */
756	if ((med_status < 0) || (med_info.sm_media_type == SM_PCMCIA_MEM) ||
757	    (med_info.sm_media_type == SM_PCMCIA_ATA)) {
758		(void) close(fd);
759		DPRINTF("Reopening device for -p option\n");
760		fd = my_open(dev_name, O_RDONLY|O_NDELAY);
761		if (fd < 0)  {
762			if (p_flag)  {
763				PERROR("Could not open device");
764				(void) smedia_release_handle(handle);
765				(void) close(fd);
766				exit(1);
767			} else {
768				(void) fprintf(stdout,
769				    gettext("<Unknown>\n"));
770				(void) smedia_release_handle(handle);
771				(void) close(fd);
772				return;
773			}
774			fd = my_open(dev_name, O_RDWR|O_NDELAY);
775			if (fd < 0)  {
776				(void) fprintf(stdout,
777				gettext("Medium is write protected.\n"));
778			}
779		} else { /* Open succeeded */
780			(void) fprintf(stdout,
781			    gettext("Medium is not write protected.\n"));
782		}
783		return;
784	}
785	med_status = wps.sm_new_state;
786	switch (med_status) {
787
788		case SM_READ_WRITE_PROTECT :
789			(void) fprintf(stdout,
790			gettext("Medium is read-write protected.\n"));
791			break;
792		case SM_WRITE_PROTECT_PASSWD :
793			(void) fprintf(stdout,
794			gettext("Medium is write protected with password.\n"));
795			break;
796		case SM_WRITE_PROTECT_NOPASSWD :
797			(void) fprintf(stdout,
798			gettext("Medium is write protected.\n"));
799			break;
800		case SM_WRITE_PROTECT_DISABLE  :
801			(void) fprintf(stdout,
802			gettext("Medium is not write protected.\n"));
803			break;
804		case SM_STATUS_UNKNOWN :
805			default:
806			(void) fprintf(stdout,
807			    gettext("Unknown write protect status.\n"));
808			break;
809	}
810}
811
812static void
813process_c_flag(smedia_handle_t handle)
814{
815	char error_string[256];
816
817	if (smedia_reassign_block(handle, repair_blk_no) != 0) {
818		(void) snprintf(error_string, 255,
819		    gettext("Could not repair block no %llu"), repair_blk_no);
820		PERROR(error_string);
821		return;
822	}
823}
824
825/*
826 * This routine handles the -V (verify) option.
827 * There can be devices without rw_read option. If the raw_read
828 * and raw_write are not supported by the interface, then read and
829 * write system calls are used. It is assumed that either both
830 * raw_read and raw_write are supported or both are unsupported.
831 */
832
833static void
834process_V_flag(smedia_handle_t handle, int32_t fd)
835{
836	int32_t ret;
837	uint32_t j;
838	diskaddr_t bn;
839	char *read_buf, *write_buf;
840	int32_t old_per = 0;
841	int32_t new_per;
842	int32_t no_raw_rw = 0;
843	int32_t verify_size;
844	diskaddr_t capacity;
845	int32_t blocksize;
846
847	DPRINTF("ANALYSE MEDIA \n");
848
849	ret = smedia_get_medium_property(handle, &med_info);
850	if (ret == -1) {
851		DPRINTF("get_media_info failed\n");
852		return;
853	}
854
855	DPRINTF1("media_type %d\n", med_info.sm_media_type);
856	DPRINTF1("sector_size %d\n", med_info.sm_blocksize);
857	DPRINTF1("num_sectors %u\n", (uint32_t)med_info.sm_capacity);
858	DPRINTF1("nsect	 %d\n", med_info.sm_nsect);
859
860	blocksize = med_info.sm_blocksize;
861
862	capacity = (uint32_t)med_info.sm_capacity;
863	verify_size = (med_info.sm_nsect > 64) ? 64 : med_info.sm_nsect;
864	read_buf = (char *)malloc(blocksize * verify_size);
865	if (read_buf == NULL) {
866		DPRINTF("Could not allocate memory\n");
867		return;
868	}
869	write_buf = (char *)malloc(blocksize * verify_size);
870	if (write_buf == NULL) {
871		DPRINTF("Could not allocate memory\n");
872		free(read_buf);
873		return;
874	}
875
876	if (!verify_write) {
877		DPRINTF("Non-destructive verify \n");
878		for (bn = 0; bn < (uint32_t)med_info.sm_capacity;
879		    bn += verify_size) {
880			new_per = (bn * 80)/(uint32_t)med_info.sm_capacity;
881			if (new_per >= old_per) {
882				(void) printf(".");
883				(void) fflush(stdout);
884				old_per++;
885			}
886			DPRINTF2("Reading %d blks starting at %llu\n",
887			    verify_size, bn);
888			ret = verify(handle, fd, bn, verify_size, read_buf,
889			    VERIFY_READ, blocksize, no_raw_rw);
890			if ((ret == -1) && (errno == ENOTSUP)) {
891				no_raw_rw = 1;
892				ret = verify(handle, fd, bn, verify_size,
893				    read_buf,
894				    VERIFY_READ, blocksize, no_raw_rw);
895				capacity = (diskaddr_t)med_info.sm_pcyl *
896				    med_info.sm_nhead * med_info.sm_nsect;
897			}
898
899			if (ret != 0) {
900				for (j = 0; j < verify_size; j++) {
901					if ((bn + j) >= capacity)
902							return;
903					DPRINTF2(
904					    "Reading %d blks starting "
905					    "at %llu\n", 1, bn + j);
906					ret = verify(handle, fd, bn + j, 1,
907					    read_buf,
908					    VERIFY_READ, blocksize,
909					    no_raw_rw);
910					if (ret == -1) {
911						(void) printf(
912						    "Bad block %llu\n",
913						    bn + j);
914					}
915				}
916			}
917		}
918	} else {
919
920		DPRINTF("Destrutive verify \n");
921		for (bn = 0; bn < (uint32_t)med_info.sm_capacity;
922		    bn += verify_size) {
923			new_per = (bn * 80)/(uint32_t)med_info.sm_capacity;
924			if (new_per >= old_per) {
925				(void) printf(".");
926
927				(void) fflush(stdout);
928				old_per++;
929			}
930
931			for (j = 0; j < blocksize * verify_size; j++) {
932				write_buf[j] = (bn | j) & 0xFF;
933			}
934			DPRINTF2("Writing %d blks starting at %llu\n",
935			    verify_size, bn);
936			ret = verify(handle, fd, bn, verify_size, write_buf,
937			    VERIFY_WRITE, blocksize, no_raw_rw);
938
939			if (ret != 0) {
940				for (j = 0; j < verify_size; j++) {
941					if ((bn + j) >= capacity)
942							break;
943					DPRINTF2(
944					    "Writing %d blks starting "
945					    "at %llu\n", 1, bn + j);
946					ret = verify(handle, fd, bn + j, 1,
947					    write_buf,
948					    VERIFY_WRITE, blocksize,
949					    no_raw_rw);
950					if (ret == -1) {
951						(void) printf(
952						    "Bad block %llu\n", bn + j);
953					}
954				}
955			}
956			DPRINTF2("Read after write  %d blks starting at %llu\n",
957			    verify_size, bn);
958			ret = verify(handle, fd, bn, verify_size,
959			    read_buf, VERIFY_READ, blocksize, no_raw_rw);
960
961			if (ret != 0) {
962				for (j = 0; j < verify_size; j++) {
963					if ((bn + j) >= capacity)
964							return;
965					DPRINTF2(
966					    "Read after write  %d blks "
967					    "starting at %llu\n", 1, bn + j);
968					ret = verify(handle, fd, bn + j, 1,
969					    read_buf, VERIFY_READ,
970					    blocksize, no_raw_rw);
971					if (ret == -1) {
972						(void) printf(
973						    "Bad block %llu\n", bn + j);
974					}
975				}
976			}
977
978
979		}
980	}
981}
982
983static void
984process_s_flag(smedia_handle_t handle, int32_t fd)
985{
986	int32_t i, ret;
987	struct extvtoc v_toc, t_vtoc;
988	if (valid_slice_file(handle, fd, slice_file, &v_toc)) {
989			(void) smedia_release_handle(handle);
990			(void) close(fd);
991			exit(1);
992	}
993
994	(void) memset(&t_vtoc, 0, sizeof (t_vtoc));
995
996
997	t_vtoc.v_nparts = V_NUMPAR;
998	t_vtoc.v_sanity = VTOC_SANE;
999	t_vtoc.v_version = V_VERSION;
1000	t_vtoc.v_sectorsz = DEV_BSIZE;
1001
1002	/* Get existing Vtoc, don't bother if it fails. */
1003
1004	/* Turn on privileges. */
1005	(void) __priv_bracket(PRIV_ON);
1006
1007	(void) read_extvtoc(fd, &t_vtoc);
1008
1009	/* Turn off privileges. */
1010	(void) __priv_bracket(PRIV_OFF);
1011
1012	for (i = 0; i < V_NUMPAR; i++) {
1013		t_vtoc.v_part[i].p_start = v_toc.v_part[i].p_start;
1014		t_vtoc.v_part[i].p_size = v_toc.v_part[i].p_size;
1015		t_vtoc.v_part[i].p_tag	= v_toc.v_part[i].p_tag;
1016		t_vtoc.v_part[i].p_flag = v_toc.v_part[i].p_flag;
1017	}
1018
1019	errno = 0;
1020
1021
1022	/* Turn on privileges. */
1023	(void) __priv_bracket(PRIV_ON);
1024
1025	ret = write_extvtoc(fd, &t_vtoc);
1026
1027	/* Turn off privileges. */
1028	(void) __priv_bracket(PRIV_OFF);
1029
1030	if (ret < 0)  {
1031#ifdef sparc
1032		PERROR("write VTOC failed");
1033		DPRINTF1("Errno = %d\n", errno);
1034#else /* i386 */
1035		if (errno == EIO) {
1036			PERROR("No Solaris partition, eject & retry");
1037			DPRINTF1("Errno = %d\n", errno);
1038		} else {
1039			PERROR("write VTOC failed");
1040			DPRINTF1("Errno = %d\n", errno);
1041		}
1042#endif
1043	}
1044}
1045static void
1046process_e_flag(smedia_handle_t handle)
1047{
1048	if (smedia_eject(handle) < 0) {
1049		PERROR("Eject failed");
1050	}
1051}
1052static void
1053process_H_flag(smedia_handle_t handle, int32_t fd)
1054{
1055	uint32_t cyl, head;
1056	int32_t old_per = 0;
1057	int32_t new_per;
1058
1059	(void) fprintf(stderr,
1060	    gettext("Formatting will erase all the data on disk.\n"));
1061	if (!get_confirmation())
1062		return;
1063
1064	for (cyl = 0; cyl < med_info.sm_pcyl; cyl++) {
1065		for (head = 0; head < med_info.sm_nhead; head++) {
1066			if (smedia_format_track(handle, cyl, head, SM_FORMAT_HD)
1067			    < 0) {
1068					PERROR("Format failed");
1069					return;
1070			}
1071		}
1072		new_per = (cyl * 80)/med_info.sm_pcyl;
1073		while (new_per >= old_per) {
1074			(void) printf(".");
1075			(void) fflush(stdout);
1076			old_per++;
1077		}
1078	}
1079
1080	(void) write_sunos_label(fd, med_info.sm_media_type);
1081}
1082
1083static void
1084process_D_flag(smedia_handle_t handle, int32_t fd)
1085{
1086	uint32_t cyl, head;
1087	int32_t old_per = 0;
1088	int32_t new_per;
1089
1090	(void) fprintf(stderr,
1091	    gettext("Formatting will erase all the data on disk.\n"));
1092	if (!get_confirmation())
1093		return;
1094	for (cyl = 0; cyl < med_info.sm_pcyl; cyl++) {
1095		for (head = 0; head < med_info.sm_nhead; head++) {
1096			if (smedia_format_track(handle, cyl, head, SM_FORMAT_DD)
1097			    < 0) {
1098					PERROR("Format failed");
1099					return;
1100			}
1101		}
1102		new_per = (cyl * 80)/med_info.sm_pcyl;
1103		while (new_per >= old_per) {
1104			(void) printf(".");
1105			(void) fflush(stdout);
1106			old_per++;
1107		}
1108	}
1109	(void) write_sunos_label(fd, med_info.sm_media_type);
1110}
1111
1112/*
1113 * This routine handles the -b (label) option.
1114 * Please note that, this will fail if there is no valid vtoc is
1115 * there on the medium and the vtoc is not faked.
1116 */
1117
1118static void
1119process_b_flag(int32_t fd)
1120{
1121	int32_t ret, nparts;
1122	struct extvtoc v_toc;
1123	struct dk_gpt *vtoc64;
1124
1125	/* For EFI disks. */
1126	if (efi_type(fd)) {
1127		if (efi_alloc_and_read(fd, &vtoc64) < 0) {
1128			/*
1129			 * If reading the vtoc failed, try to
1130			 * auto-sense the disk configuration.
1131			 */
1132			if (efi_auto_sense(fd, &vtoc64) < 0) {
1133				(void) fprintf(stderr,
1134				    gettext("Could not write label.\n"));
1135				return;
1136			}
1137		}
1138		for (nparts = 0; nparts < vtoc64->efi_nparts;
1139		    nparts++) {
1140			if (vtoc64->efi_parts[nparts].p_tag ==
1141			    V_RESERVED) {
1142			if (vtoc64->efi_parts[nparts].p_name) {
1143				(void) strncpy(
1144				    vtoc64->efi_parts[nparts].p_name, label,
1145				    EFI_PART_NAME_LEN);
1146			}
1147			break;
1148		}
1149		}
1150		if (efi_write(fd, vtoc64) != 0) {
1151			(void) efi_err_check(vtoc64);
1152			(void) fprintf(stderr,
1153			    gettext("Could not write label.\n"));
1154		}
1155		return;
1156	}
1157
1158	/* Get existing Vtoc */
1159
1160	/* Turn on privileges. */
1161	(void) __priv_bracket(PRIV_ON);
1162
1163	ret = read_extvtoc(fd, &v_toc);
1164
1165	/* Turn off privileges */
1166	(void) __priv_bracket(PRIV_OFF);
1167
1168	if (ret < 0) {
1169#ifdef sparc
1170		PERROR("read VTOC failed");
1171		DPRINTF1("Errno = %d\n", errno);
1172#else /* i386 */
1173		if (errno == EIO) {
1174			PERROR("No Solaris partition, eject & retry");
1175			DPRINTF1("Errno = %d\n", errno);
1176		} else {
1177			PERROR("read VTOC failed");
1178			DPRINTF1("Errno = %d\n", errno);
1179		}
1180#endif
1181		return;
1182	}
1183
1184	(void) strncpy(v_toc.v_volume, label, LEN_DKL_VVOL);
1185
1186
1187	/* Turn on the privileges. */
1188	(void) __priv_bracket(PRIV_ON);
1189
1190	ret = write_extvtoc(fd, &v_toc);
1191
1192	/* Turn off the privileges. */
1193	(void) __priv_bracket(PRIV_OFF);
1194
1195	if (ret < 0) {
1196#ifdef sparc
1197		PERROR("write VTOC failed");
1198		DPRINTF1("Errno = %d\n", errno);
1199#else /* i386 */
1200		if (errno == EIO) {
1201			PERROR("No Solaris partition, eject & retry");
1202			DPRINTF1("Errno = %d\n", errno);
1203		} else {
1204			PERROR("write VTOC failed");
1205			DPRINTF1("Errno = %d\n", errno);
1206		}
1207#endif
1208	}
1209}
1210