uname จะรับข้อมูลจากที่ไหน


40

uname ได้รับข้อมูลจากที่ไหน

ฉันคิดว่านี่เป็นสิ่งที่ควรตรงไปตรงมา น่าเสียดายที่ฉันไม่พบส่วนหัวที่มีเพียงข้อมูลนั้น

สมมติว่ามีคนต้องการเปลี่ยนผลลัพธ์พื้นฐานของuname/ uname -s จากLinuxเป็นอย่างอื่น (โดยพื้นฐานแล้วคือเปลี่ยนชื่อเคอร์เนล)

เขา / เธอจะทำอย่างไรในวิธีที่เหมาะสม (นั่นคือการเปลี่ยนแหล่งที่มา)

คำตอบ:


26

unameยูทิลิตี้ได้รับข้อมูลจากuname()ระบบโทร มันเติม struct เช่นนี้ (ดู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ได้)
สกอตต์

2
นี่ไม่เกี่ยวข้อง - คำถามที่ถามว่าจะเปลี่ยนแปลงสิ่งนี้ ดังนั้นใช่unameคำสั่งได้รับข้อมูลจากการเรียกระบบ และระบบโทรหาข้อมูลของมันอยู่ที่ไหน? (คำตอบจัดทำโดยผู้โพสต์อื่น ๆ ที่นี่: มันยากในเคอร์เนลในเวลารวบรวม)
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

@Gilles: สิ่งที่ไม่เกี่ยวข้อง? หากคำตอบคือ "จัดทำโดยผู้โพสต์อื่น ๆ ที่นี่: มันเป็นรหัสยากในเคอร์เนล ... " โปรดทราบฉันได้พูดในสิ่งเดียวกัน: "นี่มาโดยตรงจากเคอร์เนลที่รันอยู่ฉันจะถือว่าข้อมูลทั้งหมดนั้นยาก เข้ารหัสลงในมัน ... เนื่องจากมันเป็นโอเพนซอร์สคุณสามารถเปลี่ยนซอร์สโค้ดและคอมไพล์เคอร์เนลใหม่เพื่อใช้สิ่งที่ sysname ที่คุณต้องการมันไม่ใช่ตัวเลือก config
goldilocks

2
@goldilocks ทำไมจะmachineเปลี่ยน? มันอาจจะไม่ได้รับการ hardcoded ลงในเคอร์เนลเพราะมันอาจปรับให้เข้ากับฮาร์ดแวร์ แต่แน่นอนแล้วมันจะถูกตั้งค่าในเวลาบูตและจะไม่เปลี่ยนแปลงหลังจากนั้น แต่ไม่สามารถตั้งค่าต่อกระบวนการได้ (เช่นเพื่อรายงานi686ไปยังประมวลผลแบบ 32 บิตใน x86_64) โดยวิธีการที่releaseสามารถปรับแต่งต่อกระบวนการในระดับหนึ่ง (ลองsetarch i686 --uname-2.6 uname -a)
Gilles 'หยุดความชั่วร้าย'

1
@Gilles ผมได้แก้ไขmachine, nodenameและreleaseเป็นคำถามที่มีการอ้างอิงถึงการแสดงความคิดเห็น อีกครั้งคำถามไม่ได้เกี่ยวกับเขตข้อมูลเหล่านั้นทั้งหมด
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);

สตริงตัวเองอยู่ในรวม / สร้าง / compile.h:

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

และรวมอยู่ใน / สร้าง / 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 / {ชื่อโฮสต์, ชื่อโดเมน} ต่อไปนี้เป็นเนมสเปซ UTS:

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

นี่เป็นคำตอบที่ดีและสมบูรณ์ แต่อาจจะคุ้มค่าในขณะตอบคำถามของผู้โพสต์โดยตรง ฉันเชื่อว่านี่จะเป็นจำนวนเงิน - เปลี่ยนรายการที่เกี่ยวข้องในไฟล์ที่เกี่ยวข้องและคอมไพล์ใหม่ คุณเขียน "หรือเป็น #define ใน makefiles" คุณสามารถทำอย่างละเอียด?
Faheem Mitha

+1 unshareสำหรับ ยังไงก็เถอะฉันก็จะพลาดคำสั่งนี้จนถึงวันนี้ ขอบคุณ!
Tino

และinclude/generated/compile.hสร้างขึ้นโดยscripts/mkcompile_h: unix.stackexchange.com/a/485962/32558
Ciro Santilli 事件改造中心中心法轮功六四事件

8

ด้วยความช่วยเหลือของการอ้างอิงข้ามลินุกซ์และการกล่าวถึงคุณของ/proc/sys/kernel/ostypeผมติดตามostypeการรวม / Linux / sysctl.hregister_sysctl_tableที่แสดงความคิดเห็นว่าชื่อที่จะถูกเพิ่มโดยโทร

ดังนั้นที่เรียกว่ามาจากไหน? ที่เดียวคือkernel / utsname_sysctl.cซึ่งรวมถึง / linux / uts.hที่เราพบ:

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

ดังนั้นตามเอกสารของเคอร์เนล :

วิธีเดียวในการปรับค่าเหล่านี้คือสร้างเคอร์เนลใหม่

:-)


6

ตามที่แสดงความคิดเห็นไว้ที่อื่นข้อมูลนั้นมาพร้อมกับunamesyscall ซึ่งข้อมูลจะถูกกำหนดค่าตายตัวในเคอร์เนลที่กำลังทำงานอยู่

