I'm Bramante,

a Software Engineer

from Hsinchu City

about me

Happy Coding !!

recent public projects

Status updating…

found on

GNU Make Print Commands Before Executing

- - | Comments

複雜的大型程式有時很難搞清楚它們是怎麼被build出來的, 如果我們能看到GNU Make在執行Makefile時做了些什麼, 那麼狀況就會變得很清楚.

另外, 像是Android.mk, 最終負責執行它的內容的程式, 其實也是GNU Make, 所以如果我們能看到GNU Make執行了哪些command, 那我們就可以知道在build Android時, Android到底用了哪些特別的compiler flag.

我改了一版GNU Make來取得make執行了哪些command的資訊, build code的方法如下:

Terminal
1
2
3
4
bramante@matrix:~$ git clone https://github.com/Bramante/debugging-tools.git
bramante@matrix:~$ cd debugging-tools/make-3.81/
bramante@matrix:~/debugging-tools/make-3.81$ ./configure
bramante@matrix:~/debugging-tools/make-3.81$ make

我改動的code其實就只有下面這幾行:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
bramante@matrix:~/debugging-tools/make-3.81$ git log job.c
commit 127676f45707a6bef7361c146b9b106d4302393a
Author: bramante <bramante@matrix.(none)>
Date:   Thu Oct 8 00:04:48 2015 +0800

    +: Making make print commands before executing.

commit d6ded34ecab13b1569186fd4b879fdee98b49f65
Author: bramante <bramante@matrix.(none)>
Date:   Wed Oct 7 09:38:08 2015 +0800

    +: make-3.81
bramante@matrix:~/debugging-tools/make-3.81$ git diff d6ded34ecab13b1569186fd4b879fdee98b49f65 job.c
diff --git a/make-3.81/job.c b/make-3.81/job.c
old mode 100644
new mode 100755
index a81cd81..a912b36
--- a/make-3.81/job.c
+++ b/make-3.81/job.c
@@ -2073,6 +2073,32 @@ exec_command (char **argv, char **envp)

 # else

+  char* makeLogFileName = getenv("MAKE_LOG_FILE_NAME");
+  if( makeLogFileName )
+    {
+     int i ;
+     FILE * fh = NULL ;
+     fh = fopen( makeLogFileName, "a" );
+     if(fh)
+       {
+        fprintf(fh,"[*][argv] ");
+        for(i=0;argv[i]!=NULL;i++)
+           {
+            fprintf(fh,"%s ",argv[i]);
+           }
+        fprintf(fh,"\n");
+        fprintf(fh,"[*][envp] ");
+        for(i=0;envp[i]!=NULL;i++)
+           {
+            fprintf(fh,"%s ",envp[i]);
+           }
+        fprintf(fh,"\n");
+        fflush(fh);
+        fsync(fileno(fh));
+        fclose(fh);
+       }
+   }
+
   /* Run the program.  */
   environ = envp;
   execvp (argv[0], argv);
bramante@matrix:~/debugging-tools/make-3.81$

替換掉原本系統裡的GNU Make, 並設定log file的名稱:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bramante@matrix:~/debugging-tools/make-3.81$ which make
/usr/bin/make
bramante@matrix:~/debugging-tools/make-3.81$ ll make
-rwxrwxr-x 1 bramante bramante 610769 Oct  8 17:10 make*
bramante@matrix:~/debugging-tools/make-3.81$ cp ./make ../
bramante@matrix:~/debugging-tools/make-3.81$ cd ..
bramante@matrix:~/debugging-tools$ ll
total 616
drwxr-xr-x  4 bramante bramante   4096 Oct  8 18:20 ./
drwxr-xr-x 19 bramante bramante   4096 Oct  8 17:09 ../
drwxrwxr-x  8 bramante bramante   4096 Oct  8 17:09 .git/
-rwxrwxr-x  1 bramante bramante 610769 Oct  8 18:20 make*
drwxrwxr-x 10 bramante bramante   4096 Oct  8 17:10 make-3.81/
bramante@matrix:~/debugging-tools$ pwd
/home/bramante/debugging-tools
bramante@matrix:~/debugging-tools$ export PATH="/home/bramante/debugging-tools:$PATH"
bramante@matrix:~/debugging-tools$ which make
/home/bramante/debugging-tools/make
bramante@matrix:~/debugging-tools$ export MAKE_LOG_FILE_NAME="make_log.txt"

