サンプルプログラム集

提供: Wikinote
移動: 案内検索

TP の素を揃えておこうかと。

C

pthread.c

コマンド引き数で与えられた数だけ、ただ寝てるだけのスレッドを生成するプログラム。

ソースコード

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_func(void *arg) {
    printf("Thread %d\n", (int) arg);
    while (1)
        sleep(1);
}
int main(int argc, char *argv[]) {
    int i, num;
    pthread_t *th;

    if (argc < 2) {
        printf("Usage: %s threads\n", argv[0]);
        return 1;
    }
    if ((num = atoi(argv[1])) < 1) {
        printf("arg 1 = %d\n", num);
        return 1;
    }
    th = (pthread_t *) malloc(sizeof(pthread_t) * num);
    for (i = 0; i < num; i++) {
        pthread_create(&th[i], NULL, &thread_func, (void *) i);
    }
    for (i = 0; i < num; i++) {
        pthread_join(th[i], NULL);
    }
    return 0;
}

実行例

$ cc -l pthread -o pthread pthread.c
$ ./pthread 
Usage: ./pthread threads
$ ./pthread 3 &
[1] 580
Thread 0
Thread 1
Thread 2
$ ps -elfL | grep pthread
0 S hagio      580 13327   580  0    4  77   0 -  8117 -      09:59 pts/5    00:00:00 ./pthread 3
1 S hagio      580 13327   582  0    4  75   0 -  8117 -      09:59 pts/5    00:00:00 ./pthread 3
1 S hagio      580 13327   583  0    4  75   0 -  8117 -      09:59 pts/5    00:00:00 ./pthread 3
1 S hagio      580 13327   584  0    4  75   0 -  8117 -      09:59 pts/5    00:00:00 ./pthread 3
0 S hagio      602 13327   602  0    1  77   0 -  1245 pipe_w 09:59 pts/5    00:00:00 grep pthread
$ kill $!
[1]+  終了しました      ./pthread 3

fork.c

コマンド引き数で与えられた数だけ fork して、ゾンビ状態で放置するプログラム。

ソースコード

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[]) {
    int i, num;
    pid_t pid;

    if (argc < 2) {
        printf("Usage %s procs\n", argv[0]);
        return 0;
    }
    if ((num = atoi(argv[1])) < 0) {
        printf("arg 1 = %d\n", num);
        return 0;
    }
    for (i = 0; i < num; i++) {
        pid = fork();
        if (pid < 0) {
            perror("fork");
            return 1;
        } else if (pid == 0) {
            printf("Child %d\n", i);
            //while (1) sleep(1);
            return 0;
        } else {
            printf("Parent %d (PID: %d)\n", i, pid);
        }
    }
    while (1) sleep(1);
    return 0;
}

実行例

$ cc -o fork fork.c
$ ./fork 3
Child 0
Parent 0 (PID: 1197)
Child 1
Parent 1 (PID: 1198)
Child 2
Parent 2 (PID: 1199)
$ ps -elf | grep fork
0 S hagio     1196 13327  0  75   0 -   378 -      10:30 pts/5    00:00:00 ./fork 3
1 Z hagio     1197  1196  0  76   0 -     0 exit   10:30 pts/5    00:00:00 [fork] <defunct>
1 Z hagio     1198  1196  0  77   0 -     0 exit   10:30 pts/5    00:00:00 [fork] <defunct>
1 Z hagio     1199  1196  0  77   0 -     0 exit   10:30 pts/5    00:00:00 [fork] <defunct>
0 S hagio     1208 31213  0  78   0 -  1245 pipe_w 10:30 pts/4    00:00:00 grep fork

setro.c

ioctl のサンプル。ブロックデバイスの読み込み専用フラグを変更するプログラム。

ソースコード

#include <stdio.h>
#include <fcntl.h>
#include <linux/fs.h>

int main(int argc, char* argv[]) {
    int fd, res, flag;

    if (argc != 3) {
        printf("Usage: %s DEVICE RO_FLAG\n", argv[0]);
        return 1;
    }

    if ((fd = open(argv[1], O_RDWR)) < 0) {
        perror("open");
        return 1;
    }

    flag = atoi(argv[2]);
    if ((res = ioctl(fd, BLKROSET, &flag)) < 0) {
        perror("ioctl");
        close(fd);
        return 1;
    }
    close(fd);
    return 0;
}