ส่วนรุ่นที่มีการตั้งค่าได้ตามปกติเมื่อรวบรวม kernel ใหม่โดย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_unamesyscall นั้นสร้างขึ้นโดยใช้มาโคร (ในลักษณะที่ค่อนข้างซับซ้อน) คุณสามารถเริ่มต้นจากที่นี่ หากคุณรู้สึกอยากผจญภัย

อาจเป็นวิธีที่ดีที่สุดในการเปลี่ยนแปลงข้อมูลดังกล่าวคือการเขียนโมดูลเคอร์เนลเพื่อแทนที่unamesyscall; ฉันไม่เคยทำแบบนั้น แต่คุณสามารถค้นหาข้อมูลในหน้านี้ได้ในหัวข้อ 4.2 (ขออภัยไม่มีลิงก์โดยตรง) โปรดสังเกตว่ารหัสนั้นอ้างถึงเคอร์เนลที่ค่อนข้างเก่า (ในขณะนี้เคอร์เนล Linux มีutsเนมสเปซไม่ว่ามันจะหมายถึงอะไร) ดังนั้นคุณจะต้องเปลี่ยนมันเป็นจำนวนมาก


ขอบคุณทุกคน ฉันรู้แล้วว่ามันมีบางอย่างเกี่ยวข้องกับ uname อย่างไรก็ตามสิ่งที่ฉันไม่สามารถเข้าใจได้คือสิ่งที่และภายในที่มาของสตริงที่กำหนด "Linux" ทั้งหมดที่ฉันรู้คือที่ที่ฉันสามารถค้นหาข้อมูลระหว่างรันไทม์ (มันมีอยู่ภายใน / proc / sys / kernel / ostype) การค้นหาว่าเคอร์เนลรู้ตัวเองว่าชื่อที่ถูกต้องจะเป็นหนึ่งในสิ่งที่น่าสนใจมากกว่านี้ได้ไหม
user237251

@ user237251 มีคำว่า "Linux" ปรากฏกี่อินสแตนซ์ในเคอร์เนลซอร์สในบริบทสตริง? หากยังไม่มากนักคุณสามารถตรวจสอบผลลัพธ์ของการค้นหาที่เป็นข้อความและดูว่าอะไรที่ทำให้คุณ
JAB

@JAB มีจำนวนมากเกินไป โชคดีที่มีคนใน kernelnewbies.org ช่วยฉันแก้ปัญหา "ความลึกลับ" Linux ได้รับชื่อ sys จาก /include/Linux/uts.h ดูที่นี่: lxr.free-electrons.com/source/include/linux/uts.h?v=3.10
237251

2

แม้ว่าฉันจะไม่พบสิ่งใดในแหล่งที่มาเพื่อระบุสิ่งนี้ แต่ฉันเชื่อว่ามันใช้ syscall แบบ uname

man 2 uname

ควรบอกคุณเพิ่มเติมเกี่ยวกับเรื่องนี้ ถ้าเป็นกรณีนั้นมันจะได้รับข้อมูลโดยตรงจากเคอร์เนลและการเปลี่ยนแปลงมันอาจจะต้องมีการคอมไพล์ใหม่

คุณสามารถเปลี่ยนไบนารีเพื่อให้คุณยกเลิกการทำสิ่งที่คุณต้องการได้เพียงแค่เขียนมันด้วยโปรแกรม w / e ที่คุณต้องการ ข้อเสียของสคริปต์บางตัวก็ขึ้นอยู่กับผลลัพธ์นั้น


3
หากคุณทำเช่นstrace unameนั้นจะเป็นการยืนยันว่ามีการunameใช้การเรียกระบบ
แกรม

1

วิธีที่เหมาะสมในการเปลี่ยนชื่อจะเป็นการเปลี่ยนหัวคอมไพล์และคอมไพล์อีกครั้งตามที่คนอื่นแนะนำ แต่ฉันไม่แน่ใจว่าทำไมคุณถึงต้องการที่จะผ่านปัญหามากมายเมื่อคุณสามารถทำอะไรบางอย่างเช่น

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

หรือแม้กระทั่ง

alias uname 'echo whatever'

0

คำตอบของRmanoช่วยให้ฉันได้ส่วนหนึ่ง แต่เวทมนตร์ที่แท้จริงนั้นค้นพบได้ง่ายขึ้นโดยการส่งQ=ตัวเลือกในmakecommandline ของคุณในไดเรกทอรีซอร์สเคอร์เนล 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

สิ่งนี้แสดงให้ฉันเห็นว่าถ้าฉันต้องการสร้างโมดูลเคอร์เนลเพื่อทำงานกับเคอร์เนลที่กำลังรันอยู่ฉันกำลังปล่อยแท็กที่ไม่ถูกต้องและยอมรับผิด ฉันต้องแก้ไขและสร้างอย่างน้อย DTBs ( make dtbs) เพื่อสร้างไฟล์ที่สร้างขึ้นด้วยหมายเลขเวอร์ชั่นที่ถูกต้อง


ปรากฎว่ายังไม่เพียงพอ ฉันต้องเปลี่ยนscripts/setlocalversionเป็นสิ่งที่ทำได้ง่าย:

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

จากนั้นสร้างไฟล์ที่สร้างอัตโนมัติใหม่:

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

จากนั้นฉันสามารถสร้างไดร์เวอร์ตัวอย่างของ Derek Molloy และสามารถทำได้insmodสำเร็จ เห็นได้ชัดว่าคำเตือนเกี่ยวกับการModule.symversไม่อยู่ไม่สำคัญ Linux ทั้งหมดใช้เพื่อพิจารณาว่าโมดูลจะทำงานเป็นสตริง localversion นั้นหรือไม่


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://stackoverflow.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.