重build GNU Make 3.81來取得make執行了哪些command的資訊:

Terminal
1
2
3
4
5
6
bramante@matrix:~/debugging-tools$ cd -
/home/bramante/debugging-tools/make-3.81
bramante@matrix:~/debugging-tools/make-3.81$ make clean ; make
bramante@matrix:~/debugging-tools/make-3.81$ ll make_log.txt
-rw-rw-r-- 1 bramante bramante 99665 Oct  8 18:27 make_log.txt
bramante@matrix:~/debugging-tools/make-3.81$

從log file可以看出make執行過哪些command:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
bramante@matrix:~/debugging-tools/make-3.81$ grep "\[argv]" make_log.txt
[*][argv] /bin/sh -c if test ! -f config.h; then \
[*][argv] make all-recursive
[*][argv] /bin/sh -c failcom='exit 1'; \
[*][argv] /bin/sh -c if test ! -f config.h; then \
[*][argv] /bin/sh -c failcom='exit 1'; \
[*][argv] /bin/sh -c test -z "make" || rm -f make
[*][argv] /bin/sh -c test -z "loadavg" || rm -f loadavg
[*][argv] rm -f ansi2knr
[*][argv] /bin/sh -c rm -f *.o
[*][argv] /bin/sh -c test "" = "" || rm -f *_.c
[*][argv] /bin/sh -c if test ! -f config.h; then \
[*][argv] make all-recursive
[*][argv] /bin/sh -c failcom='exit 1'; \
[*][argv] /bin/sh -c if test ! -f config.h; then \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT ar.o -MD -MP -MF ".deps/ar.Tpo" -c -o ar.o ar.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT arscan.o -MD -MP -MF ".deps/arscan.Tpo" -c -o arscan.o arscan.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT commands.o -MD -MP -MF ".deps/commands.Tpo" -c -o commands.o commands.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT default.o -MD -MP -MF ".deps/default.Tpo" -c -o default.o default.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT dir.o -MD -MP -MF ".deps/dir.Tpo" -c -o dir.o dir.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT expand.o -MD -MP -MF ".deps/expand.Tpo" -c -o expand.o expand.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT file.o -MD -MP -MF ".deps/file.Tpo" -c -o file.o file.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT function.o -MD -MP -MF ".deps/function.Tpo" -c -o function.o function.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT getopt.o -MD -MP -MF ".deps/getopt.Tpo" -c -o getopt.o getopt.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT getopt1.o -MD -MP -MF ".deps/getopt1.Tpo" -c -o getopt1.o getopt1.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT implicit.o -MD -MP -MF ".deps/implicit.Tpo" -c -o implicit.o implicit.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT job.o -MD -MP -MF ".deps/job.Tpo" -c -o job.o job.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT main.o -MD -MP -MF ".deps/main.Tpo" -c -o main.o main.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT misc.o -MD -MP -MF ".deps/misc.Tpo" -c -o misc.o misc.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT read.o -MD -MP -MF ".deps/read.Tpo" -c -o read.o read.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT remake.o -MD -MP -MF ".deps/remake.Tpo" -c -o remake.o remake.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT remote-stub.o -MD -MP -MF ".deps/remote-stub.Tpo" -c -o remote-stub.o remote-stub.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT rule.o -MD -MP -MF ".deps/rule.Tpo" -c -o rule.o rule.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT signame.o -MD -MP -MF ".deps/signame.Tpo" -c -o signame.o signame.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT strcache.o -MD -MP -MF ".deps/strcache.Tpo" -c -o strcache.o strcache.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT variable.o -MD -MP -MF ".deps/variable.Tpo" -c -o variable.o variable.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT version.o -MD -MP -MF ".deps/version.Tpo" -c -o version.o version.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT vpath.o -MD -MP -MF ".deps/vpath.Tpo" -c -o vpath.o vpath.c; \
[*][argv] /bin/sh -c if gcc -DLOCALEDIR=\"/usr/local/share/locale\" -DLIBDIR=\"/usr/local/lib\" -DINCLUDEDIR=\"/usr/local/include\" -DHAVE_CONFIG_H -I. -I. -I.      -g -O2 -MT hash.o -MD -MP -MF ".deps/hash.Tpo" -c -o hash.o hash.c; \
[*][argv] rm -f make
[*][argv] gcc -g -O2 -o make ar.o arscan.o commands.o default.o dir.o expand.o file.o function.o getopt.o getopt1.o implicit.o job.o main.o misc.o read.o remake.o remote-stub.o rule.o signame.o strcache.o variable.o version.o vpath.o hash.o -lrt
bramante@matrix:~/debugging-tools/make-3.81$

