Software Development Kit (SDK) and API Discussions

Perl API file-write-file "Missing: offset"?

j_kleijer
4,446 Views

Hi all,

I'm trying to create a script that creates users on our filers when necessary and create the appropriate /vol/vol0/etc/sshd/<user>/.ssh/authorized_keys file and so far, I've been able to create the user and create the directories when necessary.

I'm now in the process of trying to create the file authorized_keys using the API call file-write-file* and basically use this function call to create the file and inject / write the keys in to them.

I've been able to figure out that I need to pack the data that I'm trying to write but no matter what I try, I keep getting the error message

file-write-file: Missing input: offset

even though the offset is explicitly given during the following command:

$dst_file = "/vol/vol0/etc/sshd/jmk3/.ssh/authorized_keys";

$packed_string = pack( "H*",  $lines[0] );

$offset = -1;

$api_output = $connection->invoke( $api_call, "path", $dst_file, "data", $packed_string, "offset", $offset );

Using this I get the "Missing input: offset" error.

Does anyone know what's going on here?

Kind regards,

Jeroen Kleijer

*) The reason I want to use the API-call file-write-file is that some of our filers have been installed with vol0 being on a NTFS filesystem meaning that I cannot mount them that easily under Linux and write the authorized_keys file. (yes, I can export it using NFS but then I would have to create a mapping where root = Administrator and that was something that I'd hope to avoid. If I can use the API I'd prefer to do that)

6 REPLIES 6

j_kleijer
4,446 Views

Ok, should've tried some more combinations before posing the question.

Apparently order is important when using the file-write-file API-call:

Using

$api_output = $connection->invoke( $api_call, "offset", $offset, "path", $dst_file, "data", $packed_string );

seems to work (though I'm still trying to figure out how to pack the string to something that the API likes)

Kind regards,

Jeroen Kleijer

rle
NetApp Alumni
4,446 Views

The API documentation states that the data should be in this form:

Data to be written. The format of the data is ASCII hex characters, two characters representing one byte. Whitespace characters, for convenience in formatting, can be present in the value and are ignored.

The data needs to be converted to ASCII hex.  This was done so that binary values could be easily transferred.  I have included some Perl code to do the conversion.

sub str_to_hex($) {
        my $s = shift;
        my $r = "";
        my $leng = length($s);
        for ( my $n=0; $n < $leng; $n++ ) {
                my $c = substr($s,$n,1);
                my $hx = sprintf "%02x", ord("$c");
                $r = $r . $hx;
        }
        return($r);
}
sub hex_to_str($) {
        my $s = shift;
        my $r = "";
        my $leng = length($s);
        for ( my $n=0; $n < $leng; $n+=2 ) {
                my $hx = substr($s,$n,2);
                my $hn = hex("$hx");
                $r = $r . chr($hn);
        }
        return($r);
}

Before the string is written, use string to str_to_hex(). 

Also note the the offset is integer, and therefore you must covert the integer to a string.  Your call could look like this:

$offset = "-1";

$api_output = $connection->invoke( $api_call, "offset", $offset, "path", $dst_file, "data", $packed_string );

Regards,

   - Rick -

kevingraham
4,446 Views

Rick -- pack and unpack are your friends:

$elem->child_add(NaElement->new('data', unpack('H*', $filedata));

...and:

$filedata = pack('H*', $elem->child_get_string('data'));

chris_algar
4,446 Views

Or use 'ord':

     (my $hex = $args{conent} ) =~ s/(.|\n)/sprintf("%02lx", ord $1)/eg;

      my $output     = $serv->invoke( "file-write-file",

                                                    "data", $hex,

                                                    "offset", $args{offset},

                                                    "overwrite", $args{overwrite},

                                                    "path", $args{path} );

and from back from hex when reading:

     $content     =~ s/([a-fA-F0-9]{2})/chr(hex $1)/eg;

chris_algar
4,444 Views

Or use 'ord':

     (my $hex = $args{conent} ) =~ s/(.|\n)/sprintf("%02lx", ord $1)/eg;

      my $output     = $serv->invoke( "file-write-file",

                                                    "data", $hex,

                                                    "offset", $args{offset},

                                                    "overwrite", $args{overwrite},

                                                    "path", $args{path} );

and from back from hex when reading:

     $content     =~ s/([a-fA-F0-9]{2})/chr(hex $1)/eg;

chris_algar
4,446 Views

Or use 'ord':

     (my $hex = $args{conent} ) =~ s/(.|\n)/sprintf("%02lx", ord $1)/eg;

      my $output     = $serv->invoke( "file-write-file",

                                                    "data", $hex,

                                                    "offset", $args{offset},

                                                    "overwrite", $args{overwrite},

                                                    "path", $args{path} );

and from back from hex when reading:

     $content     =~ s/([a-fA-F0-9]{2})/chr(hex $1)/eg;

Public