実行例

# umount /boot        ★いったんアンマウント
# ./setro /dev/sda1 1 ★リードオンリーにセット
# mount /boot
mount: ブロックデバイス /dev/sda1 は書き込み禁止です、読込み専用でマウントします
# umount /boot
# ./setro /dev/sda1 0 ★リードオンリーを解除
# mount /boot

signal.c

単に受信したシグナル番号を出力するプログラム。

ソースコード

#include <stdio.h>
#include <signal.h>

void signal_handler(int sig) {
    printf("signal: %d\n", sig);
}
int main(void) {
    //signal(SIGINT , SIG_IGN);
    signal(SIGINT , SIG_DFL);
    signal(SIGQUIT, signal_handler);
    signal(SIGALRM, signal_handler);
    signal(SIGTERM, signal_handler);
    alarm(5);
    while (1) {
        sleep(1);
    }
}

実行例

$ ./signal
signal: 3
signal: 3
signal: 15
signal: 14
signal: 3

shm.c

共有メモリの確保と読み書きを行うプログラム。削除は ipcrm で…。

ソースコード

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

#define SHM_SIZE 1024

int main(int argc, char *argv[]) {
    int shmid;
    char *shmaddr;
    char *data;

    if (argc < 2) {
        printf("Usage: %s data [shmid]\n", argv[0]);
        return 1;
    }
    data = argv[1];
    if (argc < 3) {
        if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666)) < 0) {
            perror("shmget");
            return 1;
        }
        printf("new shmid = %d\n", shmid);
    } else {
        shmid = atoi(argv[2]);
    }

    if ((shmaddr = shmat(shmid, NULL, 0)) < 0) {
        perror("shmat");
        return 1;
    }
    printf("shmaddr = %p\n", shmaddr);
    printf("current value = %s\n", shmaddr);

    strcpy(shmaddr, data);
    printf("written value = %s\n", shmaddr);
}

実行例

$ ./a.out 
Usage: ./a.out data [shmid]
$ ./a.out "test data"
new shmid = 655367
shmaddr = 0xb7fb1000
current value = 
written value = test data
$ ./a.out hoge 655367
shmaddr = 0xb7f27000
current value = test data
written value = hoge
$ ./a.out test 655367
shmaddr = 0xb7fb2000
current value = hoge
written value = test
$ ipcs -m

------ 共有メモリセグメント --------
キー     shmid      所有者  権限     バイト  nattch     状態      
0x00000000 229379     hagio     600        393216     2          対象       
0x00000000 262149     hagio     600        393216     2          対象       
0x00000000 655367     hagio     666        1024       0                       

$ ipcrm -m 655367
$ ipcs -m

------ 共有メモリセグメント --------
キー     shmid      所有者  権限     バイト  nattch     状態      
0x00000000 229379     hagio     600        393216     2          対象       
0x00000000 262149     hagio     600        393216     2          対象       

Python

tcp_server.py / tcp_client.py

簡単な TCP サーバ / クライアントプログラム。例外処理はある程度まで。

tcp_server.py

#!/usr/bin/env python
import sys, socket

port = 55555
if len(sys.argv) > 1:
    try:
        port = int(sys.argv[1])
    except:
        print "Ivalid port number"
        sys.exit(1)

try:
    sock = socket.socket()
    sock.bind(("", port))
    sock.listen(5)
except socket.error, msg:
    print msg
    sys.exit(1)
    
while True:
    print "Waiting for a connection (port: %d)..." % port
    try:
        csock, addr = sock.accept()
        print "Connected by %s:%d" % addr
        while True:
            try:
                buf = csock.recv(1024)
                if not buf:
                    print "Disconnected."
                    break
                print "Received : %s" % buf
            except KeyboardInterrupt:
                break
        csock.close()
    except KeyboardInterrupt:
        break
sock.close()

tcp_client.py

#!/usr/bin/env python
import sys, socket

if len(sys.argv) < 2:
    print "Usage: %s host [port]" % sys.argv[0]
    sys.exit(1)

host = sys.argv[1]
port = 55555
if len(sys.argv) > 2:
    try:
        port = int(sys.argv[2])
    except ValueError:
        print "Invalid port number"
        sys.exit(1)