Fallocate System Call

- - | Comments

嵌入式系統的儲存空間相當有限, 如果在下載檔案前, 先把檔案按預期的大小給建立起來, 下載時再來寫入真正的檔案內容, 這樣便能保證不會發生下載到一半卻出現Disk Full的狀況.

Linux系統有個fallocate system call可以讓我們快速建立內容全為0x00的檔案, 相當適合用來處理這樣的問題.

以下的程式會利用fallocate system call, 建立多個1GB大小的file, 直到無法再寫檔為止:

test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <linux/falloc.h>

int main(int argc, char **argv)
{
 FILE* fh ;
 char fname[128] ;
 loff_t  length = 1024*1024*1024 ;
 loff_t  offset = 0 ;
 int falloc_mode = 0 ;
 int error;
 int i ;
 for( i = 0 ; i < 200 ; i ++ )
    {
     sprintf(fname,"./data%04d",i);
     fh = fopen( fname,"w+");
     if(fh)
       {
        error = syscall(SYS_fallocate, fileno(fh), falloc_mode, offset, length);
        if(error < 0)
          {
           printf("[*][error] no space !!!\n");
           perror("fallocate failed");
           exit(EXIT_FAILURE);
          }
        fclose(fh);
       }
    }
 return 0;
}

編譯與執行:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
bramante@matrix:~/test/fallocate$ gcc -o ./test ./test.c
bramante@matrix:~/test/fallocate$ time ./test
[*][error] no space !!!
fallocate failed: Disk quota exceeded

real    0m0.897s
user    0m0.000s
sys     0m0.100s
bramante@matrix:~/test/fallocate$ ll
total 92309096
drwxrwxr-x 2 bramante bramante       4096 Sep  8 19:04 ./
drwxr-xr-x 6 bramante bramante       4096 Sep  8 18:16 ../
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0000
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0001
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0002
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0003
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0004
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0005
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0006
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0007
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0008
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0009
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0010
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0011
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0012
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0013
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0014
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0015
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0016
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0017
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0018
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0019
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0020
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0021
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0022
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0023
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0024
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0025
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0026
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0027
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0028
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0029
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0030
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0031
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0032
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0033
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0034
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0035
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0036
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0037
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0038
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0039
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0040
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0041
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0042
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0043
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0044
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0045
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0046
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0047
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0048
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0049
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0050
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0051
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0052
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0053
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0054
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0055
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0056
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0057
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0058
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0059
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0060
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0061
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0062
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0063
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0064
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0065
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0066
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0067
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0068
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0069
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0070
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0071
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0072
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0073
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0074
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0075
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0076
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0077
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0078
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0079
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0080
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0081
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0082
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0083
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0084
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0085
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0086
-rw-rw-r-- 1 bramante bramante 1073741824 Sep  8 19:04 data0087
-rw-rw-r-- 1 bramante bramante   34848768 Sep  8 19:04 data0088
-rwxrwxr-x 1 bramante bramante       8799 Sep  8 19:04 test*
-rw-rw-r-- 1 bramante bramante        721 Sep  8 19:04 test.c
bramante@matrix:~/test/fallocate$

