📄 growisofs.c
字号:
if (!S_ISCHR(sb.st_mode)) { if (S_ISBLK(sb.st_mode) && !strncmp (device,"/dev/dsk",7)) { fprintf (stderr,":-) you most likely want to use " "/dev/r%s instead!\n",device+5); if (isatty(0) && !dry_run) poll(NULL,0,5000); } open_rw: setuid(uid); /* drop all privileges */ close (in_fd); /* reopen as mortal */ if ((in_fd = open64 (device,O_RDONLY)) < 0) fprintf (stderr,":-( unable to reopen(\"%s\",O_RDONLY): ",device), perror (NULL), exit (FATAL_START(errno)); if ((out_fd = open64 (device,O_RDWR)) < 0) fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",device), perror (NULL), exit (FATAL_START(errno)); opened_rw: poor_man = 0; close (ioctl_fd); ioctl_handle = INVALID_HANDLE; setuid (uid); /* drop all privileges */ return device; } /* * Still as euid=root! But note that get_mmc_profile makes sure it's * an MMC device, as it terminates the program if the unit doesn't * reply to GET CONFIGURATON. In combination with following switch * this means that if installed set-root-uid, growisofs grants * access to DVD burner(s), but not to any other device. */ tray_might_be_open: if ((in_fd<0) ? attr_get (device,"_devname",hw_path,&hw_len,0) : attr_getf (in_fd,"_devname",hw_path,&hw_len,0) ) fprintf (stderr,":-( unable to obtain hw_path for \"%s\": ",device), perror (NULL), exit (FATAL_START(errno)); if (hw_len>=sizeof(hw_path)) hw_len=sizeof(hw_path)-1; /* paranoia */ hw_path[hw_len]='\0'; if ((s=strstr(hw_path,"/scsi_ctlr/"))) sscanf (s,"/scsi_ctlr/%d/target/%d/lun/%d/",&bus,&tgt,&lun); /* Make sure user is using /dev/rdsk/dksXdYlZvol... */ if ((s=strstr(hw_path,"/disk/volume/char"))==NULL) { if (lun) fprintf (stderr,":-( stick to /dev/rdsk/dks%dd%dl%dvol!\n", bus,tgt,lun); else fprintf (stderr,":-( stick to /dev/rdsk/dks%dd%dvol!\n", bus,tgt); exit(FATAL_START(EINVAL)); } memcpy (s,"/scsi",6); ioctl_handle = (void *)(long)open64 (hw_path,O_RDWR); if (ioctl_handle == INVALID_HANDLE) fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",hw_path), perror (NULL), exit (FATAL_START(errno)); if (fstat64 (ioctl_fd,&sc) < 0) fprintf (stderr,":-( unable to stat(\"%s\"): ",hw_path), perror (NULL), exit (FATAL_START(errno)); memcpy (s,"/disk/volume/char",6); mmc_profile = get_mmc_profile (ioctl_handle); switch (mmc_profile&0xFFFF) { case 0x11: /* DVD-R */ case 0x13: /* DVD-RW Restricted Overwrite */ case 0x14: /* DVD-RW Sequential */ case 0x1A: /* DVD+RW */ case 0x1B: /* DVD+R */ case 0x2B: /* DVD+R Double Layer */ open_poor_man: poor_man = 1; out_fd = dup (ioctl_fd); if (in_fd<0 && (in_fd=open64 (hw_path,O_RDONLY))<0) /* hope for the best? */ ; setuid (uid); /* drop all privileges */ mediad_get_exclusiveuse (hw_path,"growisofs"); if (mediad_last_error ()==RMED_NOERROR) putenv ("MEDIAD_GOT_EXCLUSIVEUSE="); /* kludge... */ sprintf (rscsi,"/dev/scsi/sc%dd%dl%d",bus,tgt,lun); return ioctl_device=rscsi; /* might be bogus... */ case 0x12: /* DVD-RAM */ /* Some of latest tentative IRIX releases seem to * implement DVD-RAM writing at dksc level, but I'm * not sure which one. So I just fall down to poor-man, * at least for now... */ goto open_poor_man; break; default: fprintf (stderr,":-( %s: media is not recognized as " "recordable DVD: %X\n",device,mmc_profile); exit (FATAL_START(EMEDIUMTYPE)); } /* not actually reached */ setuid(uid); goto open_rw;}#else#error "Unsupported OS"#endifint setup_C_parm (char *C_parm,struct iso_primary_descriptor *descr){ int next_session=-1,profile=mmc_profile&0xFFFF; if (!poor_man || profile==0x1A || profile==0x13 || profile==0x12) { next_session = from_733(descr->volume_space_size); /* pad to closest 32K boundary */ next_session += 15; next_session /= 16; next_session *= 16; sprintf (C_parm,"16,%u",next_session); } else if (profile==0x2B || profile==0x1B || profile==0x11 || profile==0x14) next_session=plusminus_r_C_parm (ioctl_handle,C_parm); return next_session;}int builtin_dd (int infd,int outfd,off64_t outoff){ char *s; int n,fd; unsigned int off; struct stat64 sb; off64_t capacity=0,tracksize=0,startoff=outoff; pid_t pid=(pid_t)-1,ppid=getpid(); volatile struct { time_t zero; off64_t current,final; } *progress; if ((fd=mkstemp (s=strdup("/tmp/dvd+rw.XXXXXX"))) < 0) fprintf (stderr,":-( unable to mkstemp(\"%s\")",s), exit(FATAL_START(errno)); ftruncate(fd,(off_t)sizeof(*progress)); unlink(s), free(s); progress = (void *)mmap (NULL,sizeof(*progress),PROT_READ|PROT_WRITE, MAP_SHARED,fd,(off_t)0); close (fd); if (progress == MAP_FAILED) fprintf (stderr,":-( unable to anonymously mmap %lu?\n", sizeof(*progress)), perror (NULL), exit(FATAL_START(errno)); if (fstat64 (infd,&sb)) perror (":-( unable to fstat64"), exit(FATAL_START(errno)); if (ioctl_handle!=INVALID_HANDLE) capacity = get_capacity (ioctl_handle); progress->zero=0; progress->current=outoff; if (dao_size || S_ISREG(sb.st_mode)) { tracksize = dao_size ? (dao_size*CD_BLOCK) : sb.st_size; progress->final=outoff+tracksize; if (capacity && progress->final > capacity) { fprintf (stderr,":-( %s: %lld blocks are free, " "%lld to be written!\n", ioctl_device, (capacity-outoff)/2048,tracksize/2048); if (overburn) fprintf (stderr,":-! ignoring...\n"); else close(infd), close(outfd), exit (FATAL_START(ENOSPC)); } } else progress->final=0; if (!dry_run && quiet<=0 && (pid=fork()) == 0) { double ratio,velocity,slept; int delta,nfirst=0; off64_t lastcurrent=outoff,current; struct timeval tv; close (infd); close (outfd); while (kill (ppid,0)==0) { gettimeofday (&tv,NULL); slept = tv.tv_usec/1e6+tv.tv_sec; lastcurrent = progress->current; poll (NULL,0,3333); gettimeofday (&tv,NULL); slept -= tv.tv_usec/1e6+tv.tv_sec; if (progress->zero==0 || !nfirst++) continue; if ((current = progress->current) > outoff) { delta = time (NULL) - progress->zero; ratio = (double)(progress->final-outoff) / (double)(current-outoff); delta *= ratio - 1.0; velocity=(current-lastcurrent)/(-slept*1024*1385); fprintf (stdout,"%10lld/%lld (%4.1f%%) @%.1fx, " "remaining %d:%02d\n", current,progress->final,100.0/ratio, velocity,delta/60,delta%60); lastcurrent=current; } else fprintf (stdout,"%10lld/%lld (%4.1f%%) @0x, remaining ??:??\n", current,progress->final,0.0); fflush (stdout); } exit(0); /* not [normally] reached */ } /* suck in first 64K and examine ISO9660 Primary Descriptor if present */ off = 0; while ((n=read (infd,the_buffer+off,2*DVD_BLOCK-off)) > 0) { off += n; if (off == 2*DVD_BLOCK) { if (!memcmp(the_buffer+DVD_BLOCK,"\1CD001",6)) { struct iso_primary_descriptor *descr; descr=(struct iso_primary_descriptor *)(the_buffer+DVD_BLOCK); if (!zero_image) { if (tracksize==0) { tracksize=from_733(descr->volume_space_size)*CD_BLOCK; if (capacity && (outoff+tracksize) > capacity) { fprintf (stderr,":-( %s: %lld blocks are free, " "%lld to be written\n", ioctl_device, (capacity-outoff)/2048, tracksize/2048); if (overburn) fprintf (stderr,":-! ignoring...\n"); else { n = -1; errno = FATAL_START(ENOSPC); goto out; } } } /* else already checked for overburn condition */ /* layer_break is meaningful only for -Z recording */ if (layer_break>0 && !outoff) { if (tracksize > layer_break*CD_BLOCK*2) { fprintf (stderr,":-( insane Layer Break position " "with respect to dataset size\n"); n = -1; errno = FATAL_START(EINVAL); goto out; } if (!progress->final) progress->final = tracksize; tracksize = layer_break*CD_BLOCK*2; } } else if (capacity > outoff) { int i=0; unsigned int ts = (tracksize=capacity-outoff)/2048; while (i<16 && descr->type[0] != (unsigned char)255) to_733 (descr->volume_space_size,ts), descr++, i++; } else { fprintf (stderr,":-( capacity is undefined or insane?\n"); n = -1; errno = FATAL_START(EINVAL);/* ... or whatever */ goto out; } } else if (outoff && zero_image) { fprintf (stderr,":-( no volume descriptors found " "in previous session?\n"); n = -1; errno = FATAL_START(ENOTDIR); /* ... or whatever */ goto out; } if (dry_run) close(infd), close(outfd), exit(0); if (poor_man) /* * See commentary section in growisofs_mmc.cpp for * further details on poor_mans_setup */ pwrite64_method = poor_mans_setup (ioctl_handle, outoff+tracksize); if (!progress->final) { if (tracksize) progress->final = outoff+tracksize; else progress->final = capacity; } if (capacity && progress->final>capacity) progress->final = capacity; progress->zero=time(NULL); /* Write two 32KB chunks, not one 64KB... */ if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff)) != DVD_BLOCK) { if (n>0) errno = FATAL_START(EIO); else if (n==0) errno = FATAL_START(ENOSPC); n = -1; goto out; } outoff += DVD_BLOCK; progress->current=outoff; if ((n=(*pwrite64_method) (outfd,the_buffer+DVD_BLOCK,DVD_BLOCK,outoff)) != DVD_BLOCK) { if (n>0) errno = EIO; else if (n==0) errno = ENOSPC; n = -1; goto out; } outoff += DVD_BLOCK; progress->current=outoff; break; } } if (n<=0) goto out; /* yeah, really kludgy, shuffling file descriptor like that... */ if (zero_image) close(infd), infd=open64 ("/dev/zero",O_RDONLY); off = 0; /* * From now on only the first 32K of the_buffer are used! */ while ((n=read (infd,the_buffer+off,DVD_BLOCK-off)) > 0) { off += n; if (off == DVD_BLOCK) { off = 0; if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff)) != DVD_BLOCK) { if (n>0) errno = EIO; else if (n==0) errno = ENOSPC; n = -1; break; } outoff += DVD_BLOCK; progress->current=outoff; } } if (off) /* pad to the closest 32K is needed */ { memset (the_buffer+off,0,DVD_BLOCK-off); if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff)) != DVD_BLOCK) { if (n>0) errno = EIO; else if (n==0) errno = ENOSPC; n = -1; } outoff += DVD_BLOCK; } printf ("builtin_dd: %lld*2KB out @ average %.1fx1385KBps\n", (outoff-startoff)/2048, ((outoff-startoff)/(1024.0*1385.0))/(time(NULL)-progress->zero));out: { int saved_errno=errno; if (dry_run) close(infd), close(outfd), exit(errno); if (pid!=(pid_t)-1) kill (pid,SIGTERM), waitpid (pid,NULL,0); errno = outoff ? saved_errno : (n--?saved_errno:FATAL_START(EIO)); } return n;}void pipe_mkisofs_up (char *mkisofs_argv[],int infd,int outfd,off64_t outoff){ pid_t mkisofs_pid; int fildes[2],ret,n; if (pipe (fildes) < 0) perror (":-( unable to create pipe"), exit(FATAL_START(errno)); if ((mkisofs_pid=fork ()) == (pid_t)-1) perror (":-( unable to fork mkisofs"), exit(FATAL_START(errno)); else if (mkisofs_pid == 0) { dup2 (fildes[1],1); close (fildes[0]); close (fildes[1]); close (outfd); /* redundant:-) */#ifdef PASS_STDIN_TO_MKISOFS dup2(infd,0); close(infd); infd=0;#endif if ((n=fcntl (infd,F_GETFD))<0) n=0; fcntl (infd,F_SETFD,n&~FD_CLOEXEC); /* * If platform-specific setup_fds did not drop privileges, * do it now. I ignore return value because if it fails, * then privileges were dropped already. */ setuid(getuid()); execvp (mkisofs_argv[0],mkisofs_argv); fprintf (stderr,":-( unable to execute %s: ",mkisofs_argv[0]), perror (NULL), exit (FATAL_START(errno)); } close (fildes[1]); n=builtin_dd(fildes[0],outfd,outoff); if (n==0) /* mkisofs must have finished, consume the exit code */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -