blob: 1148fa39d92d453aecfc5b07993bd73ca819fbcf [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* 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.
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * mzip.c
20 * Iomega Zip/Jaz drive tool
21 * change protection mode and eject disk
22 */
23
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: */
27
28/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */
29/* http://www.torque.net/ziptool.html */
30
31
32/* Unprotect-till-eject modes and mount tests added
33 * by Ilya Ovchinnikov <ilya@socio.msu.su>
34 */
35
36#include "sysincludes.h"
37#include "mtools.h"
38#include "scsi.h"
39
40#ifndef _PASSWORD_LEN
41#define _PASSWORD_LEN 33
42#endif
43
44#ifdef OS_linux
45
46#if __GLIBC__ >=2
47#include <sys/mount.h>
48#else
49#define _LINUX_KDEV_T_H 1 /* don't redefine MAJOR/MINOR */
50#include <linux/fs.h>
51#endif
52
53#include "devices.h"
54
55#endif
56
57
Yi Kong39bbd962022-01-09 19:41:38 +080058static int zip_cmd(int priv, int fd, unsigned char cdb[6], uint8_t clen,
59 scsi_io_mode_t mode, void *data, uint32_t len,
Alistair Delvabeaee832021-02-24 11:27:23 -080060 void *extra_data)
61{
62 int r;
63
64 if(priv)
65 reclaim_privs();
66 r = scsi_cmd(fd, cdb, clen, mode, data, len, extra_data);
67 if(priv)
68 drop_privs();
69 return r;
70}
71
Yi Kong39bbd962022-01-09 19:41:38 +080072static int test_mounted ( char *dev UNUSEDP)
Alistair Delvabeaee832021-02-24 11:27:23 -080073{
74#ifdef HAVE_MNTENT_H
75 struct mntent *mnt;
76 struct MT_STAT st_dev, st_mnt;
77 FILE *mtab;
78/*
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).
81 */
Yi Kong39bbd962022-01-09 19:41:38 +080082
Alistair Delvabeaee832021-02-24 11:27:23 -080083 if (MT_STAT (dev, &st_dev)) {
84 fprintf (stderr, "%s: stat(%s) failed: %s.\n",
85 progname, dev, strerror (errno));
86 exit(1);
87 }
Yi Kong39bbd962022-01-09 19:41:38 +080088
89 if (!S_ISBLK (st_dev.st_mode)) /* not a block device, cannot
Alistair Delvabeaee832021-02-24 11:27:23 -080090 * be mounted */
91 return 0;
92
93#ifndef _PATH_MOUNTED
94# define _PATH_MOUNTED "/etc/mtab"
95#endif
96
97 if ((mtab = setmntent (_PATH_MOUNTED, "r")) == NULL) {
98 fprintf (stderr, "%s: can't open %s.\n",
99 progname, _PATH_MOUNTED);
100 exit(1);
101 }
Yi Kong39bbd962022-01-09 19:41:38 +0800102
Alistair Delvabeaee832021-02-24 11:27:23 -0800103 while ( ( mnt = getmntent (mtab) ) ) {
104 if (!mnt->mnt_fsname
105
106#ifdef MNTTYPE_SWAP
107 || !strcmp (mnt->mnt_type, MNTTYPE_SWAP)
108#endif
109#ifdef MNTTYPE_NFS
110 || !strcmp (mnt->mnt_type, MNTTYPE_NFS)
111#endif
112 || !strcmp (mnt->mnt_type, "proc")
113 || !strcmp (mnt->mnt_type, "smbfs")
114#ifdef MNTTYPE_IGNORE
115 || !strcmp (mnt->mnt_type, MNTTYPE_IGNORE)
116#endif
117 )
118 continue;
119
120 if (MT_STAT (mnt->mnt_fsname, &st_mnt)) {
121 continue;
122 }
Yi Kong39bbd962022-01-09 19:41:38 +0800123
Alistair Delvabeaee832021-02-24 11:27:23 -0800124 if (S_ISBLK (st_mnt.st_mode)) {
125#ifdef OS_linux
126 /* on Linux, warn also if the device is on the same
127 * partition */
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){
Yi Kong39bbd962022-01-09 19:41:38 +0800131 fprintf (stderr,
132 "Device %s%d is mounted on %s.\n",
133 dev,
134 MINOR(st_mnt.st_rdev) -
Alistair Delvabeaee832021-02-24 11:27:23 -0800135 MINOR(st_dev.st_rdev),
136 mnt->mnt_dir);
137#else
138 if(st_mnt.st_rdev != st_dev.st_rdev) {
139#endif
140 endmntent (mtab);
141 return 1;
142 }
143#if 0
144 } /* keep Emacs indentation happy */
145#endif
146 }
147 }
148 endmntent (mtab);
149#endif
150 return 0;
151}
152
153
154static void usage(int ret) NORETURN;
155static void usage(int ret)
156{
Yi Kong39bbd962022-01-09 19:41:38 +0800157 fprintf(stderr,
158 "Mtools version %s, dated %s\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800159 mversion, mdate);
Yi Kong39bbd962022-01-09 19:41:38 +0800160 fprintf(stderr,
Alistair Delvabeaee832021-02-24 11:27:23 -0800161 "Usage: %s [-V] [-q] [-e] [-u] [-r|-w|-p|-x] [drive:]\n"
162 "\t-q print status\n"
163 "\t-e eject disk\n"
164 "\t-f eject disk even when mounted\n"
165 "\t-r write protected (read-only)\n"
166 "\t-w not write-protected (read-write)\n"
167 "\t-p password write protected\n"
168 "\t-x password protected\n"
Yi Kong39bbd962022-01-09 19:41:38 +0800169 "\t-u unprotect till disk ejecting\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800170 progname);
171 exit(ret);
172}
173
Yi Kong39bbd962022-01-09 19:41:38 +0800174#define ZIP_RW (0)
175#define ZIP_RO (2)
176#define ZIP_RO_PW (3)
177#define ZIP_PW (5)
178#define ZIP_UNLOCK_TIL_EJECT (8)
Alistair Delvabeaee832021-02-24 11:27:23 -0800179
Yi Kong39bbd962022-01-09 19:41:38 +0800180static uint8_t get_zip_status(int priv, int fd, void *extra_data)
Alistair Delvabeaee832021-02-24 11:27:23 -0800181{
182 unsigned char status[128];
183 unsigned char cdb[6] = { 0x06, 0, 0x02, 0, sizeof status, 0 };
Yi Kong39bbd962022-01-09 19:41:38 +0800184
185 if (zip_cmd(priv, fd, cdb, 6, SCSI_IO_READ,
Alistair Delvabeaee832021-02-24 11:27:23 -0800186 status, sizeof status, extra_data) == -1) {
187 perror("status: ");
188 exit(1);
189 }
190 return status[21] & 0xf;
191}
192
193
Yi Kong39bbd962022-01-09 19:41:38 +0800194static int short_command(int priv, int fd, uint8_t cmd1, uint8_t cmd2,
195 uint8_t cmd3, const char *data, void *extra_data)
Alistair Delvabeaee832021-02-24 11:27:23 -0800196{
Yi Kong39bbd962022-01-09 19:41:38 +0800197 uint8_t cdb[6] = { 0, 0, 0, 0, 0, 0 };
Alistair Delvabeaee832021-02-24 11:27:23 -0800198
199 cdb[0] = cmd1;
200 cdb[1] = cmd2;
201 cdb[4] = cmd3;
202
Yi Kong39bbd962022-01-09 19:41:38 +0800203 return zip_cmd(priv, fd, cdb, 6, SCSI_IO_WRITE,
204 (char *) data, data ? (uint32_t) strlen(data) : 0,
205 extra_data);
Alistair Delvabeaee832021-02-24 11:27:23 -0800206}
207
208
Yi Kong39bbd962022-01-09 19:41:38 +0800209static int iomega_command(int priv, int fd, uint8_t mode, const char *data,
Alistair Delvabeaee832021-02-24 11:27:23 -0800210 void *extra_data)
211{
Yi Kong39bbd962022-01-09 19:41:38 +0800212 return short_command(priv, fd,
213 SCSI_IOMEGA, mode,
214 /* Do we really need strlen(data) in here? */
215 data ? (uint8_t) strlen(data) : 0,
Alistair Delvabeaee832021-02-24 11:27:23 -0800216 data, extra_data);
217}
218
Yi Kong39bbd962022-01-09 19:41:38 +0800219static int door_command(int priv, int fd, uint8_t cmd1, uint8_t cmd2,
Alistair Delvabeaee832021-02-24 11:27:23 -0800220 void *extra_data)
221{
222 return short_command(priv, fd, cmd1, 0, cmd2, 0, extra_data);
223}
224
225void mzip(int argc, char **argv, int type UNUSEDP) NORETURN;
226void mzip(int argc, char **argv, int type UNUSEDP)
227{
228 void *extra_data = NULL;
229 int c;
230 char drive;
231 device_t *dev;
232 int fd = -1;
233 char name[EXPAND_BUF];
Yi Kong39bbd962022-01-09 19:41:38 +0800234#define ZIP_NIX (0)
235#define ZIP_STATUS (1 << 0)
236#define ZIP_EJECT (1 << 1)
237#define ZIP_MODE_CHANGE (1 << 2)
238#define ZIP_FORCE (1 << 3)
239 int request = ZIP_NIX;
Alistair Delvabeaee832021-02-24 11:27:23 -0800240
Yi Kong39bbd962022-01-09 19:41:38 +0800241 uint8_t newMode = ZIP_RW;
242 uint8_t oldMode = ZIP_RW;
Alistair Delvabeaee832021-02-24 11:27:23 -0800243
244#define setMode(x) \
245 if(request & ZIP_MODE_CHANGE) usage(1); \
246 request |= ZIP_MODE_CHANGE; \
247 newMode = x; \
Yi Kong39bbd962022-01-09 19:41:38 +0800248 break
249
Alistair Delvabeaee832021-02-24 11:27:23 -0800250 /* get command line options */
251 if(helpFlag(argc, argv))
252 usage(0);
253 while ((c = getopt(argc, argv, "i:efpqrwxuh")) != EOF) {
254 switch (c) {
255 case 'i':
256 set_cmd_line_image(optarg);
257 break;
258 case 'f':
259 if (get_real_uid()) {
Yi Kong39bbd962022-01-09 19:41:38 +0800260 fprintf(stderr,
Alistair Delvabeaee832021-02-24 11:27:23 -0800261 "Only root can use force. Sorry.\n");
262 exit(1);
263 }
264 request |= ZIP_FORCE;
265 break;
266 case 'e': /* eject */
267 request |= ZIP_EJECT;
268 break;
269 case 'q': /* status query */
270 request |= ZIP_STATUS;
271 break;
272
273 case 'p': /* password read-only */
274 setMode(ZIP_RO_PW);
275 case 'r': /* read-only */
276 setMode(ZIP_RO);
277 case 'w': /* read-write */
278 setMode(ZIP_RW);
279 case 'x': /* password protected */
280 setMode(ZIP_PW);
281 case 'u': /* password protected */
Yi Kong39bbd962022-01-09 19:41:38 +0800282 setMode(ZIP_UNLOCK_TIL_EJECT);
Alistair Delvabeaee832021-02-24 11:27:23 -0800283 case 'h':
284 usage(0);
285 default: /* unrecognized */
286 usage(1);
Yi Kong39bbd962022-01-09 19:41:38 +0800287
Alistair Delvabeaee832021-02-24 11:27:23 -0800288 }
289 }
Yi Kong39bbd962022-01-09 19:41:38 +0800290
Alistair Delvabeaee832021-02-24 11:27:23 -0800291 if (request == ZIP_NIX) request = ZIP_STATUS; /* default action */
292
Yi Kong39bbd962022-01-09 19:41:38 +0800293 if (argc - optind > 1 ||
Alistair Delvabeaee832021-02-24 11:27:23 -0800294 (argc - optind == 1 &&
295 (!argv[optind][0] || argv[optind][1] != ':')))
296 usage(1);
Yi Kong39bbd962022-01-09 19:41:38 +0800297
Alistair Delvabeaee832021-02-24 11:27:23 -0800298 drive = ch_toupper(argc - optind == 1 ? argv[argc - 1][0] : ':');
Yi Kong39bbd962022-01-09 19:41:38 +0800299
Alistair Delvabeaee832021-02-24 11:27:23 -0800300 for (dev = devices; dev->name; dev++) {
301 unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 };
302 struct {
303 char type,
304 type_modifier,
305 scsi_version,
306 data_format,
307 length,
308 reserved1[2],
309 capabilities,
310 vendor[8],
311 product[16],
312 revision[4],
313 vendor_specific[20],
314 reserved2[40];
315 } inq_data;
316
Yi Kong39bbd962022-01-09 19:41:38 +0800317 if (dev->drive != drive)
Alistair Delvabeaee832021-02-24 11:27:23 -0800318 continue;
319 expand(dev->name, name);
320 if ((request & (ZIP_MODE_CHANGE | ZIP_EJECT)) &&
321 !(request & ZIP_FORCE) &&
322 test_mounted(name)) {
Yi Kong39bbd962022-01-09 19:41:38 +0800323 fprintf(stderr,
Alistair Delvabeaee832021-02-24 11:27:23 -0800324 "Can\'t change status of/eject mounted device\n");
325 exit(1);
326 }
327 precmd(dev);
328
329 if(IS_PRIVILEGED(dev))
330 reclaim_privs();
331 fd = scsi_open(name, O_RDONLY
332#ifdef O_NDELAY
333 | O_NDELAY
334#endif
335 , 0644,
336 &extra_data);
337 if(IS_PRIVILEGED(dev))
338 drop_privs();
339
340 /* need readonly, else we can't
341 * open the drive on Solaris if
Yi Kong39bbd962022-01-09 19:41:38 +0800342 * write-protected */
343 if (fd == -1)
Alistair Delvabeaee832021-02-24 11:27:23 -0800344 continue;
345 closeExec(fd);
346
347 if (!(request & (ZIP_MODE_CHANGE | ZIP_STATUS)))
348 /* if no mode change or ZIP specific status is
349 * involved, the command (eject) is applicable
350 * on all drives */
351 break;
352
353 cdb[0] = SCSI_INQUIRY;
354 cdb[4] = sizeof inq_data;
Yi Kong39bbd962022-01-09 19:41:38 +0800355 if (zip_cmd(IS_PRIVILEGED(dev), fd, cdb, 6, SCSI_IO_READ,
Alistair Delvabeaee832021-02-24 11:27:23 -0800356 &inq_data, sizeof inq_data, extra_data) != 0) {
357 close(fd);
358 continue;
359 }
Yi Kong39bbd962022-01-09 19:41:38 +0800360
Alistair Delvabeaee832021-02-24 11:27:23 -0800361#ifdef DEBUG
362 fprintf(stderr, "device: %s\n\tvendor: %.8s\n\tproduct: %.16s\n"
363 "\trevision: %.4s\n", name, inq_data.vendor,
364 inq_data.product, inq_data.revision);
365#endif /* DEBUG */
366
367 if (strncasecmp("IOMEGA ", inq_data.vendor,
368 sizeof inq_data.vendor) ||
369 (strncasecmp("ZIP 100 ",
370 inq_data.product, sizeof inq_data.product) &&
371 strncasecmp("ZIP 100 PLUS ",
372 inq_data.product, sizeof inq_data.product) &&
373 strncasecmp("ZIP 250 ",
374 inq_data.product, sizeof inq_data.product) &&
375 strncasecmp("ZIP 750 ",
376 inq_data.product, sizeof inq_data.product) &&
377 strncasecmp("JAZ 1GB ",
378 inq_data.product, sizeof inq_data.product) &&
379 strncasecmp("JAZ 2GB ",
380 inq_data.product, sizeof inq_data.product))) {
381
382 /* debugging */
383 fprintf(stderr,"Skipping drive with vendor='");
Yi Kong39bbd962022-01-09 19:41:38 +0800384 fwrite(inq_data.vendor,1, sizeof(inq_data.vendor),
Alistair Delvabeaee832021-02-24 11:27:23 -0800385 stderr);
386 fprintf(stderr,"' product='");
Yi Kong39bbd962022-01-09 19:41:38 +0800387 fwrite(inq_data.product,1, sizeof(inq_data.product),
Alistair Delvabeaee832021-02-24 11:27:23 -0800388 stderr);
389 fprintf(stderr,"'\n");
390 /* end debugging */
391 close(fd);
392 continue;
393 }
394 break; /* found Zip/Jaz drive */
395 }
396
397 if (dev->drive == 0) {
398 fprintf(stderr, "%s: drive '%c:' is not a Zip or Jaz drive\n",
399 argv[0], drive);
400 exit(1);
401 }
402
403 if (request & (ZIP_MODE_CHANGE | ZIP_STATUS))
404 oldMode = get_zip_status(IS_PRIVILEGED(dev), fd, extra_data);
405
406 if (request & ZIP_MODE_CHANGE) {
407 /* request temp unlock, and disk is already unlocked */
408 if(newMode == ZIP_UNLOCK_TIL_EJECT &&
409 (oldMode & ZIP_UNLOCK_TIL_EJECT))
410 request &= ~ZIP_MODE_CHANGE;
411
412 /* no password change requested, and disk is already
413 * in the requested state */
414 if(!(newMode & 0x01) && newMode == oldMode)
415 request &= ~ZIP_MODE_CHANGE;
416 }
417
418 if (request & ZIP_MODE_CHANGE) {
419 int ret;
Yi Kong39bbd962022-01-09 19:41:38 +0800420 uint8_t unlockMode, unlockMask;
Alistair Delvabeaee832021-02-24 11:27:23 -0800421 const char *passwd;
422 char dummy[1];
423
424 if(newMode == ZIP_UNLOCK_TIL_EJECT) {
425 unlockMode = newMode | oldMode;
426 unlockMask = 9;
427 } else {
428 unlockMode = newMode & ~0x5;
429 unlockMask = 1;
430 }
431
432 if ((oldMode & unlockMask) == 1) { /* unlock first */
433 char *s;
434 passwd = "APlaceForYourStuff";
435 if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */
Yi Kong39bbd962022-01-09 19:41:38 +0800436 iomega_command(IS_PRIVILEGED(dev), fd, unlockMode,
Alistair Delvabeaee832021-02-24 11:27:23 -0800437 passwd, extra_data);
438 }
Yi Kong39bbd962022-01-09 19:41:38 +0800439
440 if ((get_zip_status(IS_PRIVILEGED(dev), fd, extra_data) &
Alistair Delvabeaee832021-02-24 11:27:23 -0800441 unlockMask) == 1) {
442 /* unlock first */
443 char *s;
444 passwd = getpass("Password: ");
445 if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */
Yi Kong39bbd962022-01-09 19:41:38 +0800446 if((ret=iomega_command(IS_PRIVILEGED(dev), fd,
447 unlockMode, passwd,
Alistair Delvabeaee832021-02-24 11:27:23 -0800448 extra_data))){
449 if (ret == -1) perror("passwd: ");
450 else fprintf(stderr, "wrong password\n");
451 exit(1);
452 }
Yi Kong39bbd962022-01-09 19:41:38 +0800453 if((get_zip_status(IS_PRIVILEGED(dev),
454 fd, extra_data) &
Alistair Delvabeaee832021-02-24 11:27:23 -0800455 unlockMask) == 1) {
456 fprintf(stderr, "wrong password\n");
457 exit(1);
458 }
459 }
Yi Kong39bbd962022-01-09 19:41:38 +0800460
Alistair Delvabeaee832021-02-24 11:27:23 -0800461 if (newMode & 0x1) {
462 char first_try[_PASSWORD_LEN+1];
Yi Kong39bbd962022-01-09 19:41:38 +0800463
Alistair Delvabeaee832021-02-24 11:27:23 -0800464 passwd = getpass("Enter new password:");
465 strncpy(first_try, passwd,_PASSWORD_LEN);
466 passwd = getpass("Re-type new password:");
467 if(strncmp(first_try, passwd, _PASSWORD_LEN)) {
468 fprintf(stderr,
469 "You misspelled it. Password not set.\n");
470 exit(1);
471 }
472 } else {
473 passwd = dummy;
474 dummy[0] = '\0';
475 }
476
477 if(newMode == ZIP_UNLOCK_TIL_EJECT)
478 newMode |= oldMode;
479
Yi Kong39bbd962022-01-09 19:41:38 +0800480 if((ret=iomega_command(IS_PRIVILEGED(dev), fd,
Alistair Delvabeaee832021-02-24 11:27:23 -0800481 newMode, passwd, extra_data))){
482 if (ret == -1) perror("set passwd: ");
483 else fprintf(stderr, "password not changed\n");
484 exit(1);
485 }
486#ifdef OS_linux
487 ioctl(fd, BLKRRPART); /* revalidate the disk, so that the
488 kernel notices that its writable
489 status has changed */
490#endif
491 }
Yi Kong39bbd962022-01-09 19:41:38 +0800492
Alistair Delvabeaee832021-02-24 11:27:23 -0800493 if (request & ZIP_STATUS) {
494 const char *unlocked;
495
496 if(oldMode & 8)
497 unlocked = " and unlocked until eject";
498 else
Yi Kong39bbd962022-01-09 19:41:38 +0800499 unlocked = "";
Alistair Delvabeaee832021-02-24 11:27:23 -0800500 switch (oldMode & ~8) {
Yi Kong39bbd962022-01-09 19:41:38 +0800501 case ZIP_RW:
Alistair Delvabeaee832021-02-24 11:27:23 -0800502 printf("Drive '%c:' is not write-protected\n",
503 drive);
504 break;
505 case ZIP_RO:
506 printf("Drive '%c:' is write-protected%s\n",
507 drive, unlocked);
508 break;
Yi Kong39bbd962022-01-09 19:41:38 +0800509 case ZIP_RO_PW:
510 printf("Drive '%c:' is password write-protected%s\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800511 drive, unlocked);
512 break;
Yi Kong39bbd962022-01-09 19:41:38 +0800513 case ZIP_PW:
514 printf("Drive '%c:' is password protected%s\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800515 drive, unlocked);
516 break;
Yi Kong39bbd962022-01-09 19:41:38 +0800517 default:
Alistair Delvabeaee832021-02-24 11:27:23 -0800518 printf("Unknown protection mode %d of drive '%c:'\n",
519 oldMode, drive);
Yi Kong39bbd962022-01-09 19:41:38 +0800520 break;
521 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800522 }
Yi Kong39bbd962022-01-09 19:41:38 +0800523
Alistair Delvabeaee832021-02-24 11:27:23 -0800524 if (request & ZIP_EJECT) {
525 if(request & ZIP_FORCE)
Yi Kong39bbd962022-01-09 19:41:38 +0800526 if(door_command(IS_PRIVILEGED(dev), fd,
Alistair Delvabeaee832021-02-24 11:27:23 -0800527 SCSI_ALLOW_MEDIUM_REMOVAL, 0,
528 extra_data) < 0) {
529 perror("door unlock: ");
530 exit(1);
531 }
532
Yi Kong39bbd962022-01-09 19:41:38 +0800533 if(door_command(IS_PRIVILEGED(dev), fd,
Alistair Delvabeaee832021-02-24 11:27:23 -0800534 SCSI_START_STOP, 1,
535 extra_data) < 0) {
536 perror("stop motor: ");
537 exit(1);
538 }
539
Yi Kong39bbd962022-01-09 19:41:38 +0800540 if(door_command(IS_PRIVILEGED(dev), fd,
Alistair Delvabeaee832021-02-24 11:27:23 -0800541 SCSI_START_STOP, 2, extra_data) < 0) {
542 perror("eject: ");
543 exit(1);
544 }
Yi Kong39bbd962022-01-09 19:41:38 +0800545 if(door_command(IS_PRIVILEGED(dev), fd,
Alistair Delvabeaee832021-02-24 11:27:23 -0800546 SCSI_START_STOP, 2, extra_data) < 0) {
547 perror("second eject: ");
548 exit(1);
549 }
550 }
Yi Kong39bbd962022-01-09 19:41:38 +0800551
Alistair Delvabeaee832021-02-24 11:27:23 -0800552 close(fd);
553 exit(0);
554}