不到1 sec可以建立出超過88 GB的檔案, 真的是好快, 而且disk quota用盡時, 程式還能順利停下來, 實在是很不錯.

從以下的執行範例, 可以看出建檔與砍檔都很快, 都不用1 sec, 而且檔案的確有內容, 內容都為0x00 :

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
bramante@matrix:~/test/fallocate$ time ./test
[*][error] no space !!!
fallocate failed: Disk quota exceeded

real    0m0.741s
user    0m0.000s
sys     0m0.100s
bramante@matrix:~/test/fallocate$ hexdump -C data0087
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
40000000
bramante@matrix:~/test/fallocate$ hexdump -C data0088
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0213a000
bramante@matrix:~/test/fallocate$ hexdump -C data0001
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
40000000
bramante@matrix:~/test/fallocate$ time rm data0*

real    0m0.864s
user    0m0.004s
sys     0m0.820s
bramante@matrix:~/test/fallocate$

另外要提一下, fallocate其實也可以用來把file裡的內容給刪掉一段, 例如, 刪除file開頭的4096 byte:

syscall(SYS_fallocate, fileno(fh), FALLOC_FL_COLLAPSE_RANGE, 0, 4096);

這個功能滿強大的, 如果能用的話, 刪除檔案裡一些不需要的內容會很快, 只可惜我的Linux server太舊了, 這個功能沒有試成功.

Define Macro on Command Line

- - | Comments

之前曾經遇過在source file與header file裡找不到Macro定義的狀況, 最後才發現Macro被定義在command line上, 以下示範如何在command line上定義Macro.

範例程式:

test.c
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(void)
{
 int a = 1 ;
 int b = 2 ;
 int c ;
 c = SUM(a,b);
 printf("c = %d\n",c);
 return 0 ;
}

編譯與執行:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bramante@matrix:~/blog/define_macro_on_command_line$ gcc -o ./test "-DSUM(a,b)=(a+b)" ./test.c
bramante@matrix:~/blog/define_macro_on_command_line$ ./test
c = 3
bramante@matrix:~/blog/define_macro_on_command_line$ gcc -E "-DSUM(a,b)=(a+b)" ./test.c | grep -A8 "int main(void)"
int main(void)
{
 int a = 1 ;
 int b = 2 ;
 int c ;
 c = (a+b);
 printf("c = %d\n",c);
 return 0 ;
}
bramante@matrix:~/blog/define_macro_on_command_line$

從執行的結果, 與展開Macro後的source code, 可以確定在command line上定義Macro是可行的.

Expand Macro

- - | Comments

閱讀別人所寫的程式, 如果遇到複雜的Macro, 不太能確定執行後會有什麼結果時, 可以使用Expand Macro的技巧, 把Macro給展開, 這樣程式應該會變得比較容易了解一點.

範例程式:

test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

#define SUM( a, b ) (a+b)

int main(void)
{
 int a = 1 ;
 int b = 2 ;
 int c ;
 c = SUM(a,b);
 printf("c = %d\n",c);
 return 0 ;
}

利用gcc的”-E”參數, 可以把Macro給展開:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bramante@matrix:~/test/Expand_Macro$ gcc -o ./test ./test.c
bramante@matrix:~/test/Expand_Macro$ ./test
c = 3
bramante@matrix:~/test/Expand_Macro$ gcc -E ./test.c | grep -A8 "int main(void)"
int main(void)
{
 int a = 1 ;
 int b = 2 ;
 int c ;
 c = (a+b);
 printf("c = %d\n",c);
 return 0 ;
}
bramante@matrix:~/test/Expand_Macro$