try:
    sock = socket.socket()
    sock.connect((host, port))
except socket.error, msg:
    print msg
    sys.exit(1)
print "Connected to %s:%d" % (host, port)
while True:
    try:
        buf = raw_input("> ")
        if buf == "q":
            break
        sock.send(buf)
    except KeyboardInterrupt:
        break
sock.close()

実行例

サーバ側:
$ ./tcp_server.py 12345
Waiting for a connection (port: 12345)...
Connected by 127.0.0.1:51522
Received : test data
Disconnected.
Waiting for a connection (port: 12345)...

クライアント側:
$ ./tcp_client.py localhost 12345
Connected to localhost:12345
> test data
> 
> quit

memcurses.py

curses (libcurses) を利用した /proc/meminfo の変化量を表示するスクリプト。

ソースコード

#!/usr/bin/env python
import sys, time, curses

def main(argv):
    win = curses.initscr()
    if len(argv) > 1:
        interval = int(argv[1])
    else:
        interval = 1

    f = open("/proc/meminfo", "r")
    prev = []
    while True:
        win.clear()
        win.addstr(0, 0, "Every %d.0s : %s" % (interval, time.ctime()))
        i = 0
        try:
            for line in f:
                win.addstr(i+2, 0, line[:-1])
                cur = line.split()[1]
                try:
                    if cur != prev[i]:
                        win.addstr(" %+d" % (int(cur) - int(prev[i])))
                        prev[i] = cur
                except IndexError:
                    prev.append(cur)
                i += 1
            win.addstr("\n")
            win.refresh()
            f.seek(0)
            time.sleep(interval)
        except KeyboardInterrupt:
            break

    curses.endwin()
    f.close()
    return 0

if __name__ == "__main__":
    sys.exit(main(sys.argv))

実行例

$ ./memcurses.py 5
Every 5.0s : Sat Feb 26 01:06:31 2011

MemTotal:      5968984 kB
MemFree:        458472 kB
Buffers:        292224 kB +8
Cached:        4135716 kB
SwapCached:          0 kB
Active:        2248520 kB +44
Inactive:      2798728 kB
HighTotal:     5241152 kB
HighFree:       449732 kB
LowTotal:       727832 kB
LowFree:          8740 kB
SwapTotal:     6144852 kB
SwapFree:      6144716 kB
Dirty:             456 kB
Writeback:           0 kB
AnonPages:      619336 kB +32
Mapped:        1179140 kB +112
Slab:           111936 kB -44
PageTables:      12296 kB +52
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   9129344 kB
Committed_AS:  1629408 kB
VmallocTotal:   116728 kB
VmallocUsed:     19364 kB
VmallocChunk:    97136 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

grep.py

grep -Hn と同様の出力となるスクリプト。 標準入力からの入力には非対応。

ソースコード

#!/usr/bin/env python
import sys, re, threading

def grep(reg, path):
    f = open(path, "r")
    row = 1
    for line in f:
        if reg.search(line):
            print "%s:%d:%s" % (path, row, line),
        row += 1
    f.close()

if __name__ == "__main__":
    if len(sys.argv) > 2:
        reg = re.compile(sys.argv[1])
        for path in sys.argv[2:]:
            grep(reg, path)
    else:
        print "Usage: %s PATTERN FILES.." % sys.argv[0]
        sys.exit(1)

実行例

$ ./grep.py
Usage: ./grep.py PATTERN FILES..
$ ./grep.py while *.py
graph.py:9:    while 1:
memcurses.py:13:    while True:
memstat.py:12:    while True:
ncurses.py:8:    while True:
netmonitor.py:32:    while 1:
netstat.py:67:        while True:
netstat.py:132:while True:
open.py:12:while True:
pystat.py:85:while True:
sdx.py:9:    while (q > 0):
tcp_client.py:13:while True:
tcp_server.py:8:while 1:
tcp_server.py:13:        while True:

wc.py

Python で作った wc コマンド。

ソースコード

#!/usr/bin/env python
import sys, getopt

def usage():
    print "Usage: %s [-cmlLw] FILES" % sys.argv[0]

