downer has asked for the wisdom of the Perl Monks concerning the following question:

sorry I can't include more of my program here. Here is part of the sub routine where there error occurs. I have been running the program for a while, but always only one file handle open for writing at a time.
print STDERR "saving block $writeCounter, \@ docID $docID "; system("date"); my $postingList = ''; my $posting = ''; my $output = ''; my $savename = "/indexes/1_indexBlock_$writeCounter"; print STDERR "saving $savename\n"; open my $save, ">.$savename" or die "can't open save $!\n"; flock($save, 2) or die "can't lock save $!\n"; print STDERR "$savename is open\n"; foreach my $x (sort (keys %inMemIndex)) { $postingList = $inMemIndex{$x}; $posting = "$x $inMemIndex{$x}\n"; $output .= $posting; } print $save $output or die "can't write to save $!\n"; $output = ''; %inMemIndex = (); flock($save, 8); close $save or die "can't close save $!\n"; system("./logMergeManager.pl $writeCounter &"); $writeCounter++; $totalWordSize = 0;
when $writeCounter gets to 1342, the program dies on writing with the error: "can't write to save Inappropriate ioctl for device" i'm sorry i can't really give a condensed version of the code since this is part of a very large program. i added the flocks just to ensure that nothing is trying to open the file at the same time, its possible that i'm not using these correctly, though i was having this error before i included these. can anyone see any obvious flaws?

EDIT: changed '||' to 'or' as per Fletch's suggestion. re-running my code now.

EDIT: changed file handles as per ikegami's suggestion. seems to be working properly now :)

Replies are listed 'Best First'.
Re: Inappropriate ioctl for device
by ikegami (Patriarch) on Oct 29, 2007 at 14:41 UTC

    A couple of notes.

    • In addition to checking the table in perlop, you can check precedence using the -p option of B::Deparse.

      >perl -MO=Deparse,-p -e"open FILE, $file || die" open(FILE, ($file || die)); -e syntax OK >perl -MO=Deparse,-p -e"open FILE, $file or die" (open(FILE, $file) or die); -e syntax OK

      General rule: Only use || when you're saving the value of the OR.

    • You mentioned in the ChatterBox that you thought your file handles were being closed automatically when the subroutine exits. In your case, they weren't before adding explicit calls close.

      File handles are automatically closed when they go out of scope and there are no more references to them. Since you are using a global variable (*SAVE) as your file handle, and since you don't localize it, it never goes out of scope.

      Fix:

      open(local *FH, '<', $file) or die("Unable to open file \"$file\": $!\n");
      open(my $fh, '<', $file) or die("Unable to open file \"$file\": $!\n");
      if i use either of those methods, how do i change the lines were i read/write? <*FH> and <$fh>?
      thanks monks, every day i'm becoming a better programmer
        local *FHmy $fh
        Read<FH><$fh>
        Writeprint FH ...print $fh ...
Re: Inappropriate ioctl for device
by Fletch (Bishop) on Oct 29, 2007 at 14:27 UTC

    You have several precedence problems where you're using || where you really want or instead. Your print line for instance parses like this:

    print(SAVE ($output || die(((q[can't write to save ] . $!) . "\n"))));

    Which means that if $output evaluates to a false value then you're going to see a spurious die with who knows what error message from who knows what transient value that got left in $!.

    Update: OK, maybe s/several/a couple/; looking closer you have precedence problems with the print line and when you call open.