Откуда uname получает свою информацию?

Я решил эту проблему (отправленный мной) переустановка alsa-utils. Я не знаю, является ли это решением, но оно работает на меня.

41
24.08.2015, 01:47
8 ответов

Как уже говорилось, информация приходит вместе с uname syscall, информация о котором жестко закодирована в работающем ядре.

Версионная часть обычно устанавливается при компиляции нового ядра с помощью Makefile:

VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =

, когда у меня было время поиграть с компиляцией моих ядер, я добавлял там вещи в EXTRAVERSION; это давало вам uname -r с такими вещами, как 3.4.1-mytestkernel.

Я не до конца понимаю это, но думаю, что остальная информация установлена в Makefile также вокруг линии 944:

# ---------------------------------------------------------------------------

# KERNELRELEASE can change from a few different places, meaning version.h
# needs to be updated, so this check is forced on all builds

uts_len := 64
define filechk_utsrelease.h
    if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
      echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2;    \
      exit 1;                                                         \
    fi;                                                               \
    (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";)
endef

define filechk_version.h
    (echo \#define LINUX_VERSION_CODE $(shell                         \
    expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
    echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef

$(version_h): $(srctree)/Makefile FORCE
    $(call filechk,version.h)

include/generated/utsrelease.h: include/config/kernel.release FORCE
    $(call filechk,utsrelease.h)

PHONY += headerdep
headerdep:
    $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
    $(srctree)/scripts/headerdep.pl -I$(srctree)/include

Для остальных данных, sys_uname sys_uname syscall генерируется с помощью макросов (в довольно запутанном виде), вы можете начать с здесь , если вы чувствуете себя авантюристом.

Наверное, лучший способ изменить такую информацию - это написать модуль ядра для переопределения системного вызова uname; я никогда этого не делал, но вы можете найти информацию на этой странице в разделе 4.2 (извините, прямая ссылка отсутствует). Обратите внимание, однако, что этот код относится к довольно старому ядру (теперь ядро Linux имеет uts пространства имен, что бы они ни значили), так что вам, вероятно, придется его сильно поменять.

6
27.01.2020, 19:35

С помощью перекрестной ссылки Linux и вашего упоминания /proc/sys/kernel/ostype я отследил ostype до include/linux/sysctl.h, где комментарий говорит, что имена добавляются вызовом register_sysctl_table.

Итак, откуда этот вызывается из ? Одним из мест является kernel/utsname_sysctl.c, который включает в себя include/linux/uts.h, где мы находим:

/*.
 * Определяет, что должна возвращать функция uname() * 
 */
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

Итак, как указано в документации к ядру :

Единственный способ настроить эти значения - это перестроить ядро

:-)

.
8
27.01.2020, 19:35

Данные хранятся в init/version.c:

struct uts_namespace init_uts_ns = {
        .kref = {
                .refcount       = ATOMIC_INIT(2),
        },
        .name = {
                .sysname        = UTS_SYSNAME,
                .nodename       = UTS_NODENAME,
                .release        = UTS_RELEASE,
                .version        = UTS_VERSION,
                .machine        = UTS_MACHINE,
                .domainname     = UTS_DOMAINNAME,
        },
        .user_ns = &init_user_ns,
        .proc_inum = PROC_UTS_INIT_INO,
};
EXPORT_SYMBOL_GPL(init_uts_ns);

Сами строки находятся в include/generated/compile.h:

#define UTS_MACHINE "x86_64"
#define UTS_VERSION "#30 SMP Fri Apr 11 00:24:23 BST 2014"

и в include/generated/utsrelease. h:

#define UTS_RELEASE "3.14.0-v2-v"

UTS_SYSNAME может быть определено в include/linux/uts.h

#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

или как #define в makefiles

Наконец, имя хоста и доменное имя могут управляться /proc/sys/kernel/{hostname,domainname}. Это для пространства имен UTS:

# hostname
hell
# unshare --uts /bin/bash
# echo test > /proc/sys/kernel/hostname 
# hostname
test
# exit
# hostname
hell
26
27.01.2020, 19:35

Утилита uname получает информацию из системного вызова uname () . Он заполняет такую ​​структуру (см. man 2 uname ):

       struct utsname {
           char sysname[];    /* Operating system name (e.g., "Linux") */
           char nodename[];   /* Name within "some implementation-defined
                                 network" */
           char release[];    /* Operating system release (e.g., "2.6.28") */
           char version[];    /* Operating system version */
           char machine[];    /* Hardware identifier */
       #ifdef _GNU_SOURCE
           char domainname[]; /* NIS or YP domain name */
       #endif
       };

Это происходит непосредственно из работающего ядра. Я предполагаю, что вся информация жестко закодирована в нем, за исключением, возможно, имени домена (и, как оказалось, также имени узла , машины и ] выпуск , см. комментарии). Строка выпуска из uname -r может быть установлена ​​через конфигурацию во время компиляции, но я очень сомневаюсь, что поле sysname может - это ядро ​​Linux, и нет никаких причин для использования чего-либо еще .

