1 /* Copyright 1996 Grant R. Guenther, based on work of Itai Nahshon
2 * http://www.torque.net/ziptool.html
3 * Copyright 1997-2002,2007-2009 Alain Knaff.
4 * This file is part of mtools.
6 * Mtools is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Mtools is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
20 * Iomega Zip/Jaz drive tool
21 * change protection mode and eject disk
24 /* mzip.c by Markus Gyger <mgyger@itr.ch> */
25 /* This code is based on ftp://gear.torque.net/pub/ziptool.c */
26 /* by Grant R. Guenther with the following copyright notice: */
28 /* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */
29 /* http://www.torque.net/ziptool.html */
32 /* Unprotect-till-eject modes and mount tests added
33 * by Ilya Ovchinnikov <ilya@socio.msu.su>
36 #include "sysincludes.h"
41 #define _PASSWORD_LEN 33
47 #include <sys/mount.h>
49 #define _LINUX_KDEV_T_H 1 /* don't redefine MAJOR/MINOR */
58 static int zip_cmd(int priv, int fd, unsigned char cdb[6], int clen,
59 scsi_io_mode_t mode, void *data, size_t len,
66 r = scsi_cmd(fd, cdb, clen, mode, data, len, extra_data);
72 static int test_mounted ( char *dev )
76 struct MT_STAT st_dev, st_mnt;
79 * Now check if any partition of this device is already mounted (this
80 * includes checking if the device is mounted under a different name).
83 if (MT_STAT (dev, &st_dev)) {
84 fprintf (stderr, "%s: stat(%s) failed: %s.\n",
85 progname, dev, strerror (errno));
89 if (!S_ISBLK (st_dev.st_mode)) /* not a block device, cannot
94 # define _PATH_MOUNTED "/etc/mtab"
97 if ((mtab = setmntent (_PATH_MOUNTED, "r")) == NULL) {
98 fprintf (stderr, "%s: can't open %s.\n",
99 progname, _PATH_MOUNTED);
103 while ( ( mnt = getmntent (mtab) ) ) {
107 || !strcmp (mnt->mnt_type, MNTTYPE_SWAP)
110 || !strcmp (mnt->mnt_type, MNTTYPE_NFS)
112 || !strcmp (mnt->mnt_type, "proc")
113 || !strcmp (mnt->mnt_type, "smbfs")
114 #ifdef MNTTYPE_IGNORE
115 || !strcmp (mnt->mnt_type, MNTTYPE_IGNORE)
120 if (MT_STAT (mnt->mnt_fsname, &st_mnt)) {
124 if (S_ISBLK (st_mnt.st_mode)) {
126 /* on Linux, warn also if the device is on the same
128 if (MAJOR(st_mnt.st_rdev) == MAJOR(st_dev.st_rdev) &&
129 MINOR(st_mnt.st_rdev) >= MINOR(st_dev.st_rdev) &&
130 MINOR(st_mnt.st_rdev) <= MINOR(st_dev.st_rdev)+15){
132 "Device %s%d is mounted on %s.\n",
134 MINOR(st_mnt.st_rdev) -
135 MINOR(st_dev.st_rdev),
138 if(st_mnt.st_rdev != st_dev.st_rdev) {
144 } /* keep Emacs indentation happy */
154 static void usage(int ret)
157 "Mtools version %s, dated %s\n",
160 "Usage: %s [-V] [-q] [-e] [-u] [-r|-w|-p|-x] [drive:]\n"
161 "\t-q print status\n"
163 "\t-f eject disk even when mounted\n"
164 "\t-r write protected (read-only)\n"
165 "\t-w not write-protected (read-write)\n"
166 "\t-p password write protected\n"
167 "\t-x password protected\n"
168 "\t-u unprotect till disk ejecting\n",
179 ZIP_UNLOCK_TIL_EJECT = 8
182 static enum mode_t get_zip_status(int priv, int fd, void *extra_data)
184 unsigned char status[128];
185 unsigned char cdb[6] = { 0x06, 0, 0x02, 0, sizeof status, 0 };
187 if (zip_cmd(priv, fd, cdb, 6, SCSI_IO_READ,
188 status, sizeof status, extra_data) == -1) {
192 return status[21] & 0xf;
196 static int short_command(int priv, int fd, int cmd1, int cmd2,
197 int cmd3, const char *data, void *extra_data)
199 unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 };
205 return zip_cmd(priv, fd, cdb, 6, SCSI_IO_WRITE,
206 (char *) data, data ? strlen(data) : 0, extra_data);
210 static int iomega_command(int priv, int fd, int mode, const char *data,
213 return short_command(priv, fd,
214 SCSI_IOMEGA, mode, data ? strlen(data) : 0,
218 static int door_command(int priv, int fd, int cmd1, int cmd2,
221 return short_command(priv, fd, cmd1, 0, cmd2, 0, extra_data);
224 void mzip(int argc, char **argv, int type)
231 char name[EXPAND_BUF];
235 ZIP_MODE_CHANGE = 1 << 2,
239 enum mode_t newMode = ZIP_RW;
240 enum mode_t oldMode = ZIP_RW;
243 if(request & ZIP_MODE_CHANGE) usage(1); \
244 request |= ZIP_MODE_CHANGE; \
248 /* get command line options */
249 if(helpFlag(argc, argv))
251 while ((c = getopt(argc, argv, "i:efpqrwxuh")) != EOF) {
254 set_cmd_line_image(optarg, SCSI_FLAG);
257 if (get_real_uid()) {
259 "Only root can use force. Sorry.\n");
262 request |= ZIP_FORCE;
264 case 'e': /* eject */
265 request |= ZIP_EJECT;
267 case 'q': /* status query */
268 request |= ZIP_STATUS;
271 case 'p': /* password read-only */
273 case 'r': /* read-only */
275 case 'w': /* read-write */
277 case 'x': /* password protected */
279 case 'u': /* password protected */
280 setMode(ZIP_UNLOCK_TIL_EJECT)
283 default: /* unrecognized */
289 if (request == ZIP_NIX) request = ZIP_STATUS; /* default action */
291 if (argc - optind > 1 ||
292 (argc - optind == 1 &&
293 (!argv[optind][0] || argv[optind][1] != ':')))
296 drive = toupper(argc - optind == 1 ? argv[argc - 1][0] : ':');
298 for (dev = devices; dev->name; dev++) {
299 unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 };
315 if (dev->drive != drive)
317 expand(dev->name, name);
318 if ((request & (ZIP_MODE_CHANGE | ZIP_EJECT)) &&
319 !(request & ZIP_FORCE) &&
320 test_mounted(name)) {
322 "Can\'t change status of/eject mounted device\n");
327 if(IS_PRIVILEGED(dev))
329 fd = scsi_open(name, O_RDONLY
335 if(IS_PRIVILEGED(dev))
338 /* need readonly, else we can't
339 * open the drive on Solaris if
345 if (!(request & (ZIP_MODE_CHANGE | ZIP_STATUS)))
346 /* if no mode change or ZIP specific status is
347 * involved, the command (eject) is applicable
351 cdb[0] = SCSI_INQUIRY;
352 cdb[4] = sizeof inq_data;
353 if (zip_cmd(IS_PRIVILEGED(dev), fd, cdb, 6, SCSI_IO_READ,
354 &inq_data, sizeof inq_data, extra_data) != 0) {
360 fprintf(stderr, "device: %s\n\tvendor: %.8s\n\tproduct: %.16s\n"
361 "\trevision: %.4s\n", name, inq_data.vendor,
362 inq_data.product, inq_data.revision);
365 if (strncasecmp("IOMEGA ", inq_data.vendor,
366 sizeof inq_data.vendor) ||
367 (strncasecmp("ZIP 100 ",
368 inq_data.product, sizeof inq_data.product) &&
369 strncasecmp("ZIP 100 PLUS ",
370 inq_data.product, sizeof inq_data.product) &&
371 strncasecmp("ZIP 250 ",
372 inq_data.product, sizeof inq_data.product) &&
373 strncasecmp("ZIP 750 ",
374 inq_data.product, sizeof inq_data.product) &&
375 strncasecmp("JAZ 1GB ",
376 inq_data.product, sizeof inq_data.product) &&
377 strncasecmp("JAZ 2GB ",
378 inq_data.product, sizeof inq_data.product))) {
381 fprintf(stderr,"Skipping drive with vendor='");
382 fwrite(inq_data.vendor,1, sizeof(inq_data.vendor),
384 fprintf(stderr,"' product='");
385 fwrite(inq_data.product,1, sizeof(inq_data.product),
387 fprintf(stderr,"'\n");
392 break; /* found Zip/Jaz drive */
395 if (dev->drive == 0) {
396 fprintf(stderr, "%s: drive '%c:' is not a Zip or Jaz drive\n",
401 if (request & (ZIP_MODE_CHANGE | ZIP_STATUS))
402 oldMode = get_zip_status(IS_PRIVILEGED(dev), fd, extra_data);
404 if (request & ZIP_MODE_CHANGE) {
405 /* request temp unlock, and disk is already unlocked */
406 if(newMode == ZIP_UNLOCK_TIL_EJECT &&
407 (oldMode & ZIP_UNLOCK_TIL_EJECT))
408 request &= ~ZIP_MODE_CHANGE;
410 /* no password change requested, and disk is already
411 * in the requested state */
412 if(!(newMode & 0x01) && newMode == oldMode)
413 request &= ~ZIP_MODE_CHANGE;
416 if (request & ZIP_MODE_CHANGE) {
418 enum mode_t unlockMode, unlockMask;
422 if(newMode == ZIP_UNLOCK_TIL_EJECT) {
423 unlockMode = newMode | oldMode;
426 unlockMode = newMode & ~0x5;
430 if ((oldMode & unlockMask) == 1) { /* unlock first */
432 passwd = "APlaceForYourStuff";
433 if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */
434 iomega_command(IS_PRIVILEGED(dev), fd, unlockMode,
438 if ((get_zip_status(IS_PRIVILEGED(dev), fd, extra_data) &
442 passwd = getpass("Password: ");
443 if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */
444 if((ret=iomega_command(IS_PRIVILEGED(dev), fd,
447 if (ret == -1) perror("passwd: ");
448 else fprintf(stderr, "wrong password\n");
451 if((get_zip_status(IS_PRIVILEGED(dev),
454 fprintf(stderr, "wrong password\n");
460 char first_try[_PASSWORD_LEN];
462 passwd = getpass("Enter new password:");
463 strncpy(first_try, passwd,_PASSWORD_LEN);
464 passwd = getpass("Re-type new password:");
465 if(strncmp(first_try, passwd, _PASSWORD_LEN)) {
467 "You mispelled it. Password not set.\n");
475 if(newMode == ZIP_UNLOCK_TIL_EJECT)
478 if((ret=iomega_command(IS_PRIVILEGED(dev), fd,
479 newMode, passwd, extra_data))){
480 if (ret == -1) perror("set passwd: ");
481 else fprintf(stderr, "password not changed\n");
485 ioctl(fd, BLKRRPART); /* revalidate the disk, so that the
486 kernel notices that its writable
487 status has changed */
491 if (request & ZIP_STATUS) {
492 const char *unlocked;
495 unlocked = " and unlocked until eject";
498 switch (oldMode & ~8) {
500 printf("Drive '%c:' is not write-protected\n",
504 printf("Drive '%c:' is write-protected%s\n",
508 printf("Drive '%c:' is password write-protected%s\n",
512 printf("Drive '%c:' is password protected%s\n",
516 printf("Unknown protection mode %d of drive '%c:'\n",
522 if (request & ZIP_EJECT) {
523 if(request & ZIP_FORCE)
524 if(door_command(IS_PRIVILEGED(dev), fd,
525 SCSI_ALLOW_MEDIUM_REMOVAL, 0,
527 perror("door unlock: ");
531 if(door_command(IS_PRIVILEGED(dev), fd,
534 perror("stop motor: ");
538 if(door_command(IS_PRIVILEGED(dev), fd,
539 SCSI_START_STOP, 2, extra_data) < 0) {
543 if(door_command(IS_PRIVILEGED(dev), fd,
544 SCSI_START_STOP, 2, extra_data) < 0) {
545 perror("second eject: ");