HP/HPE公司的*nix操作系统

HP/HPE公司(即通常说的惠普公司,因其在2015年已经拆分成HPHPE两家独立运营公司,且拆分后是由HPE延续操作系统的相关工作,所以在这里使用HP/HPE。)拥有自己的Unix操作系统:HP-UX。以前中国是有团队参与HP-UX的相关工作:功能开发,Unix认证等等,现在相应的工作应该都转到印度了。目前HP-UX应该在一些银行,电信系统还在使用,不过的确是很难见到了。可以通过Wikipedia来了解HP-UX的一些信息。

再来说一下Linux,其实以前HP/HPE公司有一个很大的Linux团队,其甚至有能力做出自己的Linux发行版:

img_20161123_140305_hdr

此外,这个团队也曾经是Linux kernel的一个很重要的贡献者。不过,随着这些年公司的战略调整,这个团队的绝大部分工程师都已经离开了,其中的很多人加盟了其它公司,继续为Linux贡献着力量。目前HP/HPELinux上的工作重心侧重在同Linux厂商的合作,譬如今年与SuSE的合作(详情请参考Sweet SUSE! HPE snags itself a Linux distro)。

strace命令介绍

straceLinux上的一个很好用的工具,它可以用来输出程序在运行过程中发生的系统调用以及收到的信号的相关信息,因此在调试和诊断问题时有很大的帮助,特别是在程序没有源码,或是在前期做一些粗略的分析时。strace命令格式如下:

strace [options] command [args]

举个例子:

# strace sleep 300
execve("/usr/bin/sleep", ["sleep", "300"], [/* 24 vars */]) = 0
brk(0)                                  = 0x22fa000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70d1ef8000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
......
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=20243, si_uid=0} ---
......

从上面例子可以看出,对于系统调用,比如openaccessstrace都会输出详细的参数和返回值,如果发生了错误,也会输出细致的错误信息。而对于接收到的信号,除了输出信息外,还要注意信号信息的前后都加了“---”,以示与系统调用的区别。

以下是一些常用的选项:
(1)-o:把strace执行结果输出到指定文件里:

# strace -o out ls

(2)-t:打印时间:

# strace -t ls
10:30:07 execve("/usr/bin/ls", ["ls"], [/* 24 vars */]) = 0
10:30:07 brk(0)
......

(3)-e:只关注某一系统调用:

# strace -e open ls
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
......

(4)-y:显示和文件描述符关联的文件路径:

# strace -y ls
......
fstat(3</etc/ld.so.cache>, {st_mode=S_IFREG|0644, st_size=32951, ...}) = 0
mmap(NULL, 32951, PROT_READ, MAP_PRIVATE, 3</etc/ld.so.cache>, 0) = 0x7fba3db13000
close(3</etc/ld.so.cache>)              = 0
......

(5)-f:追踪运行进程所生成的子进程。

参考资料:
strace(1) – Linux man page
A swiss army knife of debugging tools

inode,“hard link”和“symbol link”

*nix文件系统上,每个文件的存储实际可以看成包含两部分:inode和实际存储文件内容的数据块。其中inode存储文件的metadata,包含创建时间,访问权限,等等,当然还有指向文件具体数据块的指针。正是通过这个指针,将indoe和数据块关联起来。

要注意,inode中并不保存文件的名字。关于文件名字和inode的映射存储在目录文件中。因此,当访问一个文件时,其实是通过这个文件所在的目录文件访问到这个文件的inode信息,继而进行文件操作的。

接下来,看一下hard linksymbol linkinode之间的关系。首先创建一个文件和指向这个文件的hard linksymbol link

# echo 'Hello, World!' > myfile.txt
# ln myfile.txt my-hard-link
# ln -s myfile.txt my-soft-link

查看这3个文件的inode信息:

# ls -ailt my*
325332 lrwxr-xr-x  1 root  wheel  10 Oct 24 05:26 my-soft-link -> myfile.txt
325331 -rw-r--r--  2 root  wheel  14 Oct 24 05:25 my-hard-link
325331 -rw-r--r--  2 root  wheel  14 Oct 24 05:25 myfile.txt

可以看到myfile.txtmy-hard-link其实对应的的是同一个inode节点:325331,而my-soft-link对应的是另一个inode节点:325332。接下来删除myfile.txt,然后分别读取my-hard-linkmy-soft-link文件内容:

# rm myfile.txt
# ls -ailt my*
325332 lrwxr-xr-x  1 root  wheel  10 Oct 24 05:26 my-soft-link -> myfile.txt
325331 -rw-r--r--  1 root  wheel  14 Oct 24 05:25 my-hard-link
# cat my-hard-link
Hello, World!
# cat my-soft-link
cat: my-soft-link: No such file or directory

可以看到,因为my-hard-linkmyfile.txt对应相同的inode节点:325331,因此删除myfile.txt后,仍然可以通过my-hard-link读取325331这个inode节点所对应的文件内容。而my-soft-link仅仅是指向myfile.txt这个文件名字,因此一旦myfile.txt被删除,也就无法读取文件内容了。

