'Domain'에 해당되는 글 103건

  1. 2017.03.08 [Ubuntu/Linux] Python zip library 와 7z 간 교차 사용시 문제
  2. 2016.04.20 Run commands with synchronization in shell.
  3. 2016.04.20 Linux re-parenting. And child-subreaper.
  4. 2016.03.04 [Ninja] Feature of build-tool : Implicit dependency to input '.ninja' file
  5. 2016.01.26 [Essay] 생산성 향상에 따른 부정적인 경험, 그리고 반발.
  6. 2015.11.11 [Linux] Environment variable - more
  7. 2015.10.19 [Android] Build goldfish kernel with NDK toolchain.
  8. 2015.03.19 [GNUMake] GNUMake variable expansion - dependency section
  9. 2015.03.19 [GNUMake] 'shell' function
  10. 2015.03.09 [Linux/Ext4] Order of file list of the directory in ext4

[Ubuntu/Linux] Python zip library 와 7z 간 교차 사용시 문제

Domain/Linux 2017.03.08 22:08

[ ZIP extended data descriptor and signature issue at Python zipfile library. (Python 2.7.12) ]

Zip format spec을 보면, extended data descriptor쪽이 불명확하게 되어 있다

원칙적이로는 다음과 같은 format을 따른다.(참고: http://www.pkware.com/documents/casestudies/APPNOTE.TXT)

 4.3.9  Data descriptor:

        crc-32                          4 bytes
        compressed size                 4 bytes
        uncompressed size               4 bytes

문제는, De-facto standard로 아래와 같이 정의되는 경우가 대부분이라는 것이다. (http://www.onicos.com/staff/iz/formats/zip.html)

Extended local header:
Offset   Length   Contents
  0      4 bytes  Extended Local file header signature (0x08074b50)
  4      4 bytes  CRC-32
  8      4 bytes  Compressed size
 12      4 bytes  Uncompressed size

[ 7z - 16.02 버젼 ]

CPP/7zip/Archive/Zip/ZipIn.cpp: CInArchive::ReadLocalItemAfterCdItemFull()

    if (item.HasDescriptor())   // <= 0x8 bit of general purpose flag, is set
      // pkzip's version without descriptor is not supported
      RINOK(Seek(ArcInfo.Base + item.GetDataPosition() + item.PackSize));
      if (ReadUInt32() != NSignature::kDataDescriptor)
        return S_FALSE;

와 같이 De-facto standard를 따르고 있다.

[ Python zipfile library ]

zipfile.ZipFile 의 write 혹은 writestr 함수를 보면

< writestr 함수 >
        if zinfo.flag_bits & 0x08:
            # Write CRC and file sizes after the file data
            fmt = '<LQQ' if zip64 else '<LLL'
            self.fp.write(struct.pack(fmt, zinfo.CRC, zinfo.compress_size,

와 같이 signature가 빠져 있다. 즉 standard를 따른다!

[ 누구의 잘못인가? ]

AppNote(http://www.pkware.com/documents/casestudies/APPNOTE.TXT)는 아래와 같이 말하고 있다.

      Although not originally assigned a signature, the value
      0x08074b50 has commonly been adopted as a signature value
      for the data descriptor record.  Implementers should be
      aware that ZIP files may be encountered with or without this
      signature marking data descriptors and should account for
      either case when reading ZIP files to ensure compatibility.
      When writing ZIP files, it is recommended to include the
      signature value marking the data descriptor record.  When
      the signature is used, the fields currently defined for
      the data descriptor record will immediately follow the
즉, 원칙적으로는 7z 이 양쪽의 경우를 다 지원하도록 확장되는게 맞는것 같다.
다만 python의 zipfile library역시 recommendation을 따르는게 좋을 것 같으나... 그럴 기미가 안보인다. (Python3.5.2 에서도 zipfile library는 여전히 순수 표준을 따른다.)

[ 언제 문제가 되는가? ]

extended data descriptor를 사용하는 걸로 set된 zip file을 python library로 update할 경우, 혹은 python library로 extended data descriptor를 사용해서 zip을 생성할 경우, 이렇게 생성된 zip file은 다른 popular한 tool에서 사용할 수 없을 수도 있다.
    7z 의 경우, 'x'(extract)는 잘 되나, 'u'(update)에서는 'E_NOTIMPL' System ERROR가 발생한다.
    'zip'(pkzip)의 경우 양쪽 모두 잘 지원한다. 다만... 다른 bug가...(>4G => <4G => >4G 버그?)

또한 7z의 경우, 내부적으로 병렬로 pkzip을 수행하는 것으로 보인다.

$ time 7z ...

의 command로 확인해보면, 바로 알 수 있다. 또한 속도도 빠르다!

Trackback 0 : Comment 0

Run commands with synchronization in shell.

Domain/Linux 2016.04.20 22:43
Environment : Ubuntu 14.04
Tools : sem, flock(recommend)

> $ cat a.sh

for i in {1..7}; do

for i in {1..10}; do
    echo $str >> out                   # (*a)
#    sem "echo $str >> out"            # (*b)
#    flock out -c "echo $str >> out"   # (*c)

> $ cat runa
for i in {1..10}; do

> $ cat runa2

for i in {1..10}; do

> $ ./runa2

$ cat parout | uniq | wc -l
if 1 => OK, otherwise not-syncronized!!

(*a) ==> race condition!! :
(*c) sem ==> error!(sem bug!!)
(*b) flock ==> OK

Trackback 0 : Comment 0

Linux re-parenting. And child-subreaper.

Domain/Linux 2016.04.20 22:38
[ related information ]
* prctl
* See linux kerne for details ("kernel/exit.c : find_new_reaper())

------ commit(kernel/git/torvalds/linux.git) -----

author	  Lennart Poettering <lennart@poettering.net>    2012-03-23 22:01:54 (GMT)
committer Linus Torvalds <torvalds@linux-foundation.org> 2012-03-23 23:58:32 (GMT)
commit	  ebec18a6d3aa1e7d84aab16225e87fd25170ec2b (patch)

[ test code ]

$ cat b.sh
function echosleep2 {
    sleep 10
    echo 'sleep2 end'

function echosleep {
    sleep 5
    echo 'sleep end'

echo "hello: $BASHPID $$"
sleep 2
echo end


 3241  2573  3241  3241 init --user
 4392  3241  3374  3374 gnome-terminal
 9882  4392  9882  9882 bash

[ < 2 seconds ]

33513  9882 33513  9882 bash            # ./b.sh (*a)
33514 33513 33513  9882 bash            # ./b.sh:echosleep() (*b)
33515 33513 33513  9882 sleep 2
33516 33514 33513  9882 bash            # ./b.sh:echosleep():echosleep2() (*c)
33517 33514 33513  9882 sleep 5
33518 33516 33513  9882 sleep 10
33519 15742 33519 15742 ps -e -o pid,ppid,pgid,sid,cmd

(*a): Bash terminal executed 'b.sh' as new process group leader.
      All child/grandchild processes are executed in the same process group.

[ < 5 seconds ]

33514  3241 33513  9882 bash            # ./b.sh:echosleep() (*b)
33516 33514 33513  9882 bash            # ./b.sh:echosleep():echosleep2() (*c)
33517 33514 33513  9882 sleep 5
33518 33516 33513  9882 sleep 10
33520 15742 33520 15742 ps -e -o pid,ppid,pgid,sid,cmd

(*b): Process group leader(*a) is disappeared.
      And there is no threads in this process.
      (If there is other threads in this process, it will become new reaper)
      So, it is re-parented to orphan-reaper("init --user").

[ < 10 seconds ]

33516  3241 33513  9882 bash            # ./b.sh:echosleep():echosleep2() (*c)
33518 33516 33513  9882 sleep 10
33522 15742 33522 15742 ps -e -o pid,ppid,pgid,sid,cmd

(*c): Same with above(*b).

[ > 10 seconds ]

33524 15742 33524 15742 ps -e -o pid,ppid,pgid,sid,cmd


Sample code to get every SIGCHLD from descendents.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <errno.h>

void handle_signal(int signal) {
        pid_t pid;
        printf("Handler SIGCHLD: %d\n", signal);
        if (0 > (pid = wait(NULL))) {
		printf("Wait fails: errno: %s", strerror(errno));
	} else {
		printf("Wait done: %d\n", pid);

int main() {
        struct sigaction sa;
	pid_t pid;

        // Print pid, so that we can send signals from other shells
        printf("My pid is: %d\n", getpid());

        // Setup the sighub handler
        sa.sa_handler = &handle_signal;

        // Intercept SIGHUP and SIGINT
        if (sigaction(SIGCHLD, &sa, NULL) == -1) {
                perror("Error: cannot handle SIGCHLD"); // Should not happen

        if (0 > prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) {
                perror("Error: prctl");

	pid = fork();
	if (pid) {
		int secs = 10;
		// parent
		printf("\nSleeping for 10 second\n");
		while (secs > 0)
			secs = sleep(10);
		printf("Parent DONE\n");
	} else {
		// child
		if (0 > execlp("bash", "bash", "b.sh", NULL)) {
			printf("execl fails: %s\n", strerror(errno));

Trackback 0 : Comment 0

[Ninja] Feature of build-tool : Implicit dependency to input '.ninja' file

Domain/Android 2016.03.04 21:41

'Ninja' has implicit dependency on input '.ninja' file.

Let's thing about following example.

< build.ninja >

rule hello

     command = echo ${msg}

build aaaa: hello

      msg = aaaa

build build.ninja: hello

      msg = build.ninja


$ ninja yyyyyyy

[1/1] echo build.ninja


ninja: error: unknown target 'yyyyyyy'


Ninja try to build input '.ninja' file if rule for the '.ninja' is defined.

And then Ninja try to build given target.

Trackback 1 : Comment 0

[Essay] 생산성 향상에 따른 부정적인 경험, 그리고 반발.

Domain/Software 2016.01.26 22:57

Software개발이란, 사람의 편의를 도와주는 도구를 만드는 것과 밀접한 관련이 있다.

그리고, 이런 류의 도구들은 생산성 향상을 가져온다.

SW 엔지니어의 경우, 특히나, 수많은 소위 'Manual'한 작업들을 SW개발을 통해서 'Automation'을 하는 과정을 중요시 한다.

왜냐하면, 단순한 작업을 최소화함으로서 더 많은 시간을 '창조적인 작업'에 사용하길 원하기 때문이다.

그러나, 국내에서는 SW개발을 '창조적인 작업'으로 생각하지 않는 곳이 많다.

(여기에 대한 논란은 접어두자. 국내에서, SI와 Game쪽을 제외하고 SW가, 수익의 중심에 있는 산업은 거의 전무하다. Portal쪽은 '업계'라고 표현하기 어렵다. 대표적인 기업 2개 정도만 존재하니...)

그러다보니, 자동화나 Tool 등을 통해 기존 업무의 생산성을 향상시키면 (예를 들어, 기존 10여명이 필요한 일을 1~2명이 할 수 있게 했다면) 당해년도, 그러니까, 생산성을 향상시킨 그 해에는 좋은 평가를 받을 수 있게 되나, 그 이후에는 나머지 사람들은 소위 '할일이 없게' 된다.

즉, 다시 무언가 성과를 낼 새로운 일을 찾지 못하면, 그 이후 부터는, '나쁜' 평가를 받게 된다.

그리고, 대부분의 경우, 새로운 일을 찾는 것은 상당히 어렵기 때문에, 여유있는 사람들은, 그때 당시 업무가 과중하게 몰리는 다른 부서 혹은 분야 쪽을 투입되는 경우가 많다. 그렇게 되면, 업무가 바뀌게 되면, 대부분의 사람들이 그렇듯이, 그 사람은 새로운 환경 그리고 업무 domain에 적응해야 하고, 초반 상당기간은 '좋은 성과'를 보여주기 힘들다.

예를 들어, 대략 정리해 보자.

- 10여명의 SW 엔지니어로 구성된 team이 있다.

- 해당 team은 반복적이고 routine한 업무를 지속적으로 수행하고 있고, 이 업무는 회사내에 필수적이며, 10여명이 꾸준히 해 나가야 하는 일이다.

- 이 업무는 Automation이나, 기타 방법으로 생산성을 향상시키기가 상당히 어렵다.

Case A: 해당 업무를 지속한다. 약간씩의 improvement는 꾸준히 진행한다.

- 기본적으로 필요한 일을 지속하고 있으므로, '좋은 실적'을 보여준다고 말할 수는 없어도 '나쁜 실적'을 보여주지도 않는다. 그냥 '평이한' 평가를 일정기간 계속해서 받을 가능성이 높다.

- 해당 일에 대한 생산성 향상이 상당히 어렵다는 것이 이미 알려진 사실이므로, 약간씩의 improvement를 통해 추가적인 실적을 보여주면서 '좋은 평가'를 노려 볼수 있다.

- 해당 team은, 이미 익숙한 사람/동료/업무 환경속에서 생활하므로 관련 스트레스도 크지 않다.

- 업무에 대한 비젼이 약하므로, 이 부분에 불만이 생길 여지가 있다.

Case B: 창의적인 생각과 노력으로 생산성 향상에 성공한 경우 (필요 인력: 10여명 -> 1~2명)

- 해당 년도에 '좋은 성과'를 받을 가능성이 높다.

- 이후, 8~9 명은 당장 인력이 부족한 팀/업무 쪽으로 재배치되고, 나머지 1~2명 역시 다른 팀으로 이동될 가능성이 높다.(1~2명이 독립적인 팀으로 유지될 수는 없다.)

- 1~2 명은 생산성 향상을 가져온 새로운 환경에서, 창조적인 생각/업무 를 할 수 있는 여력이 없이 빠듯하게 기존 업무를 계속해서 수행해 나갈 것이다.

- 재배치된 8~9명은 새로운 환경/업무에 적응하면서 초반에는 '좋지 못한' 평가를 받을 가능성이 높다.

Case B 의 경우, 해당 팀의 leader는 좋은 평가와 함께, 이후에도 더 좋은 기회를 얻게 될 가능성이 있다. 그렇지만, 팀원들은 어떤가?

B의 경우를 경험해 본 사람은, 다시 이와 비슷한 상황에서, 생산성 향상/자동화 등에 강한 거부감을 가지게 된다.

(나는 실제, 이런 상황을 경험해 보았고, 대부분의 팀원은 앞서 말한대로, 이후 생산성 향상/자동화 등에 거부감을 가지게 되었다.)

생산성을 향상시키기 위한 업무에 성공한 팀/사람 이 긍적적인 결과를 경험했을때, 이후 같은 상황에서도 이를 위해 노력할 것이다. 그런데, 과연 우리 주변의 환경은 어떤가?

내가 보기에는 그리 긍정적이지 않아 보인다...

Trackback 0 : Comment 0

[Linux] Environment variable - more

Domain/Linux 2015.11.11 22:45

Linux Kernel 3.10을 기준으로 보면,

Maximum number of environment variable in Linux : 0x7fffffff

Maximum string length of environment variable and argument: PAGE_SIZE * 32 (4K page의 경우 128K)

헛갈리기 쉬운 것 (용어를 명확하게 사용하고 있지 않은 것들.)

"environment variable" vs "shell variable"


Bash 기준으로 보면


export var=hello  # This is environment variable

var=hello   # This is shell variable.

즉, environment variable 이란 descendent process들에게 영향을 미치는 '환경'을 의미한다. Current process에서만 유효한 것은 environment variable이라 부를 수 없다.

추가적으로, '$ env' command를 수행할 때 나오는 값들 역시 environment variable만 나오고 shell variable은 나오지 않는다.

Trackback 0 : Comment 0

[Android] Build goldfish kernel with NDK toolchain.

Domain/Android 2015.10.19 23:15

Here is the way to compile x86 goldfish and run on emulator

* AOSP Marshmallow + Goldfish 3.4

* ARCH=x86 (You don't need to set SUBARCH)

* Compiler version : gcc-4.8 (prebuilt x86 compiler from Android NDK)

  (Set CROSS_COMPILE environment variable)

$ make ARCH=x86 CC="${CROSS_COMPILE}gcc -mno-android" goldfish_defconfig

$ make ARCH=x86 CC="${CROSS_COMPILE}gcc -mno-android" -j40

And use 'arch/x86/boot/bzImage' as 'kernel-qemu' image

Please note that you SHOULD use '-mno-android' option to build linux kernel with NDK toolchains.
The reason is, '-mandroid' option is enabled by default at GCC in NDK(file name is something like *-*-android*)
Remember that NDK toolchain is used to build native executable or libraries run on Android devices.
And, in general, build environment of linux kernel is 'GCC' + 'GLIBC'.
(Note that, linux kernel binary even if it runs on Android device, it doesn't have any dependency on Android platform(ex. bionic or libc))
So, to build linux kernel, '-mandroid' option should be disabled by using '-mno-android' option.

Trackback 0 : Comment 0

[GNUMake] GNUMake variable expansion - dependency section

Domain/Software 2015.03.19 21:51


general_var:= my-value

target: dep1 dep2

    <do something> $(general_var)

위의 makefile이 단독으로 사용되는 경우는, 전혀 문제가 되지 않는다. 그렇지만, makefile이 서로 서로 include되는 등의 복잡한 system에서는

경우에 따라, 위의 makefile이 parsing된 이후, general_var 의 값이 다른 값으로 바뀌게 될 수도 있다.(include된 다른 make file에서...)

이럴 경우, 'target'의 command section이 수행될 때는 'general_var'가 이미 다른 값으로 치환된 이후이기 때문에, 기대와 다른 동작을 하게 될 수 있다.

('blog의 variable expansion at command section on GNUMake 참조)

이것을 막기 위해서는 아래와 같은 형태로 make file을 구성해야 한다. 


general_var:= my-value

target: private_var := $(general_var)

target: dep1 dep2

    <do something> $(private_var)

위의 makefile은, makefile이 parsing되고 target을 만들기 위한 rule이 수행되기 전에 아래와 같은 상태가 된다.


general_var:= my-value

target: private_var := my-value

target: dep1 dep2

    <do something> $(private_var)

따라서, target 의 command section이 수행되기 전에, dependency section이 수행되면서 private_var값이 my-value로 set 되고

target 의 command section은 기대했던 'my-value' 값을 가지고 수행된다.

단, 아래와 같은 syntax는 "*** commands commence before first target.  Stop." error를 발생시키니 주의해야 한다.

(즉 dependency section에서 variable assignment를 수행할 경우, command section과 함께 있으면 안된다.) 

general_var:= my-value

target: private_var := my-value

    <do something> $(private_var)

Trackback 0 : Comment 0

[GNUMake] 'shell' function

Domain/Software 2015.03.19 21:51


$(shell echo hello) # <--- (*A)


    echo all

above make file gives following results.


Makefile:1: *** missing separator.  Stop.

error is issued.

But, we can resolve this error by changing line (*A) into below line.

dummy := $(shell echo hello)


$(shell echo)

What is root cause of this?

Let's see source code of 'func_shell' function in GNUMake-v4.0.




      child_execute_job (FD_STDIN, pipedes[1], errfd, command_argv, envp); <= stdout을 pipe로 redirecdtion


          EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i)); <= pipe를 읽음


          /* The child finished normally.  Replace all newlines in its output

             with spaces, and put that in the variable output buffer.  */

          fold_newlines (buffer, &i, trim_newlines);

          o = variable_buffer_output (o, buffer, i);    <= buffer값(pipe값 -> child의 stdout값)을 variable_buffer에 저장. 



That is, 'shell' function stores it's result(stdout) into variable_buffer.

variable_buffer is buffer that is used to store result of variable-expandsion.

What does this mean?

See below samples.


$(shell echo hello) <= (*1)



$(temp) <= (*2)

Above analysis means, (*1) and (*2) is same expression in gnumake's point of view.

Actually, above rules are same on all other functions in gnumake.

But, most function gives empty string - that is, it doesn't write string value to stdout.

So, it doesn't write anything into variable_buffer. That's reason why above issues are not shown at other functions.

And, in gnumake's point of view, 'function' and 'variable' is same in concept.

So, we can say that 'function' is just special variable that can get arguments - a kind of 'predefined variable'.

Therefore, we should use same concept for 'variable' and 'function' to understand gnumake.

Trackback 0 : Comment 0

[Linux/Ext4] Order of file list of the directory in ext4

Domain/Linux 2015.03.09 22:23

ext4에서 'readdir' system call을 이용해서 directory를 읽으면, directory가 가지는 file list를 읽을 수 있다.

이때, 읽히는 file의 순서는 어떻게 정해지는가?

경험적으로 대부분의 개발자라면, 이 순서가 일정하지 않다는 것을 알고 있을 것이다.

이 부분에 대해서 좀더 깊게 살펴보기도 하자.

linux kernel에서 ext4 관련 부분의 코드를 분석해 보면 아래의 사실들을 알아 낼 수 있다.

- ext4는 directory내에서 file search등을 빠르게 하기 위해서 htree(hash tree)를 이용한다.

- 이때 사용되는 hash값의 order가 곧 readdir 로 읽어들이는 file의 order이다.

- hash 값은 'HashFunc(<hash algorithm>, <hash seed>, <file name>)"을 통해서 구한다.

- hash algorithm과 hash seed의 경우, super block에 적힌 값을 사용하면, 없는 경우 default 값을 사용한다.

- directory내의 각 file의 hash값은 directory file의 'f_pos'값 (file position값)으로 사용된다.

즉, super block에 적힌 hash algorithm과 hash seed에 따라서, directory가 같은 이름들의 file을 가지고 있다고 하더라도, readdir이 읽어 오는 file의 순서가 달라진다는 말이다.

실제로 이를 확인하기 위해서는 'dumpe2fs' 와 'debugfs' tool을 사용할 수 있다.

Assumption : '/' 가 '/dev/sda1' 에 mount 되어 있음.

>$ sudo dumpe2fs -h /dev/sda1
Default directory hash:   half_md4     <== hash algorithm
Directory Hash Seed:      5841608b-14fe-405e-8d28-76236cc8c496  <== seed (UUID format)

이후 아래와 같은 방법으로 각 file name에 해당하는 hash 값을 알 수 있다.

>$ sudo debugfs /dev/sda1
dx_hash -h half_md4 -s c773a461-6150-4fe8-abe8-96acc6086d7e vmlinuz
Hash of /vmlinuz is 0xf097024e (minor 0x0)
추가적으로 'ls -f' 를 사용하면, sorting되지 않은 순서로 file list를 읽을 수 있는데, 이 순서가 바로, hash 값에 따른 순서 즉 readdir로 읽어 들이는 순서이다.
이를 확인하기 위해서는
>$ rm dxhashs; for e in $(ls -f /); do echo "dx_hash -h half_md4 -s 5841608b-14fe-405e-8d28-76236cc8c496 $e" >> dxhashs; done; sudo debugfs -f dxhashs /dev/sda1 | grep "Hash of" | cut -d' ' -f5

와 같이 하면, 정확하게 ascending order로 출력되는 hash 값을 볼 수 있다.
즉 'ls -f' 를 통해서 보여지는 file name의 순서가 hash값이 ascending order라는 뜻이고, hash 값이 ascending order에 따라 읽어 들이는 file name의 순서가 'readdir'로 읽어 들이는 순서와 일치한다.

Trackback 1 : Comment 0