RPI-4のDebian Bookworm "who"コマンドは、ログイン日時の代わりに大きな数字を表示します。

RPI-4のDebian Bookworm "who"コマンドは、ログイン日時の代わりに大きな数字を表示します。

RPI-4でDebian Bookwormを使用すると、このwhoコマンドはログイン日時の代わりに大きな数字を表示します。一部の検索では、/run/utmp所有権と権限を削除、再作成、確認することを提案しています。

私はうまく動作する他のシステムにあるものと一致するように root:rootそれらを変更しました。これらのどれも役に立ちません。rw-r--r--root:utmprw-rw-r--

以下はコマンドの出力ですwho

root     pts/0        7205944946380205577 (192.168.0.100)

次のようにする必要があります。

root     pts/0        2024-03-17 15:49 (192.168.0.100)

2 つの AMD プロセッサシステムは正常に動作しますが、2 つの RPI-4 はそうではありません。

私が調査した内容は次のとおりwhoです。

type who
 who is hashed (/usr/bin/who)
who --version
 who (GNU coreutils) 9.1 

私のオペレーティングシステムはDebian Bookworm 12.1 Kernel 6.1.21-v8+ aarch64です。

答え1

まあ、私たちはますます近づいています。

あなたの意見で述べたように、デバッグにgdbを使用していただきありがとうございます。

$> gdb /usr/bin/who
(gdb) break strftime
(gdb) run
Starting program: /usr/bin/who [Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
 root pts/0 7205944946380205577 (192.168.0.100)
[Inferior 1 (process 6631) exited normally]
(gdb) 

strftime実際には呼び出されないと言えます。しなければならないwhov9.1に関する限りsrc/who.c、(330行目から始まります):

/* Send properly parsed USER_PROCESS info to print_line.  The most
   recent boot time is BOOTTIME. */
static void
print_user (const STRUCT_UTMP *utmp_ent, time_t boottime)
{
// …
/* skipping to line 434 */
  print_line (sizeof UT_USER (utmp_ent), UT_USER (utmp_ent), mesg,
              sizeof utmp_ent->ut_line, utmp_ent->ut_line,
              time_string (utmp_ent), idlestr, pidstr,
              hoststr ? hoststr : "", "");
}

ここで興味深い部分は、ここ(216ff行)と呼ばれる関数ですstatic char const *time_string(const STRUCT_UTMP *)。この関数の仕事は、utmpエントリから時間情報を取得し、人間に優しい方法で印刷することです。

/* Return a time string.  */
static char const *
time_string (const STRUCT_UTMP *utmp_ent)
{
  static char buf[INT_STRLEN_BOUND (intmax_t) + sizeof "-%m-%d %H:%M"];

  /* Don't take the address of UT_TIME_MEMBER directly.
     Ulrich Drepper wrote:
     "... GNU libc (and perhaps other libcs as well) have extended
     utmp file formats which do not use a simple time_t ut_time field.
     In glibc, ut_time is a macro which selects for backward compatibility
     the tv_sec member of a struct timeval value."  */
  time_t t = UT_TIME_MEMBER (utmp_ent);
  struct tm *tmp = localtime (&t);

  if (tmp)
    {
      strftime (buf, sizeof buf, time_format, tmp);
      return buf;
    }
  else
    return timetostr (t, buf);
}

今、デバッガではstrftime呼び出されないと言います!

唯一の可能な方法はif tmp0つまりlocaltimereturnです0。 glibclocaltimeのマニュアルページを読むと、これはエラー条件でのみ発生することがわかります。残念ながら、正確に何が間違っているかという兆候はありません。しかし、time_t実際にaを使ってローカルタイムスタンプに変換することには問題はありませんlocaltime。指定された唯一のエラータイプは、渡された値が人に大きすぎる場合のオーバーフローです。ここで何が起こるかは次のとおりです。

このエラー状態が発生した場合、呼び出しは単に呼び出されますtimetostranytostrgnulib、特にgnulib / lib / anytostr.cです)。しかし、正直なところ、それは歴史的な理由でひどくて巨視的に汚染されています。anytostr(inttype i, char *buf)正直なところ、これは重複した再実装であるだけなので、utmpレコードを10進数として解釈して印刷するsprintf(buf, "%jd")だけです!time_t

驚くべきことに、10進数7205944946380205577を読むとナノ秒単位で測定されますが、それは何世紀から数千年の未来です。

そのため、utmpの記録が破損し、localtime合理的なローカルタイムスタンプに変換できないため、元の番号だけが印刷されます。

今、なぜファイルから読み取られたutmpレコードが破損しています。わかりません。

これは、実行中の両方のシステムで深刻なバグのようです。おそらく、utmpレコードがそれを読み取るlibcで使用されているものとは異なる構造定義で書かれていますかwho?おそらく、ファイルがx86 PCからARMシステムにコピーされている可能性は低いです。

これが私がコメントから「壊れたlibcアップデート」について推測した理由です。 1つの説明は、utmpファイルを読み取るときに正しいと仮定し、utmp.hファイルwhoを作成するときにまだ正しいと仮定することが異なることです。しかし、ファイルを削除したとし、その後ログインしたと仮定してそれを除外できます。

この時点では Debian レベルのデバッグが必要です。whoDebian Manager(おそらくパッケージマネージャ)にバグを送信することをお勧めしますcoreutils。 coreutilsのgnulibが最新であること、特に設定スクリプトが存在するかどうかをutmp.h正しく検出していることを確認してくださいutmpx.h。 (私はこれがgnulibがソースコードにコピーするソースコードの束であり、すでにこれを噛んでいるユーザーを含む他のシステムと同期を維持するのが難しい多くのケースの1つだと思います)。

関連情報