プロセスが手動で実行されると、Linux ioctl VT_GETSTATEは失敗します。

プロセスが手動で実行されると、Linux ioctl VT_GETSTATEは失敗します。

私はioctl現在、Cプログラムからttyを取得するためにLinuxでシステムコールを使用しています。

ioctlプログラムを手動で(rootとして)実行すると、プログラムが失敗する理由はわかりませんが、init.dスクリプト(root)を使用すると期待どおりに機能します。 GUIセッションでSSH接続またはターミナルアプリケーションを使用しようとしています。プログラムを正しく実行する唯一の方法は、仮想端末(CTRL + Fx、xは数字)に切り替えてそこからコマンドを実行することです。このプログラムをRHEL8とRHEL6でテストした。 RHEL8 では ("デバイスに不適切な ioctl")ioctlが返されENOTTY、RHEL6 ではエラーがEINVAL("無効な引数") です。

問題をデバッグするためにこのテストプログラムを作成しましたが、基本プログラムとは異なる動作をしているようです。

#include <stdlib.h> 
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <linux/vt.h>
#include <linux/kd.h>

int main()
{

    long tty = -1;
    long fd = 0;
    int result = 0;
    struct vt_stat ttyinfo;

    fd = open("/dev/tty", O_RDWR | O_NOCTTY);

    if(fd <= 0) 
    {
        printf("Trying tty0\n");
        fd = open("/dev/tty0", O_RDWR | O_NOCTTY);

        if(fd <= 0)
        {
            printf("[open] error = %s\n" , strerror(errno) );
            return -1;
        }
    }

    result = ioctl(fd, VT_GETSTATE, &ttyinfo);

    if (result == 0) 
    {
        tty = ttyinfo.v_active;
        printf("tty: %d\n" , tty);
    }
    else
    {
        printf("[ioctl] error = %s\n" , strerror(errno) );
    }

    return 0;
}

注:これは単なるコードスニペットであり、実際のプログラムはデーモンであり、より多くのことを行います。

RHEL8:

UI または実際のアプリケーション (SSH) でコマンドを実行して /dev/tty および /dev/tty0 を試みると、報告されるエラーは次のとおりです。 Inproperty ioctl for device.

RHEL6: SSH /dev/ttyを使用してUIでコマンド(実際のアプリケーション)を実行すると、次のエラーが報告されます。無効な引数

なぜこれが起こるのか知っていますか?テストプログラムにデーモンを追加してみましたが、テストプログラムは機能し続けますが、メインプログラムは機能しません。テストプログラムが実行していないタスクのうち、メインプログラムが実行する他のタスクが必要です。

答え1

仮想コンソールではなく端末でプログラムを実行しているため、これが発生していると思われます。/dev/tty制御端末へのアクセスを提供する特別な装置です。、必ずしも仮想コンソールではありませんが、ioctl使用中のものは仮想コンソールにのみ適用されます。

fdポイントがどこかにあることを確認すると、プログラムは確実に実行されます。仮想コンソール、rootとして実行するときにこれを行う最も簡単な方法は/dev/tty0アクティブな仮想コンソールです。:

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/vt.h>

int main(int argc, char **argv) {
  long tty = -1;
  long fd = 0;
  int result = 0;
  struct vt_stat ttyinfo;

  fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
  if (fd < 0) {
    perror("Error opening /dev/tty0");
    return 1;
  }
  result = ioctl(fd, VT_GETSTATE, &ttyinfo);
  if (result == 0) {
    tty = ttyinfo.v_active;
    printf("Active tty: %ld\n", tty);
  } else {
    perror("ioctl failed");
  }
}

関連情報