NSTaskの実行について

157 views
Skip to first unread message

Randy Rhoads

unread,
Jul 17, 2010, 5:02:33 AM7/17/10
to cocoa-dev-japan
初の投稿ですがよろしくお願い致します。
NSTaskでOSX固有のコマンドの"diskutil"でドライブのUUIDを取得したいのですが質問です。
以下のソースでdiskutilからUUIDを取得するコードを組んだのですが、EXC_BAD_ACCESSもしくは取得できませんでした。このソー
スにおかしい部分があったらご指摘願えないでしょうか。

- (IBAction)targetSelect:(id)sender {
// set string to textField
[textField setStringValue:@"Please select target hard drive"];
NSString *drive_str = @"/Volumes/";
NSOpenPanel *opanel = [NSOpenPanel openPanel];
// NSOpenPanelの動作設定
[opanel setAllowsMultipleSelection:NO];
[opanel setCanChooseDirectories:YES];
[opanel setResolvesAliases:YES];
[opanel setCanChooseFiles:NO];

int opReturn;
opReturn = [opanel runModalForDirectory:drive_str
file:nil
types:nil];
if (opReturn == NSOKButton) {
target_path = [NSString stringWithFormat:@"%@", [opanel filename]];

[textField setStringValue:[opanel filename]];
}
else {
NSLog(@"Canceled.");
}


- (IBAction)saveSelect:(id)sender {
task = [[NSTask alloc] init];
pOutput = [[NSPipe alloc] init];
pError = [[NSPipe alloc] init];

// コマンドと引数を設定
[task setLaunchPath:@"/usr/sbin/diskutil"];

[task setArguments:[NSArray arrayWithObjects: @"info", @"%@",
target_path, nil]];
// [task setArguments:[NSString stringWithFormat: @"info %@",
target_path]];
NSLog(@"%s", target_path);
// 標準出力先
[task setStandardOutput:pOutput];
// エラー出力先
[task setStandardError:pError];
// 実行
[task launch];

// NSData *data = [handle readDataToEndOfFile];
// NSString *output = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];

NSData *dataError = [[pError fileHandleForReading] availableData];
NSData *dataOutput = [[pOutput fileHandleForReading] availableData];

NSLog(@"%@", [NSString stringWithFormat:@"error-s", [dataError
bytes]]);
NSLog(@"%@", [[[NSString alloc]initWithData:dataOutput
encoding:NSUTF8StringEncoding]autorelease]);

[task release];
[pOutput release];
[pError release];
}

kimura wataru

unread,
Jul 18, 2010, 6:13:53 AM7/18/10
to cocoa-d...@googlegroups.com
木村(わ)といいます。

該当クラスのヘッダファイルもないと確実なことはわかりませんが
おそらく target_path のメモリ管理の問題だと思います。

* target_pathをretainありのプロパティにする
* target_pathを適切にretain/releaseする
* GC有効にしてアプリをコンパイルする

のいずれかでEXC_BAD_ACCESSは解消すると思います。

On Sat, 17 Jul 2010 02:02:33 -0700 (PDT), Randy Rhoads wrote:
> 初の投稿ですがよろしくお願い致します。
> NSTaskでOSX固有のコマンドの"diskutil"でドライブのUUIDを取得したいので
> すが質問です。


> 以下のソースでdiskutilからUUIDを取得するコードを組んだのですが、
> EXC_BAD_ACCESSもしくは取得できませんでした。このソー
> スにおかしい部分があったらご指摘願えないでしょうか。
>
> - (IBAction)targetSelect:(id)sender {
> // set string to textField
> [textField setStringValue:@"Please select target hard drive"];

> target_path = [NSString stringWithFormat:@"%@", [opanel filename]];
非GCのとき、ここでretainCountが確保されていないので問題になります。

> - (IBAction)saveSelect:(id)sender {
> task = [[NSTask alloc] init];
> pOutput = [[NSPipe alloc] init];
> pError = [[NSPipe alloc] init];
>
> // コマンドと引数を設定
> [task setLaunchPath:@"/usr/sbin/diskutil"];
>
> [task setArguments:[NSArray arrayWithObjects: @"info", @"%@",
> target_path, nil]];

ここの@"%@"が不要です。

> NSData *dataError = [[pError fileHandleForReading] availableData];
> NSData *dataOutput = [[pOutput fileHandleForReading] availableData];
>

今回は出力が小さいので問題ありませんでしたが、一般的にパイプを使ったときは
出力がなくなるまで何度か読む必要があります。

http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/OperatingSystem/Tasks/pipes.html


--
kimura wataru

Koichi Saeki

unread,
Jul 18, 2010, 10:44:17 AM7/18/10
to cocoa-d...@googlegroups.com
さえきと申します。

木村さんがすでにコメントされているので、あえて別の角度で。。

もし、あくまで目的はボリューム情報の取得であって、
特に NSTask や diskutil を使いたいわけではない、ということなら、
API で直接取得したらどうでしょう??

いくつか方法はあるでしょうが、その中でも比較的簡単な方法として、
File Manager と Disk Arbitration Framework を使用した方法を紹介しておきます。


DASessionRef session = DASessionCreate(kCFAllocatorDefault);

OSErr err = noErr;

for (ItemCount volumeIndex = 1; err == noErr || err != nsvErr; volumeIndex++) {

FSVolumeRefNum actualVolume;
err = FSGetVolumeInfo(kFSInvalidVolumeRefNum, volumeIndex, &actualVolume, kFSVolInfoNone, NULL, NULL, NULL);
if (err == noErr) {

GetVolParmsInfoBuffer volumeParms;
err = FSGetVolumeParms(actualVolume, &volumeParms, sizeof(volumeParms));
if (err == noErr) {
if (volumeParms.vMServerAdr == 0) {
DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, volumeParms.vMDeviceID);
CFDictionaryRef description = DADiskCopyDescription(disk);
CFUUIDRef volumeUUID = CFDictionaryGetValue(description, kDADiskDescriptionVolumeUUIDKey);

NSLog(@"%s: %@", volumeParms.vMDeviceID, volumeUUID);

CFRelease(description);
CFRelease(disk);
}
}
}
}

CFRelease(session);

Randy Rhoads

unread,
Jul 19, 2010, 5:30:06 PM7/19/10
to cocoa-dev-japan
迅速な回答ありがとうございます。

引数設定の部分で基本的なミスをしてしまっていたようですね。。
GC及びメモリ管理についてもしっかり勉強し直すつもりです。

Randy Rhoads

unread,
Jul 19, 2010, 5:38:37 PM7/19/10
to cocoa-dev-japan
親切な回答ありがとうございます。

目的はボリューム情報の取得なんですが、他に方法が思いつかず、
Cocoa APIのリファレンスでNSTaskを見つけて実装しようと思っていたところでした。

このコードをビルドしてみたところ思った通りの情報が得られました。

日本語だけでなく英語のドキュメントやリファレンスでも併せて探したほうがいいですね。
Reply all
Reply to author
Forward
0 new messages