Program Hangs on Exit

- - | Comments

之前有遇過程式在執行exit()之後, 竟然發生程式hang住, 無法結束執行的狀況. 這個問題罩因於, 在執行exit()時, 會對C++的static/global Object進行de-init, 若C++ class的destructor沒有寫好, 例如卡在destructor裡的永久迴圈, 或是發生了dead lock, 便會造成這個異常的現象, 下面的程式刻意在destructor裡加入永久迴圈, 故意製造hang住的狀態, 重製這樣的bug:

hang.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

static char* ptr ;

class PARENT {
      public:
              PARENT()
              {
              }
              ~PARENT()
              {
               while(1)
                    {
                     printf("block...\n");
                     sleep(1);
                    }
              }
              void test(void)
              {
               printf("test()\n");
              }
};

int main(void)
{
 static PARENT parentObj ;
 parentObj.test();
 exit(0);
 return 0 ;
}

編譯與執行:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
bramante@matrix:~/test$ g++ -o ./hang ./hang.cpp
bramante@matrix:~/test$ gdb ./hang
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/bramante/test/hang...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/bramante/test/hang
test()
block...
block...
block...
block...
block...
block...
block...
^C
Program received signal SIGINT, Interrupt.
0x00007ffff77db090 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
82      ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) bt
#0  0x00007ffff77db090 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1  0x00007ffff77daf4c in __sleep (seconds=0) at ../sysdeps/unix/sysv/linux/sleep.c:138
#2  0x0000000000400770 in PARENT::~PARENT() ()
#3  0x00007ffff77575b1 in __run_exit_handlers (status=0, listp=0x7ffff7ad3688, run_list_atexit=true) at exit.c:78
#4  0x00007ffff7757635 in __GI_exit (status=<optimized out>) at exit.c:100
#5  0x0000000000400746 in main ()
(gdb)

從callstack可以看出是main()執行exit()時, 在class PARENT的destructor發生hang住的狀況.

這個bug, 在glibc的callstack看到的是:

__run_exit_handlers()
__GI_exit()

在bionic libc看到的則是:

__cxa_finalize()
exit()

不同的libc在這部份的實作上, 似乎有點不一樣.

C++的程式在一跑起來時, 會利用__cxa_atexit()去註冊destructor, 然後在程式結束執行時, 便會去執行這些登記在案的destructor.

work around bug的方法很簡單, 可以把exit()換成kill(getpid(), SIGKILL), 或是把exit()換成_exit(), 讓程式刻意不去執行destructor, 便可以讓hang住不要發生.

Program Crashes on Exit

- - | Comments

之前有遇過程式在執行exit()之後, 竟然發生crash的狀況. 這個問題罩因於, 在執行exit()時, 會對C++的static/global Object進行de-init, 若C++ class的destructor沒有寫好, 就會在執行destructor時發生crash, 下面的程式故意在destructor裡製造crash, 重製這樣的bug:

crash.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdlib.h>
#include <stdio.h>

static char* ptr ;

class PARENT {
      public:
              PARENT()
              {
               if(ptr)
                 {
                  ptr = (char*) malloc(100);
                 }
              }
              ~PARENT()
              {
               free(ptr);
               ptr = (char*) 0xDEADBEEF ;
              }
              void test(void)
              {
               printf("test()\n");
              }
};

int main(void)
{
 static PARENT parentObj1, parentObj2 ;
 parentObj1.test();
 parentObj2.test();
 exit(0);
 return 0 ;
}

編譯與執行:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
bramante@matrix:~/test$ g++ -o ./crash ./crash.cpp
bramante@matrix:~/test$ gdb ./crash
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/bramante/test/crash...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/bramante/test/crash
test()
test()

