C言語関係掲示板

過去ログ

No.382.system関数で呼び出したプログラムへの入力方法

[戻る] [ホームページ]
No.2551

system関数で呼び出したプログラムへの入力方法
投稿者---あげは(2002/08/31 17:29:57)


あげはと申します。
C言語でデーモンを作って、その中であるプログラムを呼び出して
出力結果を接続元に送る、というプログラムを作りたいのですが、
デーモン内で呼び出すプログラムの実行中にパスワードを聞かれ、
これを入力する方法が分からず困っています。

<デーモン内のソース例>
  system("prob_a");

<prob_a実行時の様子>
% prob_a
password? 
          ^^^^^^^^
          ↑ここをデーモンから自動入力したい

・prob_aは自作プログラムでないので作り替えはできません。
・入力リダイレクションを使ってみましたが失敗しました。
・system()のあとでprintf()を使ってパスワードを出力したら、
 案の定だめでした (^_^;

解決法をご存知の方がいましたらご教授いただけないでしょうか。

よろしくお願いします。


No.2552

参考になるかわかりませんが・・・
投稿者---はち(2002/08/31 17:46:30)


パスワードを要求しているのはprob_a内で実行しているコマンドかなにかですか?

Cではありませんが、以前UNIXでシェルスクリプトを書いたときに
内部でsuさせるときに同じように悩んだことがあります。

このときはrootにsuしたかったので、スクリプトのオーナーをrootにし、ファイルの属性にスティキィフラグを立てることで解決しました。


No.2553

Re:参考になるかわかりませんが・・・
投稿者---あげは(2002/08/31 18:49:41)


お返事ありがとうございます。

>パスワードを要求しているのはprob_a内で実行しているコマンドかなにかですか?
prob_aそのものが要求しているのだと思います。
例えば、prob_aは暗号化された文書を引数として受け取り、
実行途中で復号キーを聞いて復号する…という感じのプログラムです。

system()で駄目だったので新たにpopen()を試してみましたが、
標準入力からの入力要求でないのかうまくいきませんでした。
こうなるとお手上げなんでしょうか…。

No.2554

同じく参考になるかわかりませんが・・・
投稿者---kikk(2002/08/31 22:21:47)


ども。


手元に環境がないので確認できず的外れかもしれませんが。


書き込みをみて、最初に考えついたのが
system("echo PASSWORD|prob_a")
でしたが、入力リダイレクト("PASSWORD\n"を書いたファイルを
< するですよね)もだめということなのでこれもたぶんだめかと。


で、

>system()で駄目だったので新たにpopen()を試してみましたが、
>標準入力からの入力要求でないのかうまくいきませんでした。

これでいけそうな気がしたのですが、だめでしたか。
一応、
・パスワード書き込み時に改行を追加
・書き込み後にfflush()してみる
を確かめてみてください。たぶんもうやっているような気がしますが。。


あとはシェルがやっているようなこと(fork&exec)を自前でやるというのも
考えられますが、変わらないような気も。


では。

No.2556

Re:同じく参考になるかわかりませんが・・・
投稿者---あげは(2002/09/01 00:07:55)


お返事ありがとうございます。

>書き込みをみて、最初に考えついたのが
>system("echo PASSWORD|prob_a")

system()の引数の文字列内にパイプがあるとprob_aに怒られてしまいます。
中で何が起こっているのか…。

>>system()で駄目だったので新たにpopen()を試してみましたが、
>>標準入力からの入力要求でないのかうまくいきませんでした。
>
>これでいけそうな気がしたのですが、だめでしたか。

実はpopen()はついさっき知って初めて使ったのですが、

FILE *fp_w = popen("prob_a", "w");
fprintf(fp_w, "password");
pclose(fp_w);

という使い方でいいのでしょうか。
「うまくいかなかった」のは上記の書き方なのですが…。
ちなみにfprintf()の後ろでfflush(fp_w)とやっても駄目でした。

No.2555

Re:system関数で呼び出したプログラムへの入力方法
投稿者---かずま(2002/08/31 23:43:24)


> ・入力リダイレクションを使ってみましたが失敗しました。

それはそうでしょう。パスワードの入力は、標準入力ではなく、制御端末(/dev/tty)を
オープンして行われるはずですから。

次のプログラムは参考になりますか。
#include <sys/wait.h>
#include <pty.h>
#include <string.h>

int main()
{
    int n, fd;  char buf[1024];

    n = forkpty(&fd, buf, NULL, NULL); /* pty を open し、fork する */
    if (n == 0) {                      /* 子プロセス */
        system("prob_a");
        return 0;
    }
    /* 親プロセス */
    while ((n = read(fd, buf, 1024)) > 0) { /* prob_a の出力を読む */
        wirte(1, buf, n);                      /* prob_a の出力を表示 */
        if (strncmp(buf, "password?", 9) == 0) {   /* password 要求か */
            write(fd, "himitsu", 7);               /* password を送信 */
            write(1, "\n", 1);
        }
    }
    wait(NULL);  /* 子プロセスの終了を待つ */
    return 0;
}
Red Hat Linux 7.2 では、-lutil をつけてコンパイル。

No.2559

Re:system関数で呼び出したプログラムへの入力方法
投稿者---かずま(2002/09/02 14:55:33)


> 次のプログラムは参考になりますか。

> #include <pty.h>

NetBSD 1.5.2 では、#include <util.h> でした。
>       wirte(1, buf, n);                      /* prob_a の出力を表示 */
>       if (strncmp(buf, "password?", 9) == 0) {   /* password 要求か */
>           write(fd, "himitsu", 7);               /* password を送信 */
>           write(1, "\n", 1);
>       }

       write(1, buf, n);                      /* prob_a の出力を表示 */
       if (strncmp(buf, "password?", 9) == 0) {   /* password 要求か */
           write(fd, "himitsu\n", 8);             /* password を送信 */
           write(1, "\n", 1);
       }

password の送信では、改行コードをつけてください。


No.2563

Re:system関数で呼び出したプログラムへの入力方法
投稿者---あげは(2002/09/02 22:31:36)


お返事ありがとうございます。

こちらの実行環境は Solaris8 です。
書くのを忘れていた私が悪いのですが、
pty.h、util.h ともに見つからないため
まず forkpty() を使えるようにします。
その後教えていただいた方法を試してみてから改めてお返事します。

No.2566

Re:system関数で呼び出したプログラムへの入力方法
投稿者---かずま(2002/09/02 23:54:54)


> こちらの実行環境は Solaris8 です。

Solaris は得意ではありませんが、pty(擬似端末 pseudo terminal)の実装に
STREAMS を使っているかもしれないので、forkpty() がないとすれば、
次のようなコードが必要かもしれません。
このコードはエラーチェックをしていないし、たぶん動かないと思います。
int main(void)
{
    char *pn, buf[1024];  int fd, slave, n;

    fd = open("/dev/ptmx", O_RDWR);
    grantpt(fd);
    unlockpt(fd);
    pn = ptsname(fd);
    n = fork();
    if (n == 0) { /* child process */
        slave = open(pn, O_RDWR, 0);
        ioctl(slave, I_PUSH, "ptem");
        ioctl(slave, I_PUSH, "ldterm");
        close(fd);
        dup2(slave, 0); dup2(slave, 1); dup2(slave, 2);
        ioctl(slave, TIOCSCTTY, 0);
        system("prob_a");
        return 0;
    }
    /* parent process */
    n = read(fd, buf, 1024);
    if (strncmp(buf, "password?", 9) == 0)
        write(fd, "himitsu\n", 8);
    wait(0);
    return 0;
}


No.2659

Re:system関数で呼び出したプログラムへの入力方法
投稿者---あげは(2002/09/09 18:47:14)


返事が遅くなってしまい申し訳ありません。
書いていただいたソースはTIOCSCTTYという変数が未定義だと言われて
コンパイルできませんでした(termios.hにある、とマニュアルに
あるのですがなぜか未定義だと)。

そこでTIOCSCTTYの代わりに無理やり0を代入したらコンパイルは通ったの
ですが、無限ループみたいに処理が止まってしまい、強制終了するしか
ありませんでした。

実は使用言語がperlに変更になってしまったので、今度はperlで同じことが
できないかを探してみます。

いろいろとありがとうございました。