Однако, поскольку это открытый исходный код, вы можете изменить исходный код и перекомпилировать ядро, чтобы использовать любое системное имя, какое захотите.

26
27.01.2020, 19:35

Хотя я не смог найти ничего в источнике, чтобы указать на это, я считаю, что он использует системный вызов uname.

man 2 uname

должен рассказать вам об этом подробнее. Если это так, он получает информацию непосредственно из ядра и ее изменение, вероятно, потребует перекомпиляции.

Вы можете изменить двоичный файл для uname, чтобы делать все, что захотите, просто напишите поверх него с помощью ж / е программы, которая вам нравится. Обратной стороной является то, что некоторые сценарии полагаются на этот вывод.

2
27.01.2020, 19:35

Правильный способ изменить uname - это изменить заголовки компиляции и перекомпилировать, как предлагали другие. Но я не уверен, почему вы хотите испытывать столько проблем, если вы можете сделать что-то вроде,

alias uname 'uname \\!* | sed s/2.6.13/2.6.52/'

или даже

alias uname 'echo whatever'
1
27.01.2020, 19:35

Ответ Rmano помог мне на полпути, но настоящее волшебство легче обнаружить, передав параметр Q=в вашей командной строке makeв исходном каталоге ядра. он позволяет увидеть детали, одна из которых — вызов скрипта:echo "4.4.19$(/bin/sh./scripts/setlocalversion.)". выполнение того же фрагмента дает номер версии ядра 4.4.19-00010-ge5dddbf. если вы посмотрите на скрипт, он определяет номер из системы управления версиями, и запуск его с bash -xпоказывает точный процесс:

+++ git rev-parse --verify --short HEAD
++ head=e5dddbf
+++ git describe --exact-match
++ '[' -z '' ']'
++ false
+++ git describe
++ atag=release/A530_os_1.0.0-10-ge5dddbf
++ echo release/A530_os_1.0.0-10-ge5dddbf
++ awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
++ git config --get svn-remote.svn.url
++ git diff-index --name-only HEAD
++ grep -qv '^scripts/package'
++ return
+ res=-00010-ge5dddbf
+ echo -00010-ge5dddbf
-00010-ge5dddbf

Это показывает мне, что если я хочу собрать модуль ядра для работы с моим работающим ядром, я нахожусь на неправильном выпуске с тегами и неправильном коммите. Мне нужно исправить это и собрать по крайней мере DTB (make dtbs), чтобы создать сгенерированные файлы с правильным номером версии.


оказывается, даже этого было недостаточно. Мне пришлось заменить scripts/setlocalversionна тот, который просто делает:

#!/bin/sh
echo -0710GC0F-44F-01QA

затем перестройте автоматически сгенерированные файлы:

make Q= ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs

затем я смог собрать образец драйвера Дерека Моллоя и успешно insmod. по-видимому, предупреждение об отсутствии Module.symversне имело значения.все, что Linux использовал, чтобы определить, будет ли модуль работать, было этой строкой localversion.

0
27.01.2020, 19:35

scripts/mkcompile_h

В v4.19 это файл, который генерирует include/generated/compile.hи содержит несколько интересных частей/proc/version:https://github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_h

  • Часть #<version>исходит из файла .versionв дереве сборки, которое увеличивается всякий раз, когда возникает ссылка (требует изменения файла/конфигурации )на scripts/link-vmlinux.sh.

    Его можно переопределить KBUILD_BUILD_VERSIONпеременной окружения:

    if [ -z "$KBUILD_BUILD_VERSION" ]; then
        VERSION=$(cat.version 2>/dev/null || echo 1)
    else
        VERSION=$KBUILD_BUILD_VERSION
    fi
    
  • дата просто необработанная dateзвонок:

    if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
        TIMESTAMP=`date`
    else
        TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
    fi
    

    и аналогично имя пользователя происходит отwhoami(KBUILD_BUILD_USER)и имя хоста отhostname(KBUILD_BUILD_HOST)

  • Версия компилятора взята из gcc -vи, похоже, не поддается контролю.

Вот как изменить материальную версию вопроса:https://stackoverflow.com/questions/23424174/how-to-customize-or-remove-extra-linux-kernel-version-details-shown-at-boot

2
27.01.2020, 19:35

Теги

Похожие вопросы