Program received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0xdeadbeef) at malloc.c:2970
2970    malloc.c: No such file or directory.
(gdb) bt
#0  __GI___libc_free (mem=0xdeadbeef) at malloc.c:2970
#1  0x0000000000400831 in PARENT::~PARENT() ()
#2  0x00007ffff77575b1 in __run_exit_handlers (status=0, listp=0x7ffff7ad3688, run_list_atexit=true) at exit.c:78
#3  0x00007ffff7757635 in __GI_exit (status=<optimized out>) at exit.c:100
#4  0x00000000004007ea in main ()
(gdb)

從callstack可以看出是main()執行exit()時, 在class PARENT的destructor發生crash. crash的原因是程式去踩到一個不合法的address 0xDEADBEEF.

這個bug, 在glibc的callstack看到的是:

__run_exit_handlers()
__GI_exit()

在bionic libc看到的則是:

__cxa_finalize()
exit()

不同的libc在這部份的實作上, 似乎有點不一樣.

C++的程式在一跑起來時, 會利用__cxa_atexit()去註冊destructor, 然後在程式結束執行時, 便會去執行這些登記在案的destructor.

work around bug的方法很簡單, 如果只是單純要程式結束, 並且不想看到crash的log, 可以把exit()換成kill(getpid(), SIGKILL), 或是把exit()換成_exit(), 讓程式刻意不去執行destructor, 便可以讓crash不要發生.

Direct IO

- - | Comments

Direct IO比一般read/write file的方式來得快, 但是它有一些Alignment的規則要遵守, 不然程式會不work, 下面是用Direct IO寫成的一支copy程式:

my_copy.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
#include <stddef.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/fcntl.h>

#define BLOCK_SIZE 4096

int main(int argc, char* argv[])
{
 int fhInput ;
 int fhOutput ;
 int len ;
 int sum ;
 static unsigned char buf[BLOCK_SIZE] __attribute__((aligned (4096))) ;

 if( argc == 3 )
   {
    fhInput = open( argv[1], O_RDONLY | O_DIRECT );
    fhOutput = open( argv[2], O_WRONLY | O_CREAT | O_TRUNC |O_DIRECT );

    if((fhInput < 0) || (fhOutput < 0))
      {
       printf("[Error] open file fail.\n");
       if( fhInput >= 0 )
         {
          close(fhInput);
         }
        else
         {
          printf("[Error] Can not open %s\n", argv[1] );
         }

       if( fhOutput >= 0 )
         {
          close(fhOutput);
         }
        else
         {
          printf("[Error] Can not open %s\n", argv[2] );
         }
       return -1 ;
      }
     else
      {
       sum = 0 ;
       do{
          len = read( fhInput, buf , BLOCK_SIZE );
          //printf("len: %d\n",len);
          write( fhOutput, buf, BLOCK_SIZE );
          sum += BLOCK_SIZE ;
         }while(len == BLOCK_SIZE);

       if( len > 0 )
         {
          ftruncate( fhOutput, sum - BLOCK_SIZE + len );
         }

       struct stat fileAttr ;
       fstat( fhInput, &fileAttr );
       fchmod( fhOutput, fileAttr.st_mode );
       close(fhOutput);
       close(fhInput);

       return 0;
      }
   }
  else
   {
    printf("[help] ./my_copy ./src_file ./dest_file \n");
    return -1 ;
   }
}

編譯與執行:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
bramante@matrix:~/test$ gcc -o ./my_copy ./my_copy.c
bramante@matrix:~/test$ which ls
/bin/ls
bramante@matrix:~/test$ ll /bin/ls
-rwxr-xr-x 1 root root 105840 Nov 20  2012 /bin/ls*
bramante@matrix:~/test$ ./my_copy /bin/ls ./ls
bramante@matrix:~/test$ ll | grep ls
-rwxr-xr-x 1 bramante bramante 105840 Sep  4 11:15 ls*
bramante@matrix:~/test$ diff ./ls /bin/ls
bramante@matrix:~/test$
bramante@matrix:~/test$ ./ls -al | grep ls
-rwxr-xr-x 1 bramante bramante 105840 Sep  4 11:15 ls
bramante@matrix:~/test$