def wc(f):
    (c, m, l, L, w) = (0, 0, 0, 0, 0)
    for line in f:
        c += len(line)
        m += len(line.decode('UTF-8'))
        l += 1
        L  = max(L, len(line)-1)
        w += len(line.split())
    return (c, m, l, L, w)

if __name__ == "__main__":
    try:
        opts, args = getopt.getopt(sys.argv[1:], "cmlLw")
    except getopt.GetoptError:
        usage()
        sys.exit(1)

    # set defaults
    opt_c = True  # bytes
    opt_m = False # chars 
    opt_l = True  # lines
    opt_L = False # max-line-length
    opt_w = True  # words

    if opts:
        (opt_c, opt_l, opt_w) = (False, False, False)
    for (opt, val) in opts:
        if opt == "-c":
            opt_c = True
        elif opt == "-m":
            opt_m = True
        elif opt == "-l":
            opt_l = True
        elif opt == "-L":
            opt_L = True
        elif opt == "-w":
            opt_w = True

    (total_c, total_m, total_l, total_L, total_w) = (0, 0, 0, 0, 0)
    if not args:
        args.append("-")
    for arg in args:
        if arg == "-":
            f = sys.stdin
        else:
            f = open(arg, "r")
        (c, m, l, L, w) = wc(f)
        f.close()
        if opt_l:
            print " %5d" % l,
        if opt_w:
            print " %5d" % w,
        if opt_m:
            print " %5d" % m,
        if opt_c:
            print " %5d" % c,
        if opt_L:
            print " %5d" % L,
        print arg
        total_c += c
        total_m += m
        total_l += l
        total_L = max(total_L, L)
        total_w += w

    if len(args) > 1:
        if opt_l:
            print " %5d" % total_l,
        if opt_w:
            print " %5d" % total_w,
        if opt_m:
            print " %5d" % total_m,
        if opt_c:
            print " %5d" % total_c,
        if opt_L:
            print " %5d" % total_L,
        print "total"

実行例

$ ./wc.py -h
Usage: ./wc.py [-cmlLw] FILES
$ ./wc.py -clmwL *.py | addspace 
    29     80    438    438     45 awk.py
    28     82    719    719     59 buddy.py
    23     70    531    531     65 calc_buddy.py
     4     12     79     79     28 compare.py
    21     55    444    444     43 dec2bin.py
    35     98   1000   1000     49 decode_actlog.py
    87    255   2287   2287     51 graph.py
    20     58    475    475     55 grep.py
    24     78    498    498     43 hex2bin.py
    79    207   1790   1790     71 mail.py
   127    347   3129   3129    109 mail2pens.py
    40     91   1003   1003     71 memcurses.py
    38     77    881    881     63 memstat.py
    21     35    398    398     41 ncurses.py
    54    134   1463   1463    101 netmonitor.py
   144    590   4967   4967    129 netstat.py
    19     30    246    246     40 open.py
    33    105    916    916     57 pygrep.py
   124    376   2977   2977     80 pystat.py
    24     73    510    510     52 sdx.py
    19     43    331    331     40 tcp_client.py
    24     52    523    523     46 tcp_server.py
    84    277   1983   1983     67 wc.py
  1101   3225  27588  27588    129 total
 lines  words  chars  bytes maxlen

calc_buddy.py

/proc/buddyinfo のそれぞれのゾーンの合計サイズを計算するスクリプト。 タイムスタンプを付けて記録したファイルにも対応。

パイプで less などに繋いだ後に Broken Pipe のエラーが出ないように修正。

ソースコード

#!/usr/bin/env python
import sys

if len(sys.argv) == 1:
    files = [ open('/proc/buddyinfo', 'r') ]
    ts_shift = 4;
else:
    files = [ open(f) for f in sys.argv[1:] ]
    ts_shift = 6;

for file in files:
    for line in file:
        try:
            if len(line) > 1:
                print line[:-1],
                fields = line.split()
                total = 0
                for val in range(0,11):
                    total += int(fields[ts_shift + val]) * 4 * 2**val
                print total, "KB"
            else:
                print line,
        except IOError:
            break
    file.close()

実行例

$ ./calc_buddy.py 
Node 0, zone      DMA     46      5      3      0      0      0      0      1      1      1      0  3856 KB
Node 0, zone   Normal    327      2      1      1      1      1      1      0      0      0      1  5916 KB
Node 0, zone  HighMem  78051  15607    279      2     59     17      2      0      0      0      0  448052 KB

