この手順を実行する理由を理解できません
#include <stdio.h>
#include <stdlib.h>
int main()
{
int iRetval = 0;
unsigned int uiNum;
printf("Enter number: ");
fflush(stdout);
iRetval = scanf("%u", &uiNum);
printf("\nThe number is %u, Retval: %i\n", uiNum, iRetval);
fflush(stdout);
if( iRetval > 0)
system("/bin/sh");
else
printf("Goodbye!\n");
}
私のbashシェルから呼び出されたとき
echo -e "3\nls\n" | myprogram
lsの出力を印刷しないでください。system("/bin/sh")
呼び出しが呼び出し元の標準入力から読み取られていないのと同じです。私は一般的なLinuxユーザーではないので、system("/bin/sh");
この説明がどのように機能するかをよりよく理解するために、内容を読んで、実験を試み、コマンドを実行するのに役立ちます。
ベストアンサー1
scanf
その理由は、標準入力ストリームから読み取った内容を使用しているからです。バッファを使用するので、実際に必要なデータ量を確認する前にデータバッファを読み取ろうとします。コマンドls
はすぐに使用できるため、バッファに読み込まれ、他のscanf呼び出し(またはstdinで実行されている他のバッファ付きstdio関数)で使用されるのを待ちます。したがって、sh
stdinから読み取ろうとすると、Cプログラム内のバッファを見ることができないので、何も残りません。
この問題を解決する方法は少なくとも2つあります。
scanfが読み取りを完了するまで、lsコマンドが標準入力に反映されないことを確認してください。プログラムがそのポイントを通過したという証拠を出力するのを待つ必要があるか(マイナーではない)、固定された遅延を使用し、システムがそのポイントで停止せずに遅延を短くしすぎないことを望むので、これは少しトリッキーです(例:これは壊れます。簡単な解決策です)。後者は次のとおりです。
(echo 3 ; sleep 1 ; echo ls) | myprogram
つまり、3つのコマンドが順番に実行され、すべてmyprogram
。関数を使用して、stdin(バッファなし)から必要な最小文字数を読み取ることができます。たとえば、この
read
関数はバッファを使用しません。次のヘルパー関数を作成できます。
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
int unbuffered_scanf(const char *fmt, ...) {
char buffer[100]; // maximum line length
int i;
int ret;
for(i=0; i<sizeof(buffer)-1; ++i) {
if (!read(0, &buffer[i], 1)) break;
if (buffer[i] == '\n') break;
}
buffer[i] = '\0';
va_list ap;
va_start(ap, fmt);
ret = vsscanf(buffer, fmt, ap);
va_end(ap);
return ret;
}
int main()
{
int iRetval = 0;
unsigned int uiNum;
printf("Enter number: ");
fflush(stdout);
iRetval = unbuffered_scanf("%u", &uiNum);
printf("\nThe number is %u, Retval: %i\n", uiNum, iRetval);
fflush(stdout);
if( iRetval > 0)
system("/bin/sh");
else
printf("Goodbye!\n");
}
バッファリングされていない関数の詳細については、こちらの情報ページをご覧ください。https://www.gnu.org/software/libc/manual/html_node/I_002fO-Primitives.html#I_002fO-Primitives
編集する:scanf
明らかに、この機能を使用して他の人が実行するバッファリングを無効にする方法があります。setbuf
これはおそらく上記の例と内部的にまったく同じように機能します。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int iRetval = 0;
unsigned int uiNum;
setbuf(stdin, NULL);
printf("Enter number: ");
fflush(stdout);
iRetval = scanf("%u", &uiNum);
printf("\nThe number is %u, Retval: %i\n", uiNum, iRetval);
fflush(stdout);
if( iRetval > 0)
system("/bin/sh");
else
printf("Goodbye!\n");
}