uname은 어디에서 정보를 얻습니까?


40

uname은 실제로 어디에서 정보를 얻습니까?

나는 이것이 간단해야한다고 생각합니다. 불행히도 해당 정보 만 포함 된 헤더를 찾을 수 없습니다.

말은 사람의 기본 출력 변경을 원 uname/를 uname -s 에서 Linux(커널의 이름을 변경, 본질적으로) 뭔가 다른.

올바른 방법으로 (즉, 소스를 변경) 어떻게해야합니까?

답변:


26

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
       };

이것은 실행중인 커널에서 직접 온 것입니다. 나는 모든 정보가 하드 코딩 그것으로 가정 아마를 제외시켰다 것 domainname(그리고 밝혀도 nodename, machine그리고 release, 주석을 참조). 의 릴리스 문자열 uname -r은 컴파일 타임에 구성을 통해 설정할 수 있지만 sysname 필드는 Linux 커널이므로 다른 것을 사용할 이유가 없습니다.

그러나 오픈 소스이기 때문에 원하는 sysname을 사용하도록 소스 코드를 변경하고 커널을 다시 컴파일 할 수 있습니다.


2
domainname필드는 설정되어 domainname사용하여, 명령 setdomainname시스템 호출을. 마찬가지로 nodename필드는 시스템 호출을 hostname사용하여 명령으로 설정됩니다 sethostname. ( nodename/ hostname값은에 저장 될 수 있습니다 /etc/nodename.)
Scott

2
이것은 관련이 없습니다. 질문은 어디에서 변경해야하는지 물었습니다. 예, uname명령은 시스템 호출에서 정보를 얻습니다. 그리고 시스템 호출은 어디에서 정보를 얻습니까? (여기서 다른 포스터에서 제공하는 답변 : 컴파일 타임에 커널에 하드 코딩되어 있습니다.)
Gilles 'SO-stop

@Gilles : 관련성이 무엇입니까? 대답이 "여기에 다른 포스터에서 제공된다면 : 커널에 하드 코딩되어 있습니다 ..."참고 정확히 같은 말을했습니다. "이것은 실행중인 커널에서 직접 온 입니다. 모든 정보가 어렵다고 가정합니다 . -coded ... 오픈 소스이므로 소스 코드를 변경하고 원하는 sysname을 사용하도록 커널을 다시 컴파일 할 수 있습니다 . 구성 옵션 이 아닙니다
goldilocks

2
@goldilocks 왜 machine변할까요? 하드웨어에 적응할 수 있기 때문에 커널에 하드 코딩되지 않을 수도 있지만, 부팅시 설정되고 그 후에는 변경되지 않습니다. 그러나 아니오 : 프로세스 당 설정할 수 있습니다 (예 : i686x86_64에서 처리 된 32 비트로 보고 ). 그건 그렇고, release프로세스별로 어느 정도 사용자 정의 할 수 있습니다 (try setarch i686 --uname-2.6 uname -a).
Gilles 'SO- 악한 중지'

1
@Gilles 내가 편집 한 machine, nodenamerelease의견에 대한 참조를 사용하여 질문에. 다시 한 번 질문은 모든 분야에 관한 것이 아닙니다.
goldilocks

26

데이터는 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

또는 makefile에서 #define으로

마지막으로, 호스트 이름과 도메인 이름은 / proc / sys / kernel / {hostname, domainname}으로 제어 할 수 있습니다. UTS 네임 스페이스 별입니다.

# hostname
hell
# unshare --uts /bin/bash
# echo test > /proc/sys/kernel/hostname 
# hostname
test
# exit
# hostname
hell

이것은 일반적으로 좋고 완전한 답변이지만 포스터의 질문에 직접 대답하는 동안 가치가있을 수 있습니다. 나는 이것이 관련 파일의 관련 항목을 변경하고 다시 컴파일해야한다고 생각합니다. "또는 makefile에서 #define으로"작성했습니다. 정교하게 할 수 있습니까?
Faheem Mitha

일에 대한 unshare. 어떻게 든 오늘 까지이 명령을 놓쳤습니다. 감사!
티노

그리고 include/generated/compile.h에 의해 생성 scripts/mkcompile_h: unix.stackexchange.com/a/485962/32558
치로 틸리新疆改造中心法轮功六四事件

8

는 A의 도움으로 리눅스 상호 참조 및 당신의 언급 /proc/sys/kernel/ostype, 나는 추적 ostype할 수 / 리눅스 / sysctl.h 포함 코멘트가 이름을 호출하여 추가 말한다 곳 register_sysctl_table.

어디에서 호출 합니까? 한 곳은 kernel / utsname_sysctl.c 이며 여기에는 include / linux / uts.h 가 포함 됩니다 .

/*
 * Defines for what uname() should return 
 */
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif

커널 문서에 나와있는 것처럼 :

이 값을 조정하는 유일한 방법은 커널을 다시 작성하는 것입니다

:-)


6

다른 곳에서 언급했듯이 uname정보는 syscall 과 함께 제공 되며이 정보는 실행중인 커널에 하드 코딩됩니다.

버전 파일은 보통 Makefile에 의해 새로운 커널을 컴파일 할 때 설정됩니다 :

VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =

커널 컴파일을 할 시간이 있었을 때 EXTRAVERSION에서 추가했습니다. 그것은 당신에게 uname -r 같은 것을주었습니다 3.4.1-mytestkernel.

나는 그것을 완전히 이해하지 못하지만 나머지 정보는 Makefile944 줄에 설정되어 있다고 생각합니다 .

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

# 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_unamesyscall은 매크로를 사용하여 (매우 복잡한 방식으로) 생성됩니다 . 모험심이 느껴지면 여기 에서 시작할 수 있습니다 .

아마도 이러한 정보를 변경하는 가장 좋은 방법은 unamesyscall 을 무시하기 위해 커널 모듈을 작성하는 것입니다 . 나는 그렇게하지 않았지만 4.2 페이지의이 페이지 에서 정보 찾을 수 있습니다 (죄송합니다, 직접 링크 없음). 그러나이 코드는 아주 오래된 커널 (현재 Linux 커널에는 uts네임 스페이스가 무엇이든 관계없이 이름 공간이 있음)을 참조하므로 아마 많이 변경해야합니다.


고마워요 나는 그것이 그것이 uname과 관련이 있다는 것을 이미 알고 있었다. 그러나 내가 이해할 수없는 것은 소스 내부에서 문자열 "Linux"가 어떻게 그리고 어디에 정의되어 있는지입니다. 내가 아는 것은 런타임 동안 해당 정보를 찾을 수있는 곳입니다 (/ proc / sys / kernel / ostype에 포함되어 있음). 커널 자체가 올바른 이름이라는 것을 정확히 아는 것이 더 흥미로운 것 중 하나라고 생각합니다.
user237251

@ user237251 문자열 컨텍스트에서 커널 소스에 "Linux"라는 단어가 몇 개나 있습니까? 그 수가 많지 않으면 텍스트 검색 결과를 조사하여 그 결과가 어디로 가는지 알 수 있습니다.
JAB

@JAB Way가 너무 많습니다. 다행히도 kernelnewbies.org의 누군가가 "수수께끼"를 해결하도록 도와주었습니다. Linux는 /include/Linux/uts.h에서 시스템 이름을 가져옵니다. 여기를 참조하십시오 : lxr.free-electrons.com/source/include/linux/uts.h?v=3.10
user237251

2

소스에서 이것을 표시하기 위해 아무것도 찾을 수 없지만 uname syscall을 사용한다고 생각합니다.

man 2 uname

그것에 대해 더 알려줘야합니다. 이 경우 커널에서 직접 정보를 가져 와서 변경하면 다시 컴파일해야 할 수도 있습니다.

바이너리를 변경하여 원하는대로 할 수는 있지만 원하는 w / e 프로그램으로 덮어 쓰십시오. 일부 스크립트 인 단점은 해당 출력에 의존합니다.


3
당신이 경우에 strace uname, 그것은 확인됩니다 uname시스템 호출이 사용된다.
Graeme 2016 년

1

uname을 변경하는 올바른 방법은 컴파일 헤더를 변경하고 다른 제안과 같이 다시 컴파일하는 것입니다. 하지만 왜 당신이 뭔가를 할 수있을 때 그렇게 많은 문제를 겪고 싶을 지 모르겠습니다.

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

또는

alias uname 'echo whatever'

0

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

이것이 보여주는 것은 실행중인 커널과 함께 작동하기 위해 커널 모듈을 빌드하려면 태그가 잘못된 릴리스와 커밋이 잘못되었다는 것입니다. make dtbs올바른 버전 번호로 생성 된 파일을 작성 하려면이를 수정하고 최소한 DTB ( )를 빌드해야합니다 .


충분하지 않은 것으로 밝혀졌습니다. 나는 scripts/setlocalversion단순히 다음 과 같은 것으로 교체 해야했습니다.

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

그런 다음 자동 생성 된 파일을 다시 빌드하십시오.

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

그런 다음 Derek Molloy의 샘플 드라이버를 빌드 insmod하고 성공적으로 만들 수있었습니다 . 분명히 Module.symvers존재하지 않는다는 경고는 중요하지 않았습니다. 모든 Linux는 모듈이 작동하는지 여부를 로컬 버전 문자열인지 확인하는 데 사용했습니다.


0

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 : //.com/questions/23424174/how-to-customize-or-remove-extra-linux-kernel-version-details-shown-at-boot

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.