dec2bin.py

10 進数を 2 進数に変換するスクリプト。32 ビット限定。

ソースコード

#!/usr/bin/env python
import sys

def dec2bin(dec):
    ret = ""
    for i in range(31, -1, -1):
        if dec & (1 << i):
            ret += "1"
        elif ret:
            ret += "0"
    return ret

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print "Usage: %s dec" % sys.argv[0]
        sys.exit(1)
    try:
        print dec2bin(int(sys.argv[1]))
    except ValueError:
        print "Invalid number"
        sys.exit(1)

実行例

$ ./dec2bin.py
Usage: ./dec2bin.py dec
$ ./dec2bin.py 12345
11000000111001
$ ./dec2bin.py 1024
10000000000
$ ./dec2bin.py -65536
11111111111111110000000000000000
$ ./dec2bin.py 2147483647
1111111111111111111111111111111  // 先頭の 0 は省かれている
$ ./dec2bin.py -2147483648
10000000000000000000000000000000

int2bin.py

上の dec2bin.py を利用して、8, 10, 16 進数に対応させたもの。 コメントアウトしている最後の出力はビット位置確認用。

dec2bin の名前の付け方が悪かったな。

ソースコード

#!/usr/bin/env python
import sys
from dec2bin import dec2bin

def usage():
    print "Usage: %s DEC|'0x'HEX|'0'OCT" % sys.argv[0]
    sys.exit(1)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        usage()
    num = sys.argv[1]
    try:
        if num[:2] == "0x":
            b = dec2bin(int(sys.argv[1], 16))
        elif num[0] == "0":
            b = dec2bin(int(sys.argv[1], 8))
        else:
            b = dec2bin(int(sys.argv[1], 10))
    except ValueError:
        usage()
    l = len(b)
    s = 
    for i in range(0, l, 1):
        r = i % 4
        s = str(2 ** r) + s
    #print s
    print b

実行例

$ ./int2bin.py 
Usage: ./int2bin.py DEC|'0x'HEX|'0'OCT
$ ./int2bin.py 255
11111111
$ ./int2bin.py -255
11111111111111111111111100000001
$ ./int2bin.py 0x12ab
1001010101011
$ ./int2bin.py 0xdeadbeef
11011110101011011011111011101111
$ ./int2bin.py 0755
111101101

bash

cgrep

パターンが呼ばれている関数を検索するスクリプト。 ほとんど awk だけど。

スクリプト

#!/bin/bash
IFS=$'\n'
RESULT=$(grep -nH $@) 
for l in $RESULT; do
    FILE=$(echo "$l" | cut -d: -f 1)
    LINE=$(echo "$l" | cut -d: -f 2)
    gawk -v line=$LINE -v file=$FILE '
        NR < line && /^\w/ && !/:/ {
            cand = $0
            cand_line = NR
        }
        NR == line {
            if ($0 ~ /^\w/) {
                print file ":" line ":"
            } else {
                print file ":" cand_line ":"
                print cand
            }
            gsub("\t", "    ") 
            print $0
            exit
        }
    ' $FILE
done

実行例

$ cgrep -r shrink_slab mm
mm/vmscan.c:177:
unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
mm/vmscan.c:1026:
unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask)
        shrink_slab(sc.nr_scanned, gfp_mask, lru_pages);
mm/vmscan.c:1134:
static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
            nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
mm/vmscan.c:1426:
unsigned long shrink_all_memory(unsigned long nr_pages)
        shrink_slab(nr_pages, sc.gfp_mask, lru_pages);
mm/vmscan.c:1426:
unsigned long shrink_all_memory(unsigned long nr_pages)
            shrink_slab(sc.nr_scanned, sc.gfp_mask, lru_pages);
mm/vmscan.c:1426:
unsigned long shrink_all_memory(unsigned long nr_pages)
            shrink_slab(nr_pages, sc.gfp_mask, lru_pages);
mm/vmscan.c:1626:
static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
         * shrink_slab() does not currently allow us to determine how
mm/vmscan.c:1626:
static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
         * Note that shrink_slab will free memory on all zones and may
mm/vmscan.c:1626:
static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        while (shrink_slab(sc.nr_scanned, gfp_mask, order) &&