参考资料:
Inodes – an Introduction
What is the difference between a symbolic link and a hard link?

进程的priority和nice

本文选自Difference between nice value and priority in the top output,以Linux系统为例讲解进程的prioritynice
(1)

The difference is that PR is a real priority of a process at the moment inside of the kernel and NI is just a hint for the kernel what the priority the process should have.

Priority反映当时进程真正的优先级,而nice则是告诉kernel进程应该获得什么样的优先级。

(2)Nice的值从-2019-20表示优先级最高。通常情况下,priority = nice + 20,也就是priority的值为0~39。但是上述理论仅仅适用于调度策略是SHED_OTHER的进程,此外,kernel也有可能只改变priority的值,而nice的值保持不变,因此上述等式同样不适用。

Unix中的zombie进程和orphan进程

Unix中子进程退出后,如果父进程没有使用wait()函数获得子进程的退出状态,则子进程的相关信息仍然会在系统的进程表里占用一席之地,这时的子进程称之为zombie进程。如果父进程先于子进程退出,这时的子进程称之为orphan进程,而init进程则会变成orphan进程的父进程。init进程会定期处理父进程是initzombie进程。

参考资料:
Zombie process
Zombie process vs Orphan process

Linux系统中locale相关的笔记

 下列笔记摘自The Linux programming interface

(1)

The actual locales that are defined on a system can vary. SUSv3 doesn’t make any requirements about this, except that a standard locale called POSIX (and synonymously, C, a name that exists for historical reasons) must be defined. This locale mirrors the historical behavior of UNIX systems. Thus, it is based on an ASCII character set, and uses English for names of days and months, and for yes/no responses. The monetary and numeric components of this locale are undefined.

The locale command displays information about the current locale environment (within the shell). The command locale –a lists the full set of locales defined on the system.

(2)

There are two different methods of setting the locale using setlocale(). The locale argument may be a string specifying one of the locales defined on the system (i.e., the name of one of the subdirectories under /usr/lib/locale), such as de_DE or en_US. Alternatively, locale may be specified as an empty string, meaning that locale settings should be taken from environment variables:

setlocale(LC_ALL, “”);

We must make this call in order for a program to be cognizant of the locale environment variables. If the call is omitted, these environment variables will have no effect on the program.

以下摘自stackoverflow.com

A C program inherits its locale environment variables when it starts up. This happens automatically. However, these variables do not automatically control the locale used by the library functions, because ISO C says that all programs start by default in the standard ‘C’ locale.

FreeBSD中的sysctl函数

FreeBSDsysctl家族的函数定义:

#include <sys/types.h>
 #include <sys/sysctl.h>

 int
 sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
 const void *newp, size_t newlen);

 int
 sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
 const void *newp, size_t newlen);

 int
 sysctlnametomib(const char *name, int *mibp, size_t *sizep);

sysctl函数参数中,namenamelen用来表明内核参数IDoldpoldlenp用来存储当前内核参数的值;而newpnewlen则用来设置新的内核参数值。如果不需要的话,可以把相应的值置成NULL
看一下sysctlbyname的实现:

int
sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
    const void *newp, size_t newlen)
{
    int real_oid[CTL_MAXNAME+2];
    size_t oidlen;

    oidlen = sizeof(real_oid) / sizeof(int);
    if (sysctlnametomib(name, real_oid, &oidlen) < 0)
        return (-1);
    return (sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen));
}

可以看到,sysctlbyname首先通过sysctlnametomib获得真正的ID,接着调用sysctl完成想要的工作。

参考资料:
SYSCTL(3)
Grokking SYSCTL and the Art of Smashing Kernel Variables

Sed基础知识

以下内容摘自sed-awk-101-hacks-ebook
Sed语法:

sed [options] {sed-commands} {input-file}
或
sed [options] -f {sed-commands-in-a-file} {input-file}

Sed命令执行流程: 读取一行到一个临时缓存区,然后对这个缓存区执行相应的命令,并输出缓存区的内容,接下来清空缓存区,读取下一行。

Capture

Sed不会修改原始文件,并且总是输出到stdout,因此通常要使用-n选项来禁止自动输出默认的pattern space。举例如下:

# cat employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
# sed '2 p' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
# sed -n '2 p' employee.txt
102,Jason Smith,IT Manager

如果想保存sed命令的输出,可以把这些输出重定向到某个文件:>filename

 

uptime命令简介

uptime命令用来显示系统已经运行的时间:

# uptime
 19:05:33 up  3:16,  2 users,  load average: 0.00, 0.01, 0.05

19:05:33是当前系统时间,up 3:16是系统已经运行了3小时16分。后面还有用户和系统load信息。如果只关心系统运行了多次时间,可以使用下列命令:

# uptime -p
up 3 hours, 16 minutes

uptime命令得到系统运行时间是通过读取/proc/uptime文件:

# cat /proc/uptime
11984.78 95454.77

第一个字段是系统启动的秒数,第二个字段是系统每个CPU core处在idle状态的时间总和。