Direct IO 所read/write的byte數, 以及read/write的起點, 還有read()/write()所使用的memory buffer, 應該都要align在512 byte的倍數上, 精確的alignment限制可以參考網路上的說明:

http://people.redhat.com/msnitzer/docs/io-limits.txt

gcc有提供attribute, 讓變數可以align在特定的address上, 我只有試過在全域變數上確實有用, 其他的沒試過:

__attribute__(aligned (4096))

因為在這支程式裡, Direct IO一次read/write 4096 byte, 因此copy出的file會多一截”尾巴”, 我用ftruncate()來cut掉它:

ftruncate( fhOutput, sum - BLOCK_SIZE + len );

為了讓copy出的file的屬性和原本的file相同, 因此我用fstat()與fchmod()複製了檔案屬性:

fstat( fhInput, &fileAttr );
fchmod( fhOutput, fileAttr.st_mode );

Fallocate

- - | Comments

fallocate command可以用來快速地建立1個file, 以下是操作範例:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bramante@matrix:~/test$ fallocate -o 0 -l 96 data
bramante@matrix:~/test$ ll
total 12
drwxrwxr-x 2 bramante bramante 4096 Sep  4 00:10 ./
drwxr-xr-x 6 bramante bramante 4096 Sep  2 23:36 ../
-rw-r--r-- 1 bramante bramante   96 Sep  4 00:10 data
bramante@matrix:~/test$ hexdump -Cv ./data
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000060
bramante@matrix:~/test$

fallocate command也可以用來擴充file的size, 以下是操作範例:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bramante@matrix:~/test$ dd if=/dev/zero bs=1 count=96 | tr '\000' '\377' > data
96+0 records in
96+0 records out
96 bytes (96 B) copied, 0.000357439 s, 269 kB/s
bramante@matrix:~/test$ hexdump -Cv ./data
00000000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000040  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000050  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000060
bramante@matrix:~/test$ fallocate -o 80 -l 32 data
bramante@matrix:~/test$ hexdump -Cv ./data
00000000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000040  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000050  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070
bramante@matrix:~/test$

“fallocate -o 80 -l 32 data”的意思是, 從data這個檔案的offset 80 byte的位置開始, 要有32 byte的空間, 由於原本在offset 80之後就有16個byte, 因此檔案最後只擴充了16 byte的size.

Download the Source Code of the Ginga

- - | Comments

Ginga是巴西DTV上的Middleware, 它的source code是open source的, 可以用下面的command把source code給抓回來:

Terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
bramante@matrix:~$ git clone http://git.telemidia.puc-rio.br/ginga.git
Cloning into 'ginga'...
bramante@matrix:~$ cd ginga/
bramante@matrix:~/ginga$ ll
total 184
drwxr-xr-x 25 bramante bramante  4096 Sep  2 23:52 ./
drwxr-xr-x  6 bramante bramante  4096 Sep  2 23:36 ../
-rw-rw-r--  1 bramante bramante    96 Sep  2 23:52 AUTHORS
-rwxrwxr-x  1 bramante bramante   292 Sep  2 23:52 bootstrap*
drwxrwxr-x  2 bramante bramante  4096 Sep  2 23:52 build-aux/
-rw-rw-r--  1 bramante bramante     0 Sep  2 23:52 ChangeLog
drwxrwxr-x  2 bramante bramante  4096 Sep  2 23:52 config/
-rw-rw-r--  1 bramante bramante 17007 Sep  2 23:52 configure.ac
drwxrwxr-x  2 bramante bramante  4096 Sep  2 23:52 contrib/
-rw-rw-r--  1 bramante bramante 18009 Sep  2 23:52 COPYING
drwxrwxr-x  4 bramante bramante  4096 Sep  2 23:52 debian/
drwxrwxr-x  3 bramante bramante  4096 Sep  2 23:52 ginga/
drwxrwxr-x  6 bramante bramante  4096 Sep  2 23:52 gingacc-cm/
drwxrwxr-x  6 bramante bramante  4096 Sep  2 23:52 gingacc-contextmanager/
drwxrwxr-x  5 bramante bramante  4096 Sep  2 23:52 gingacc-dataprocessing/
drwxrwxr-x  5 bramante bramante  4096 Sep  2 23:52 gingacc-ic/
drwxrwxr-x  6 bramante bramante  4096 Sep  2 23:52 gingacc-mb/
drwxrwxr-x  5 bramante bramante  4096 Sep  2 23:52 gingacc-multidevice/
drwxrwxr-x  6 bramante bramante  4096 Sep  2 23:52 gingacc-player/
drwxrwxr-x  4 bramante bramante  4096 Sep  2 23:52 gingacc-system/
drwxrwxr-x  5 bramante bramante  4096 Sep  2 23:52 gingacc-tsparser/
drwxrwxr-x  6 bramante bramante  4096 Sep  2 23:52 gingacc-tuner/
drwxrwxr-x  5 bramante bramante  4096 Sep  2 23:52 gingacc-um/
drwxrwxr-x  5 bramante bramante  4096 Sep  2 23:52 gingalssm/
drwxrwxr-x  6 bramante bramante  4096 Sep  2 23:52 gingancl/
drwxrwxr-x  6 bramante bramante  4096 Sep  2 23:52 ginga-vs2010-solution/
drwxrwxr-x  8 bramante bramante  4096 Sep  2 23:52 .git/
-rw-rw-r--  1 bramante bramante  1406 Sep  2 23:52 .gitignore
-rw-rw-r--  1 bramante bramante  9152 Sep  2 23:52 LICENSING
-rw-rw-r--  1 bramante bramante   183 Sep  2 23:52 maint.mk
-rw-rw-r--  1 bramante bramante  2066 Sep  2 23:52 Makefile.am
drwxrwxr-x  4 bramante bramante  4096 Sep  2 23:52 ncl30/
drwxrwxr-x  4 bramante bramante  4096 Sep  2 23:52 ncl30-converter/
-rw-rw-r--  1 bramante bramante     0 Sep  2 23:52 NEWS
-rw-rw-r--  1 bramante bramante   233 Sep  2 23:52 README
-rw-rw-r--  1 bramante bramante  2066 Sep  2 23:52 README.linux
-rw-rw-r--  1 bramante bramante   188 Sep  2 23:52 README.windows
drwxrwxr-x  5 bramante bramante  4096 Sep  2 23:52 telemidia-util/
bramante@matrix:~/ginga$

Secure Copy

- - | Comments

在2台Linux電腦之間copy檔案, 使用scp command (secure copy, remote file copy program) 是相當方便的, 以下是使用範例:

Terminal 192.168.1.2
1
2
3
4
5
6
7
8
9
10
11
bramante@matrix:~$ ll ./test.bin
-rwxr--r-- 1 bramante bramante 72087592 Sep  1 15:46 ./test.bin*
bramante@matrix:~$     
bramante@matrix:~$ scp ./test.bin minions@192.168.1.3:~/
The authenticity of host '192.168.1.3 (192.168.1.3)' can't be established.
ECDSA key fingerprint is a1:3e:45:35:f5:23:e2:f3:56:c8:50:bf:22:05:4b:9b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.3' (ECDSA) to the list of known hosts.
minions@192.168.1.3's password:
test.bin                                                                                                                100%   69MB  11.5MB/s   00:06
bramante@matrix:~$

Terminal 192.168.1.3
1
2
3
minions@zion:~$ ll ./test.bin
-rwxr--r-- 1 minions minions 72087592 Sep  1 15:50 ./test.bin*
minions@zion:~$

scp也有Windows的版本, 所以在Linux電腦與Windows電腦間copy檔案, 也可以使用scp.