2022年5月19日 星期四

[Raspberry] 如何製作Raspberry Pi 4的Android Image

1. Android電腦架設
OS需安裝Ubuntu,CPU能力將決定build image的時間

2. 下載Android source code
# repo init -u https://android.googlesource.com/platform/manifest -b android-12.1.0_r5
# git clone https://github.com/android-rpi/local_manifests .repo/local_manifests -b arpi-12
# repo sync

3. 上patch

4.製作Android Image
# source build/envsetup.sh
# lunch rpi4-eng
# make -j 16 ramdisk systemimage vendorimage
(須等一段時間)

5. 編譯Android Kernel
# mkdir arpi-5.10
# cd arpi-5.10
# repo init -u https://github.com/android-rpi/kernel_manifest -b arpi-5.10
# repo sync
# build/build.sh
檔案會產生在out/arpi-5.10/dist/
需要的檔案為Image.gz, bcm2711-rpi-*.dtb 和 vc4-kms-v3d-pi4.dtbo

6. 插入記憶卡到電腦,用fdisk產生下列partition 
(假如記憶卡device node為sda)
# fdisk /dev/sda
  p1  128MB for boot : Do fdisk, set W95 FAT32(LBA) & Bootable type, mkfs.vfat
  p2 1024MB for /system : Do fdisk, new primary partition
  p3  128MB for /vendor : Do fdisk, new primary partition
  p4 remainings for /data : Do fdisk, mkfs.ext4, use -L option for mkfs.ext4

7. 處理記憶卡開機用partition
1) 格式化FAT32 partition
# mkfs.fat /dev/sda1
# mount /dev/sda1 /mnt

8. 拷貝需要的開機檔案
# cp device/arpi/rpi4/boot/* /mnt
# cp out/target/product/rpi4/ramdisk.img /mnt
# cp arpi-5.10/out/arpi-5.10/dist/Image.gz to /mnt
# cp arpi-5.10/out/arpi-5.10/dist/bcm2711-rpi-*.dtb /mnt
# cp arpi-5.10/out/arpi-5.10/dist/vc4-kms-v3d-pi4.dtbo /mnt/overlays/

9.更新system.img和vendor.img至記憶卡
# cd out/target/product/rpi4
# sudo dd if=system.img of=/dev/sda2 bs=1M
# sudo dd if=vendor.img of=/dev/sda3 bs=1M

10. 完成.  將記憶卡插入記憶卡開機

2022年5月18日 星期三

[Raspberry] Raspberry Pi OS Image Download

Raspberry Pi OS
 




[Android] Build busybox

1. 下載busybox source code
https://busybox.net/downloads/

2. 解壓縮
# tar jxvf busybox-1.35.0.tar.bz2

3. 設定成靜態編譯
# make menuconfig
然後選Settings  --->    [*] Build static binary (no shared libs) 
Exit後存檔
(補充: 在Android下編譯指令程式不是透過Android.mk時,都需靜態編譯)

4. 編譯
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
(請先確認cross compiler是甚麼版本,上面是arm的)
例如arm64是aarch64-linux-gnu-
例如mips是aarch64-linux-gnu-

5. 編譯完後可以看到busybox,你可以下file指令來確認
# file busybox
busybox: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=413e4eba5bb276bb28feae5785c10862f9c8d867, stripped


2022年5月17日 星期二

[Android] SELinux avc dennied

相信很多人都會遇到avc: denied 訊息
例如:
audit(0.0:67): avc: denied { write } for path="/dev/block/vold/93:96" dev="tmpfs" ino=/1263 scontext=u:r:kernel:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0

當初在處理selinux的avc: denied 訊息時有簡單寫一個程式 (程式下載) 來轉換  


轉換出來可以得到
allow kernel block_device:blk_file { write };

因為這是屬於kernel的
所以把上面轉換出來的加到device/{platform name}/common/sepolicy/kernel.te 即可


[Android] SELinux

在Android上實際會遇到Selinux問題,會在我們在開機程序上加入程式會被停止執行。
Selinux在這簡單說就需要讓開機程式有對應的權限設定。
在Android M之前,selinux是有disable,permissive和enforcing三種。
1. disabled : 停用模式,遇到有問題的程序會執行。
2. permissive : 寬容模式,遇到有問題的程序會執行,但會顯示警告提醒 (avc dennied)。
3. enforcing : 強制模式,遇到有問題的程序會停止。
之後就只剩下permissive和enforcing。

動態開關selinux指令
permissive mode:
# setenforce 0

enforcing mode:
# setenforce 1

預設開機都是enforcing,如果要開機預設permissive,可以到device/{platform name}/搜尋LOCAL_DEVICE_KERNEL_CMDLINE
然後加上
LOCAL_DEVICE_KERNEL_CMDLINE += androidboot.selinux=permissive

2022年5月16日 星期一

[Android] add_service permission denied issue

在Android M包了我們一個含有Bluetooth function的App
開機時出現了下面錯誤

09-01 13:12:36.103  2328  2328 E ServiceManager: add_service('NativeBluetoothRCService',65) uid=10002 - PERMISSION DENIED

本來以為是SELinux造成的
後來發現原來是權限上的的問題
最後加了下列後就可以順利執行

1. Android.mk
LOCAL_CERTIFICATE := platform

2. AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxxx.bluetoothrc"
    android:versionCode="1"
    android:versionName="1.0"
    android:sharedUserId="android.uid.system"   # <= Add the line
  >


[Android] Android 使用adb網路連線debug

1. DUT端:
可在Android下輸入:
stop adbd; setprop service.adb.tcp.port 5555; start adbd

或是在AOSP下的build/tools/buildinfo.sh加入
echo "service.adb.tcp.port=5555"

2. PC端
可以使用adb connect:
adb connect 192.168.1.58:5555

[Android] Android的映象檔格式 image format

1. Raw image:
一般原始格式image,檔案內容會完整存入到emmc中,可使用cat command導入到emmc,
例如: cat image.bin> /dev/mmcblk0p1.

2. Sparse image:
因為ext4的image size和partition大小需相同,也就是如果partition size是2G,那image szie也就為2G,因此例用img2simg tool可以將ext4檔案做壓縮動作讓映像檔案變小.一般system, cache, data都是用此格式.

以下是檔案互換的方式:
將sparse image轉換成raw image (ext4 )
system/core/libsparse/simg2img.c

將raw image (ext4 ) 轉換成sparse image
system/core/libsparse/img2simg.c

[Linux] Auto mount 自動掛載 usb disk & SD card

1. /etc/mdev.conf 加入
sd[a-z][0-9] 0:0 600 *(/etc/init.d/automount.sh $MDEV &)
mmcblk0p[0-9] 0:0 600 *(/etc/init.d/automount.sh $MDEV &)

2. 創建/etc/init.d/automount.sh
#!/bin/sh
MOUNT_PATH=""
MSG_PATH="/dev/ttyS0"

if [ $1 == "" ]; then
    echo "[AutoMount] automount.sh parameter is none" > $MSG_PATH
    exit 0
elif [ $1 == "mmcblk0p1" ]; then
    MOUNT_PATH="/mnt/sdcard"
else
    name=$1
    check=${name%[1-9]}
    vendor=`cat /sys/block/$check/device/vendor`
    if [ $vendor == "ATA" ]; then
       MOUNT_PATH="/mnt/hdd/"$name
    else
       MOUNT_PATH="/mnt/usb/"$name
    fi   
fi
echo "[AutoMount] mount path : $MOUNT_PATH" >> $MSG_PATH

FORMAT=`/sbin/fdisk -l | grep $1`
OLD_MOUNT_PATH=`mount | grep $MOUNT_PATH`

if [ "$OLD_MOUNT_PATH" == "" ]; then

    if [ ! -x $MOUNT_PATH ]; then
        mkdir -p $MOUNT_PATH
    fi 

    for token in $FORMAT
    do
        if [ $token == "FAT32" ]; then
            mount -t vfat /dev/$1 $MOUNT_PATH
            echo "[AutoMount] mount -t vfat /dev/$1 $MOUNT_PATH" > $MSG_PATH
        elif [ $token == "FAT16" ]; then
            mount -t vfat /dev/$1 $MOUNT_PATH
            echo "[AutoMount] mount -t vfat /dev/$1 $MOUNT_PATH" > $MSG_PATH
        elif [ $token == "HPFS/NTFS" ]; then
            if [ -f /usr/app/ntfs-3g ]; then
                echo "[AutoMount] /usr/app/ntfs-3g /dev/"$1" "$MOUNT_PATH > /var/log/automount/mount.log
                export LD_LIBRARY_PATH=/lib/:${LD_LIBRARY_PATH}
                /usr/app/ntfs-3g /dev/$1 $MOUNT_PATH
                echo "[AutoMount] /usr/app/ntfs-3g /dev/$1 $MOUNT_PATH" > $MSG_PATH
            else
                mount -t ntfs /dev/$1 $MOUNT_PATH
                echo "[AutoMount] mount -t ntfs /dev/$1 $MOUNT_PATH" > $MSG_PATH
            fi
        elif [ $token == "Linux" ]; then
                mount /dev/$1 $MOUNT_PATH
                echo "[AutoMount] mount /dev/$1 $MOUNT_PATH" > $MSG_PATH
        fi
    done
else
    umount $MOUNT_PATH
    echo "[AutoMount] umount "$MOUNT_PATH > $MSG_PATH
fi


[Linux Kernel] filesystem掛載driver – 以stat硬碟為例

1. 到kernel run makemenuconfig
Device Drivers =>
Serial ATA (prod) and Parallel ATA (experimental) drivers =>
<M> ATA device support
< >   Force spinup device
< >   AHCI SATA support
<M>   ServerWorks Frodo / Apple K2 SATA support
[ ]     Support for Native Command Queueing (EXPERIMENTAL)
(2)     Broadcom SATA host controller port number: 1 or 2

2. Build
make
make modules
make modules_install INSTALL_MOD_PATH=./_install

3. 將_install裡的檔案拷貝到filesystem

4. 到 busybox run makemenuconfig
Linux Module Utilities  =>
[ ] Simplified modutils
[*]   insmod
[*]   rmmod
[*]   lsmod
[*]     Pretty output
[*]   modprobe
[*]     Blacklist support
[*]   depmod
會多modprobe & depmod

5. modprobe sata_svw

6. 看到sata_svw 掛載成功

[Linux Porting] Porting SSHD & SFTP

1. zlib:
http://zlib.net/zlib-1.2.8.tar.gz

./configure
將Makefile裡的gcc改成arm-linux-gcc
make
拷貝libz.so*

2. openssl:
https://www.openssl.org/source/openssl-1.0.1h.tar.gz

./config no-asm shared
將Makefile裡的gcc改成arm-linux-gcc

make
拷貝libcrypto.so* & libssl.so*

3. openssh:
http://ftp5.usa.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-6.6p1.tar.gz

./configure CC=arm-linux-gnueabihf-gcc AR=gcc-arm-linux-gnueabihf-ar \
-host=arm-linux-gnueabihf -with-libs \
-with-zlib=../zlib-1.2.8/ \
-with-ssl-dir=../openssl-1.0.0/ \
-disable-etc-default-login 
make

4. 拷貝sftp ssh



[Linux Porting] PPPoE porting

1.Downlaod
http://ppp.samba.org/ppp/rp-pppoe-3.10.tar.gz
http://www.roaringpenguin.com/products/pppoe

2.Kernel
CONFIG_PPP=y
CONFIG_PPP_MULTILINK=y
CONFIG_PPP_FILTER=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
CONFIG_PPP_DEFLATE=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_MPPE=y
CONFIG_PPPOE=y
CONFIG_N_HDLC=y
CONFIG_UNIX98_PTYS=y


Refer:
http://tldp.org/HOWTO/PPP-HOWTO/kernel-configuration.html#AEN609
http://rsc.anu.edu.au/General/linux_ppp/ANU-PPP-HOWTO-4.html
http://www.gentoo.org/doc/zh_tw/handbook/handbook-ppc64.xml?part=1&chap=7


[Linux Porting] httpd執行CGI程式

1. Enable Busybox httpd
Networking Utilities=>[*] httpd

2. mkdir /www /www/cgi-bin

3. touch /etc/httpd.conf

4. run httpd => httpd -h /www/ -c /etc/httpd.conf

5. CGI程式:有二種方式,一個是用shell script,另一種是用c語言
5.1 shell script
存到/www/cgi-bin/cgi-test
#!/bin/sh
echo “Content-type: text/html"
echo “"
echo “<HTML><HEAD><TITLE>test</TITLE></HEAD>"
echo “<BODY>"
echo “<pre>"
ls
echo “"
echo “</pre>"
echo “</BODY></HTML>"

5.2 C language
#include <stdio.h>
main()
{
printf(“Content-type:text/html\n\n");
printf(“Hello,World!");
}


build成執行檔後將執行檔copy至/www/cgi-bin/cgi-test2

6. 用瀏覽器執行該二個cgi即可


[Linux] embedded system開機方式

 開機可以分為以下

1. initrd (from tftp)
此種是在build kernel時候也把rootfs一起build進來
所以只會有一個檔案
該kernel開機時候會順便把檔案裡的rootfs解壓縮到暫存記憶體
當然關機之後該裡面檔案就又都不見了
boot 192.168.1.254:awaysu/vmlinuz-initrd.img

2. kernel (from tftp) + rootfs (from nfs)
這是都從網路上做開機
一般在debug階段都會用此模式
ifconfig eth0 -auto
boot 192.168.1.254:awaysu/vmlinuz.img 'rootfstype=nfs root=/dev/nfs nfsroot=192.168.1.254:/home/awaysu/nfsrootfs/test rw ip=dhcp'

3. kernel (from storage) + rootfs (from storage)
這是都從flash或是emmc開機
一般在生產階段都會用此模式

ext4:
boot flash0.kernel: "root=/dev/mmcblk0p3 rootfstype=ext4 rw ip=0ff"
ubifs:
boot flash0.kernel: 'ubi.mtd=11 rootfstype=ubifs root=ubi0:rootfs rw ip=off'

[Linux Porting] 建立基本可開機的filesystem

1. 建立一個工作目錄nfs_root_work

2. 用vi建立一個mkroot.sh,並將下列複製到mkroot.sh裡存檔
echo “creatint rootfs dir……"
mkdir rootfs
cd rootfsecho “making dir : bin dev etc lib proc sbin sys usr"
mkdir bin dev etc lib proc sbin sys usr
# Don’t use mknod ,unless you run this Script as root !
# mknod -m 600 dev/console c 5 1
# mknod -m 666 dev/null c 1 3
echo “making dir : mnt tmp var"
mkdir mnt tmp var
chmod 1777 tmp
mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp
mkdir var/lib var/lock var/log var/run var/tmp
chmod 1777 var/tmp
echo “making dir : home root boot"
mkdir home root boot
cd dev
mknod -m 600 console c 5 1;mknod -m 666 null c 1 3
cd ..
cd ..
#=====================================================
echo “copy files from busybox …"
cp -af busybox-1.12.1/_install/* rootfs/
cp -af busybox-1.12.1/examples/bootfloppy/etc rootfs
#=====================================================
echo “copy files from etc …"
cp -af etc/* rootfs/etc
#=====================================================
echo “copy files from lib …"
cp -af lib/* rootfs/lib
#=====================================================
#echo “modify login file form TinyLogin …"
#cd tinylogin-1.4
#make PREFIX=../rootfs/ install
#cd ..
echo “filesystem make finish!"

3. 建立lib目錄,並把需要的library拷貝到該目錄裡

4. 建立etc目錄,並建立以下內容檔案
etc/fstab
proc /proc proc defaults 0 0
none /tmp ramfs defaults 0 0
mdev /dev ramfs defaults 0 0
sysfs /sys sysfs defaults 0 0

etc/inittab
::sysinit:/etc/init.d/rcS
::respawn:/bin/login root
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

etc/profile
# /etc/profile: system-wide .profile file for the Bourne shells
echoecho “Processing /etc/profile… "
# no-op
# Set search library path
echo “Set search library path in /etc/profile"
export LD_LIBRARY_PATH=/lib:/usr/lib
# Set user path
echo “Set user path in /etc/profile"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Set PS1
#注意:ash 除了SHELL變量外,支持\u、\h、\W、\$、\!、\n、\w 、\nnn(ASCII字符對應的八進制數)
#以及\e[xx;xxm (彩色特效)等等!
#而且前面還要多加一個 ‘\’!
echo “Set PS1 in /etc/profile"
export PS1="[$USER@Comtrend]#"
echo “Done"
echo

etc/passwd
root:x:0:0:root:/root:/bin/sh

etc/group
root:x:0:root

etc/shadow
root::13888:0:99999:7:::

etc/mdev.conf
(要有檔案但內容是空的)

etc/init.d/rcS
#! /bin/sh
echo “———-mount all"
/bin/mount -aecho “———-Starting mdev……"
#/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
echo “*********************************************************"
echo " Rootfs 2008/10/15″
echo " Love Linux ! ! ~Awaysu~ "
echo “********************************************************"

5. 下載busybox並解壓縮, http://www.busybox.net/downloads/
(注意版本名稱,mkroot.sh需相同)

6. 進入busybox目錄,使用vi修改Makefile
ARCH = mips
CROSS_COMPILE = mipsel-uclibc-

7. 執行make menuconfig
Mscellaneous Utilities
[ ] readahead
[ ] tasksetLinux System Utilities
[*] Support mounting NFS file systems
Networking Utilities
[ ] ether-wake
[*] Support RPC services
Linux Module Utilities
[ ] Simplified modutils
後面全都要勾
Miscellaneous Utilities
[ ] inotifyd

8. 建立busybox-1.12.1/arch/mips/Makefile
CFLAGS += -mips32 -mtune=mips32

9. 執行make,執行完後再執行make install,完成後會產生_install目錄,請刪除目錄裡的linuxrc檔案.

10. 完成後回到nfs_root_work執行mkroot.sh就會自動幫你建好filesystem.

11.拷貝lib檔案,一定要有
ld-uClibc-0.9.29.so
libm-0.9.29.so
libuClibc-0.9.29.so

以上我已經包成一個壓縮檔(下載),解開後執行到busybox目錄執行完後再執行make install,會到工作目錄執行make就會產生filesystem到rootfs,再用NFS作為filesystem root執行.

在Bootloader下執行
setenv -p STARTUP “boot -z -elf flash0.kernel1: ‘rootfstype=nfs root=/dev/nfs nfsroot=192.168.168.201:/home/awaysu/rootfs_work/rootfs ip=192.168.168.174 mem=128M'"

reference:
http://ccoolloorr.blogspot.com/2008/05/filesystem.html
http://wiki.jk2410.org/wiki/%E5%8A%A0%E5%85%A5Busybox

[Linux Porting] Auto configure

一般source code都會有Makefile然後我們直接去修改.
但是含有./configure的則是需要configure去產生Makefile

[root@linux bash-3.2]# 
./configure -host=arm-linux CC=arm-linux-gcc CXX=arm-linux-g++ LD=arm-linux-ld AR=arm-linux-ar AS=arm-linux-as 

[root@linux bash-3.2]#vi Makefile
修改DESTDIR = ./_install
(一定要修改,否則會蓋到原本的x86 的bash)

[root@linux bash-3.2]#make
[root@linux bash-3.2]#make install

[Linux Porting] Porting NTFS-3G

目前Linux還不支援NTF Swrite
所以關於source code部分免費的只能使用NTFS-3G

About NTFS-3G:
http://zh.wikipedia.org/zh-hk/NTFS-3G

Download page:
http://www.tuxera.com/community/ntfs-3g-download/

Download:
http://tuxera.com/opensource/ntfs-3g-2010.3.6.tgz

1. Kernel:
File systems —>
<*> Filesystem in Userspace support

2. Build:

tar zxvf ntfs-3g-2010.3.6.tgz
cd ntfs-3g-2010.3.6


3. 產生Makefile
CC=mipsel-linux-gcc CXX=mipsel-linux-g++ LD=mipsel-linux-ld AR=mipsel-linux-ar AS=mipsel-linux-as RANLIB=mipsel-linux-ranlib NM=mipsel-linux-nm STRIP=mipsel-linux-strip CFLAGS="-mabi=32 -DL_ENDIAN -DTERMIO -O3 -g -Wall" host_os=linux-gnu host=mipsel-mips-linux-gnu ./configure –target=mipsel-unknown-linux-gnu –host=mipsel-unknown-linux-gnu –build=i686-pc-linux-gnu –prefix=

4. Modify file ./include/ntfs-3g/ntfstime.h
#if !defined __timespec_defined &&            \
((defined _TIME_H &&               \
(defined __USE_POSIX199309 || defined __USE_MISC)) ||   \
defined __need_timespec)
# define __timespec_defined   1# include    /* This defines __time_t for us.  *//* POSIX.1b structure for a time value.  This is like a `struct timeval’ but
has nanoseconds instead of microseconds.  */
struct timespec
{
__time_t tv_sec;      /* Seconds.  */
long int tv_nsec;      /* Nanoseconds.  */
};#endif /* timespec not defined and or need timespec.  */

5. Modify file ./src/ntfs-3g.c
//      #error “No known timespec member in struct stat!"
/* No known timespec member in struct stat */
struct timespec ts;
ts = ntfs2timespec(ni->last_access_time);
stbuf->st_atime = ts.tv_sec;
//stbuf->st_atimensec = ts.tv_nsec;
ts = ntfs2timespec(ni->last_mft_change_time);
stbuf->st_ctime = ts.tv_sec;
//stbuf->st_ctimensec = ts.tv_nsec;
ts = ntfs2timespec(ni->last_data_change_time);
stbuf->st_mtime = ts.tv_sec;
//stbuf->st_mtimensec = ts.tv_nsec;
#endif

6. make

7. 
程式產生在src/.libs/
library產生libntfs-3g/.libs

8. command:
./ntfs-3g /dev/sda1 /mnt/





[Linux Porting] DHCP Client

1. busybox內建有DHCP Client的功能

2. /etc/udhcpc-script
#!/bin/sh
# udhcpc script edited by Tim Riker <Tim@Rikers.org>
[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
RESOLV_CONF="/etc/resolv.conf"
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
[ -n "$subnet" ] && NETMASK="netmask $subnet"
case "$1" in
    deconfig)
        /sbin/ifconfig $interface 0.0.0.0
        ;;
    renew|bound)
        /sbin/ifconfig $interface $ip $BROADCAST $NETMASK
        if [ -n "$router" ] ; then
            echo "deleting routers"
            while route del default gw 0.0.0.0 dev $interface ; do
            :
            done
            for i in $router ; do
                route add default gw $i dev $interface
            done
        fi
        echo -n > $RESOLV_CONF
        [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
        for i in $dns ; do
            echo adding dns $i
            echo nameserver $i >> $RESOLV_CONF
        done
        ;;
esac
exit 0

3. /etc/resolv.conf
nameserver 168.95.1.1

4. 開機時執行:
/sbin/ifconfig lo 127.0.0.1 up
/sbin/udhcpc -i eth0 -s /etc/udhcpc-script

參考:
http://sites.google.com/site/koukailinuxdev/build-usb-linux/create_initrd


[Linux Porting] 小而巧的ssh server (sshd)

本來都是用openssh
不過檔案滿大的
後來發現原來有這個小而巧的sshd server

1.下載:
http://matt.ucc.asn.au/dropbear/dropbear.html

2.參考[Linux] 移植openssh(ssh server)到MIPS板子上並免密碼 build zlib和openssl

3.解壓縮dropbear,並run it:
CC=mipsel-linux-gcc CXX=mipsel-linux-g++ LD=mipsel-linux-gcc AR=mipsel-linux-ar AS=mipsel-linux-as RANLIB=mipsel-linux-ranlib NM=mipsel-linux-nm STRIP=mipsel-linux-strip CFLAGS="-mabi=32 -DL_ENDIAN -DTERMIO -O3 -g -Wall" host_os=linux-gnu host=mipsel-mips-linux-gnu ./configure –target=mipsel-unknown-linux-gnu –host=mipsel-unknown-linux-gnu –build=i686-pc-linux-gnu –prefix= –with-zlib={zlib的include path}

4.build:
make

5.copy dropbear & dropbearkey to 板子,並run
dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key

否則會出現
[194] Feb 24 19:58:34 Failed reading ‘/etc/dropbear/dropbear_rsa_host_key’, disabling RSA
[194] Feb 24 19:58:34 Failed reading ‘/etc/dropbear/dropbear_dss_host_key’, disabling DSS
[194] Feb 24 19:58:34 premature exit: No hostkeys available

6.run dropbear



[HTML] 我常用的HTML and Javascript語法

1.預讀圖片

var arraryKeyImg = new Array("img/kb_bq.jpg", "img/kb_bw.jpg", "img/kb_be.jpg");
var loadImg = new Array();
for (i = 0; i != arraryKeyImg.length; i++)
{
    loadImg[i] = new Image();
    loadImg[i].src = arraryKeyImg[i];
}


2.利用陣列去中控制

var arraryKeyImgID = new Array("key_00", "key_01", "key_02");
for (i = 0; i != 10; i++)
{
    document.getElementById(arraryKeyImgID[i]).style.top= 100;    
}

<img border="0" src="img/kb_bq.jpg" id="key_00" style="position:absolute">
<img border="0" src="img/kb_bw.jpg" id="key_01" style="position:absolute">
<img border="0" src="img/kb_be.jpg" id="key_02" style="position:absolute">


3.和php一樣抓取參數

function getValue(sArgName) {
    var sHref = window.location.href;
    var args = sHref.split("?");
    var retval = "";

    if (args[0] == sHref) {
        return retval;
    }
    var str = args[1];
    args = str.split("&");
    for (var i = 0; i < args.length; i++) {
        str = args[i];
        var arg = str.split("=");
        if (arg.length <= 1) continue;
        if (arg[0] == sArgName) retval = arg[1];
    }
    return retval;
}


4.設置timer

setTimeout("move();", 1000);


5.讀取網頁時做初始
<body onLoad = "initialize()">


6.動態產生
ShowText1.innerHTML = "<center>";
<div id="ShowText1" style="color: #ffffff; font-size: 16pt; margin-top: 0; margin-bottom: 0">



7.table不稱開
<table style="word-break:break-all>


[Linux] 產生patch

 方法1:
1. 使用diff,a目錄為未修改前,b目錄為修改後:
產生patch:
diff -Naur a b > test.patch
使用patch:
patch -p1 < test.patch

2. 使用git:
產生patch:
(1) 修改前
git init .
git add .
git commit -m " First drop"
(2) 修改完後
git add .
git commit -m "do test patch"
git format-patch HEAD^ --stdout > test.patch

使用patch:
git apply test.patch

[Linux] ffmpeg command

From : http://diyland.biz/?opt=detail&topic=68&id=15480

1. 把影像檔案轉換成avi格式
ffmpeg -i filename.flv -f avi -vcodec libxvid -acodec libmp3lame -ar 22050 filename.avi
參數說明:
-i : 指輸入的檔案名稱,只要系統中有相對應的codec,就能使用多種格式。
-f : 強迫輸出的檔案格式。
-vcodec : 指定影像的編碼格式,這裡的libxvid指的是一般所說的xvid。
-acodec : 指定聲音的編碼格式,libmp3lame就是常用的mp3格式。
-ar : 指定聲音的取樣頻率,一般預設是44100。(因為我是用在手機上,所以設比較低。)

2. 把影像檔案轉換成3gp格式
ffmpeg -i filename.avi -s qcif -vcodec h263 -acodec libfaac -ac 1 -ar 8000 -r 25 -ab 32 filename.3gp
參數說明:
-i : 指輸入的檔案名稱。
-s : 畫面的解析度。qcif指的是176×144,直接輸入長和寬也可以,格式是 wxh。
-vcodec : 指定影像的編碼格式。
-acodec : 指定聲音的編碼格式,libfaac就是指aac格式。
-ac : 設定聲音的聲道數。1指是的單聲道。
-ar : 指定聲音的取樣頻率。
-r : 設定fps。
-ab : 指定聲音的bitrate。

3. 把影像檔轉換成flv格式
ffmpeg -i filename.mpg -ab 56 -ar 22050 -b 500 -r 15 filename.flv
參數說明:
-i : 指輸入的檔案名稱。
-ab : 指定聲音的bitrate。
-ar : 指定聲音的取樣頻率。
-b : 指定影像的bitrate
-r : 設定fps。

4. 將聲音檔案轉成mp3
ffmpeg -i filename.wav -acodec libmp3lame -ar 44100 -ab 128k filename.mp3
參數說明:
-i : 指輸入的檔案名稱。
-ar : 指定聲音的取樣頻率。
-ab : 指定聲音的bitrate。
-acodec : 指定聲音的編碼格式,libmp3lame就是常用的mp3格式。如果輸出的檔案有指定mp3的話,其實這裡省略沒關係。
如果覺得原本的聲音檔音量太小的話,可以再加一個 -vol 200 的參數,會讓輸出的mp3音量變成200%,就兩倍大聲。200是百分比,可以隨意調整的。

[Linux] UBIFS filesystem

最近換了一顆比較大的nand flash,沒想到以前的指令無法使用,看起來是因為page size過大
mkfs.ubifs -r ./rootfs -m 8KiB -e 2080768 -c 200 -o rootfs.ubifs
Error: too large LEB size 2080768


這一顆nand flash的info
nand: Micron MT29F32G08CBADAWP
nand: 4096MiB, MLC, page size: 8192, OOB size: 744
brcmnand f0442800.nand: 4096MiB total, 2048KiB blocks, 8KiB pages, 46B OOB, 8-bit, BCH-40 (1KiB sector)


Organization
– Page size x8: 8936 bytes (8192 + 744 bytes)
– Block size: 256 pages (2048K + 186K bytes)
– Plane size: 2 planes x 1064 blocks per plane
– Device size: 32Gb: 2128 blocks


Logical eraseblock size: 2080768 bytes, 2.0 MiB
Total amount of logical eraseblocks: 243 (505626624 bytes, 482.2 MiB)
Amount of available logical eraseblocks: 0 (0 bytes)
Maximum count of volumes 128
Count of bad physical eraseblocks: 2
Count of reserved physical eraseblocks: 38
Current maximum erase counter value: 2
Minimum input/output unit size: 8192 bytes
Character device major/minor: 249:0
Present volumes: 0


最後找到原因,因為舊版linux的ubifs不支援,需要用新版的linux,最後在fedora v21可以執行
sudo mkfs.ubifs -r ./rootfs -m 8KiB -e 2080768 -c 200 -o rootfs.ubifs
sudo ubinize -o mnt/rootfs.ubifs.img -m 8KiB -p 2048KiB -s 8KiB ubinize.cfg


ubinize.cfg:
[ubifs]
mode=ubi
image=rootfs.ubifs
vol_id=0
vol_size=400MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize


在板子上指令
ubiformat /dev/mtd0 -s 8192 -f rootfs.ubifs.img
ubiattach /dev/ubi_ctrl -m 0
mount -t ubifs ubi0_0 /tmp 

[DOS] iperf command

Server:
:loop
iperf -s
goto loop

Client:
:loop
iperf3 -c {ip} -t 30 -i 3 -u -b 100M
goto loop

[Linux] VLC auto play command

 Linux command:
/usr/bin/vlc -v ./DTV2.ts –sout udp:225.1.1.71:30120 –sout-all –ttl 3 –sout-keep –loop &


Windows command:
start “Channel 01″ “C:\Program Files\VideoLAN\VLC\vlc.exe" “D:\demo\out_clip_cut.ts" –sout=#udp{dst=225.

[Linux] 測速隨身碟速度 test usb disk throughput

測速隨身碟速度:
# 強制 kernel 清理快取
echo 1 > /proc/sys/vm/drop_caches

# Write
echo "dd if=/dev/zero of=/mnt/usb/sda1/test.bin bs=1024 count=716800"
date;dd if=/dev/zero of=/mnt/usb/sda1/test.bin bs=1024 count=716800;sync;date

echo "================================================================="

# 強制 kernel 清理快取
echo 1 > /proc/sys/vm/drop_caches

# Read
echo "dd if=/mnt/usb/sda1/test.bin of=/dev/null bs=1024 count=716800"
date;dd if=/mnt/usb/sda1/test.bin of=/dev/null bs=1024 count=716800;sync;date

[Linux] Makefile

 一般我們在linux下編譯程式碼變為執行檔
是透過gcc的指令透過參數來產生
gcc -o hello.out -Wall -I./ main.c

由於在複雜的多個程式碼裡只利用gcc指令會變很複雜
所以就有了Makefile的檔案來協助我們來做編譯
以下是二個簡單的Makefile範例
包含了一個執行檔
和另一個執行檔呼叫函式庫Makefile範例

1. 程式的Makefile

main.c
#include "stdio.h"

int main(int argc, char *argv[])
{
    printf("Hello World!\n");
    return 0;
}
Makefile
CC = gcc
INCLUDE = ./
CFLAG = -Wall
SRC = main.c
EXEC_FILE = hello.out

make_api:
    $(CC) -o $(EXEC_FILE) $(CFLAG) -I$(INCLUDE) $(SRC)

clean:
    rm -f *.o $(EXEC_FILE)

要注意的是$(CC)前是Tab鍵而非空格


2. Shared Library函式庫的Makefile
libtest.h
extern void ShowHelloWorld();
void ShowHelloWorld();
libtest.c
#include "libtest.h"
#include "stdio.h"

void ShowHelloWorld()
{
        printf("Hello World!\n");
}
main.c
#include "libtest.h"

int main(int argc, char *argv[])
{
    ShowHelloWorld();
    return 0;
}
Makefile
CC = gcc
SRC = ./main.c
INCLUDE = -I./
CFLAG = -Wall -ltest -L./
EXEC_FILE = ./hello.out

LIB = ./libtest.c
LIB_CFLAG = -Wall -fPIC -shared
LIB_NAME = ./libtest.so

all:make_lib make_api

make_api:$(SRC)
        $(CC) -o $(EXEC_FILE) $(CFLAG) $(INCLUDE) $(LIB_NAME) $(SRC)

make_lib:$(LIB)
        $(CC) -o $(LIB_NAME) $(LIB_CFLAG) $(LIB)

clean:
        rm -f *.so $(EXEC_FILE)

因為要編譯函式庫,所以CFLAG參數要多一個-shared
另外執行檔要連結函式庫,所以要用到大小寫L的參數
大寫L是表示到時候執行連結函式庫的路徑 (大部分程式的連結都是在/lib下)
小寫l則是lib之後去除.so的檔案名稱, 例如libtest.so就是取test

[Shell Script] 檢查檔案或目錄是否存在

檢查目錄是否存在
FOLDER=abc
if [ -x $FOLDER ]
then
  echo "$FOLDER EXIST"
else
  echo "$FOLDER NOT EXIST"
fi


檢查檔案是否存在

FILE=abc
if [ -f $FILE ]
then
  echo "$FILE EXIST"
else
  echo "$FILE NOT EXIST"
fi


[Linux Kernel] Kernel debug – OOPS

每次kernel掛掉總是會出現一堆16進制的東西
但我都沒有認真看過
因為….真的看不懂
不過上星期上完課之後
終於知道這些數字代表什麼
例如main.c裡面有個faulty_write function, 故意讓0的位置寫0
ssize_t faulty_write (struct file *filp, const char __user *buf, size_t count,
loff_t *pos)
{
  /* make a simple fault by dereferencing a NULL pointer */
  *(int *)0 = 0;
  return 0;
}

當我去執行的時候kernel掛掉
$ echo “1″ > /dev/aaa
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c3a70000
[00000000] *pgd=33a7e031, *pte=00000000, *ppte=00000000
Internal error: Oops: 817 [#3]
Modules linked in: faulty
CPU: 0 Tainted: G D (2.6.29.2 #2)
PC is at faulty_write+0x10/0x18 [faulty]
LR is at vfs_write+0xc4/0x148
pc : [<bf00009c>] lr : [<c00a5f6c>] psr: a0000013
sp : c3a69f44 ip : c3a69f54 fp : c3a69f50
r10: 400d0948 r9 : c3a68000 r8 : 00000000
r7 : 00000002 r6 : c3a69f78 r5 : 400d3704 r4 : c382cea0
r3 : c3a69f78 r2 : 00000002 r1 : 400d3704 r0 : 00000000
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 0000717f Table: 33a70000 DAC: 00000015
Process echo (pid: 882, stack limit = 0xc3a68260)
Stack: (0xc3a69f44 to 0xc3a6a000)
9f40: c3a69f74 c3a69f54 c00a5f6c bf00009c 00000000 c382cec0 c382cea0
9f60: c3a69f78 00000000 c3a69fa4 c3a69f78 c00a60b0 c00a5eb8 00000000 00000000
9f80: 00000000 400d1188 00000002 400d3704 00000004 c0035fa4 00000000 c3a69fa8
9fa0: c0035e00 c00a6074 400d1188 00000002 00000001 400d3704 00000002 4009f9b4
9fc0: 400d1188 00000002 400d3704 00000002 000a8374 00000002 400d0948 00000000
9fe0: 400a491c bec33d74 4009f008 4008accc 20000010 00000001 fffff7f7 fff5ffdf
Backtrace:
[<bf00008c>] (faulty_write+0x0/0x18 [faulty]) from [<c00a5f6c>] (vfs_write+0xc4/0x148)
[<c00a5ea8>] (vfs_write+0x0/0x148) from [<c00a60b0>] (sys_write+0x4c/0x74)
r7:00000000 r6:c3a69f78 r5:c382cea0 r4:c382cec0
[<c00a6064>] (sys_write+0x0/0x74) from [<c0035e00>] (ret_fast_syscall+0x0/0x2c)
r8:c0035fa4 r7:00000004 r6:400d3704 r5:00000002 r4:400d1188
Code: e1a0c00d e92dd800 e24cb004 e3a00000 (e5800000)
—[ end trace 0f24d785ce6e74e6 ]—
Segmentation fault
/ $

注意看裡面
因為instruction length是4 byte
faulty_write+0x10/0x18 = > 4 / 6 (6行的第四行錯)
在位置e3a00000 的地方
PC is at faulty_write+0x10/0x18 [faulty]
Code: e1a0c00d e92dd800 e24cb004 e3a00000 (e5800000)
執行mipsel-linux-objdump -S main.o 可以看到組語和程式碼的對應
ssize_t faulty_write (struct file *filp, const char __user *buf, size_t count,
loff_t *pos)
{
8c:     e1a0c00d mov ip, sp
90:     e92dd800 stmdb sp!, {fp, ip, lr, pc}
94:     e24cb004 sub fp, ip, #4 ; 0x4
/* make a simple fault by dereferencing a NULL pointer */
*(int *)0 = 0;
98:     e3a00000 mov r0, #0 ; 0x0
9c:     e5800000 str r0, [r0]
return 0;
}

所以這樣就可以找到哪一個錯誤!



[C/C++] Socket 範例

說明:
Socket Server/Client範例

Code:

Server=>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

int socket_server(int port)
{
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr; 
    char buffer[1024];

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));   

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(port); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
    listen(listenfd, 10); 
    connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 
    
    memset(buffer, '0', sizeof(buffer)); 
    strcpy(buffer, "I get server message!");
    
    if (write(connfd, buffer, strlen(buffer)) < 0)
    {
        printf("\n Error : Write Failed \n");
        return 1;
    } 
    
    memset(buffer, '\0', sizeof(buffer)); 
    
    if (read(connfd, buffer, sizeof(buffer)) < 0)
    {
        printf("\n Error : Read Failed \n");
        return 1;
    } 
    
    printf("buffer : [%s]\n\n", buffer);
    close(connfd);
    return 0;
}

int main(int argc, char *argv[])
{
    socket_server(5000);
    return 0;
}
Client=>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 

int socket_client(char *ip, int port)
{
    int sockfd = 0;
    char buffer[1024];
    struct sockaddr_in serv_addr; 

    memset(buffer, '\0',sizeof(buffer));
    
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&serv_addr, '0', sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port); 

    if(inet_pton(AF_INET, ip, &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
       printf("\n Error : Connect Failed \n");
       return 1;
    } 

    if (read(sockfd, buffer, sizeof(buffer)) < 0)
    {
        printf("\n Error : Read Failed \n");
        return 1;
    } 
    
    printf("buffer : [%s]\n\n", buffer);

    sleep(1);
    
    memset(buffer, '\0', sizeof(buffer));
    strcpy(buffer, "I get client message!");
    
    if (write(sockfd, buffer, strlen(buffer)) < 0) 
    {
        printf("\n Error : Write Failed \n");
        return 1;
    } 
    
    close(sockfd);
    
    return 0;
}

int main(int argc, char *argv[])
{
    socket_client("127.0.0.1", 5000);
    
    return 0;
}

Result:
buffer : [I get server message!]
buffer : [I get client message!]

[C/C++] Signal範例

說明:
Signal範例

Code:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

static int loop = 1;

void alarm_handler(int a)
{
    printf("Alarm!!!\n");
    loop = 0;
}

int main(int argc, char *argv[])
{
    signal(SIGALRM, alarm_handler);
    
    /* you also can run via "killall -14 xxx" command */
    alarm(9);
    
    while(loop)
    {
    }
    
    printf("Program exit!!!\n");
    
    return 0;
}

Result:
Alarm!!!
Program exit!!!

[C/C++] 存取系統時間

說明:
存取系統時間

Code:
#include <stdio.h>
#include <time.h>
#include <string.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

void get_time_fun(char *p_time)
{
    memset(p_time, '\0', strlen(p_time));
    struct tm *tm_ptr;
    time_t the_time;
    time(&the_time);
    tm_ptr = localtime(&the_time);
    sprintf(p_time, "%02d/%02d/%02d,%02d:%02d:%02d", 
        tm_ptr->tm_year + 1900, 
        tm_ptr->tm_mon + 1, 
        tm_ptr->tm_mday, 
        tm_ptr->tm_hour, 
        tm_ptr->tm_min, 
        tm_ptr->tm_sec);        
}
                                                           
BOOL set_time_fun(char *buffertime)                             
{
    struct tm tm_per;
    time_t time1; 
    int year,month,day,hour,min,sec,flag,len;
    year = month = day = hour = min = sec = flag = len = 0;

    len = strlen(buffertime);
    if(strlen(buffertime) != 19){
        return FALSE;
    }
    
    flag = sscanf(buffertime,"%d:%d:%d,%d:%d:%d", 
                &year, 
                &month, 
                &day, 
                &hour, 
                &min, 
                &sec);

    if(flag != 6){
        flag = -1;
    }else{
        flag = 0;
    }
    
    if(year < 1)
        flag = -1;
    if((month < 1) || (month > 12))
        flag = -1;
    if((day < 1) || (day > 31))
         flag = -1;
    if((hour < 0) || (hour > 23))
         flag = -1;
    if((min < 0) || (min > 59))
         flag = -1;
    if((sec < 0) || (sec > 59))
         flag = -1;
    
    if(flag < 0){
        return FALSE;
    }
    
    tm_per.tm_year     = year - 1900;
    tm_per.tm_mon    = month - 1;
    tm_per.tm_mday    = day;
    tm_per.tm_hour    = hour;
    tm_per.tm_min    = min;
    tm_per.tm_sec    = sec;    
    
    time1=mktime(&tm_per);
    printf("mktime=%ld\n",time1);
    
    if(time1 > 0){
        
#if __GLIBC_MINOR__ == 31
        struct timespec res;
        res.tv_sec = time1;
        
       if (clock_settime(CLOCK_REALTIME, &res) ==0)
#else
        if(stime(&time1)==0)
#endif
        {
            return TRUE;
        }else{
            return FALSE;
        }
    }else{
        return FALSE;
    }
}      

int main(int argc, char *argv[])
{
    char p_time[MAX_SHORT_LENGTH];
    
    get_time_fun(p_time);
    printf("Time: %s\n", p_time);
    
    set_time_fun(p_time);
    
    return 0;
}

Result:
Time: 2022/05/16,15:14:42

[C/C++] 執行參數解析範例

說明:

Code:
#include <stdio.h>
#include <unistd.h>

void process_options(int argc, char *argv[])
{
    int oc; 
    char *tmp;

    while((oc = getopt(argc, argv, "ngl:")) != -1)
    {
        switch(oc)
        {
            case 'n':
                printf("My name is Lyong.\n");
                break;
             case 'g':
                printf("Her name is Xxiong.\n");
                break;
            case 'l':
                tmp = optarg;
                printf("Our love is %s\n", tmp);
                break;
            default:
                printf("arguments error!\n");
                break;
        }
    }
}

int main(int argc, char *argv[])
{
    process_options(argc, argv);
    
    return 0;
}

Result:
main_parameter_sample -n -l 99
My name is Lyong.
Our love is 99

2022年5月15日 星期日

[C/C++] 存檔

說明:
存檔

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
       
BOOL save_file_fun(char *filename, char *buffer)
{
    int        fd = 0;
    int     length = 0;
    BOOL    ret = FALSE;

    length = strlen(buffer);
    
    if ( (fd = open( filename,
            O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) > 0 )
    {
        if ( write(fd, buffer, length) == length )
            ret = TRUE;
        else
            printf("[ERROR] write %s failed!\n", filename);

        if (fd) 
            close(fd);
        
        sync();
    }
    else
        printf("[ERROR] cannot creat %s!\n", filename);

    return ret;
}       

int main(int argc, char *argv[])
{
    char save[] = "abcde\n12345\n";
    save_file_fun("./save.txt", save);
    
    return 0;
}

Result:
會看見save.txt檔案

[C/C++] 一行一行讀檔

說明:
一行一行讀檔

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

BOOL load_file_fun(char *filename, char **p_content)
{
    int fd = -1;    
    int totalsize = 0;
    int readsize = 0;
    char buffer[MAX_SHORT_LENGTH];
    BOOL ret = FALSE;
    
    if ( (fd = open((char *)filename, O_RDONLY)) > 0 )
    {
        totalsize = 0;
        while( (readsize = read(fd, buffer, MAX_SHORT_LENGTH)) > 0)
            totalsize += readsize;

        if (totalsize <= 0)
        {
            printf("[ERROR] %s file size is wrong!\n", filename);
            return ret;
        }    
        
        if (lseek(fd, 0, SEEK_SET) == -1)
        {
            printf("[ERROR] %s can't seek!\n", filename);
            return ret;
        }
        
        *p_content = (char*)malloc( ( totalsize + 1) * sizeof(char));
        memset(*p_content, '\0', totalsize + 1);

        if (*p_content)
        {
            if(read(fd, *p_content, totalsize) > 0 )
            {
                ret = TRUE;
            }
            else
            {
                printf("[ERROR] %s can't read!\n", filename);
                free(*p_content);
            }

            close(fd);
        }
    }
    else
        printf("[ERROR] Open %s fail!\n", filename);

    return ret;    
}

BOOL load_file_by_line_fun(char *file)
{
    char *p_content = NULL;
    char *p_tmp = NULL;
    char *p_feed = NULL;
    char *p_line = NULL;
    int len = 0;
    BOOL ret = FALSE;

    if (load_file_fun(file, &p_content) == TRUE)
    {
        p_tmp = p_content;

        while((p_feed = strpbrk(p_tmp, "\n")))
        {
            len = p_feed - p_tmp;
            p_line = (char*)malloc(len + 1);
            memset(p_line, '\0', len + 1);
            strncpy(p_line, p_tmp, len);
            printf("p_line : %s\n", p_line);
            free(p_line);
            p_tmp = p_feed + 1;
        }
        ret = TRUE;
    }

    if (p_content)
        free(p_content);
 
    return ret;
}

int main(int argc, char *argv[])
{

    load_file_by_line_fun("/etc/exports");
    
    return 0;
}

Result:
p_line : # /etc/exports: the access control list for filesystems which may be exported
p_line : #              to NFS clients.  See exports(5).
p_line : #
p_line : # Example for NFSv2 and NFSv3:
p_line : # /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
p_line : #
p_line : # Example for NFSv4:
p_line : # /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
p_line : # /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
p_line : #
p_line : /tftpboot       *(insecure,rw,no_subtree_check,no_root_squash,no_all_squash)
p_line : /SOURCE         *(insecure,rw,no_subtree_check,no_root_squash,no_all_squash)


[C/C++] 讀檔

說明:
讀檔

Code:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

BOOL load_file_fun(char *filename, char **p_content)
{
    int fd = -1;    
    int totalsize = 0;
    int readsize = 0;
    char buffer[MAX_SHORT_LENGTH];
    BOOL ret = FALSE;
    
    if ( (fd = open((char *)filename, O_RDONLY)) > 0 )
    {
        totalsize = 0;
        while( (readsize = read(fd, buffer, MAX_SHORT_LENGTH)) > 0)
            totalsize += readsize;

        if (totalsize <= 0)
        {
            printf("[ERROR] %s file size is wrong!\n", filename);
            return ret;
        }    
        
        if (lseek(fd, 0, SEEK_SET) == -1)
        {
            printf("[ERROR] %s can't seek!\n", filename);
            return ret;
        }
        
        *p_content = (char*)malloc( ( totalsize + 1) * sizeof(char));
        memset(*p_content, '\0', totalsize + 1);

        if (*p_content)
        {
            if(read(fd, *p_content, totalsize) > 0 )
            {
                ret = TRUE;
            }
            else
            {
                printf("[ERROR] %s can't read!\n", filename);
                free(*p_content);
            }

            close(fd);
        }
    }
    else
        printf("[ERROR] Open %s fail!\n", filename);

    return ret;    
}

int main(int argc, char *argv[])
{
    char *p_content = NULL;
    
    if (load_file_fun("/etc/exports", &p_content) == TRUE)
    {
        printf("%s\n", p_content);
        
        if (p_content)
            free(p_content);
    }
    
    return 0;
}

Result:
# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#
/tftpboot       *(insecure,rw,no_subtree_check,no_root_squash,no_all_squash)
/SOURCE         *(insecure,rw,no_subtree_check,no_root_squash,no_all_squash)

[C/C++] 檢查檔案或資料夾是否存在

說明:
檢查檔案或資料夾是否存在

Code:
#include <stdio.h>
#include <unistd.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

BOOL is_file_exist_fun(char *filename)
{
    int bRet = FALSE;
    FILE* fp = fopen(filename, "r");
    if (fp) 
    {
        bRet = TRUE;
        fclose(fp);
    }
    return bRet;
}

BOOL is_folder_exist_fun(char *foldername)
{
    BOOL bRet = FALSE;
    int ret = chdir(foldername);
    if (ret == 0)
        bRet = TRUE;
    return bRet;
}

int main(int argc, char *argv[])
{
    BOOL ret = is_file_exist_fun("/etc/exports");
    printf("/etc/exports : %s\n", ret==TRUE?"Exist":"Not Exist");
    
    ret = is_folder_exist_fun("/etc/");
    printf("/etc/ : %s\n", ret==TRUE?"Exist":"Not Exist");    
    return 0;
}

Result:
/etc/exports : Exist
/etc/ : Exist

[C/C++] 16進制字串轉數值

說明:
16進制字串轉數值

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int strtonum(char *p_input)
{
    char *pTmp;
    if ( *p_input == '0' )
    {
        if ( *(p_input + 1) == 'x' || 
                 *(p_input + 1) == 'X' )
        {
            pTmp = p_input + 2;
            return strtoll( pTmp, NULL, 16 );
        }
    }
    
    return strtoll( p_input, NULL, 10 );
}

int main(int argc, char *argv[])
{
    char val[] = "0x30";
    int ret = strtonum(val);
    printf("%s = 0x%x\n", val, ret);
    
    return 0;
}


Result:
0x30 = 0x30

[C/C++] 程序號碼(process id)

說明:
程序號碼(process id)

Code:
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>

#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

unsigned int get_process_id_fun(char *app_name)
{
    DIR *dir_p = NULL;
    struct dirent *dir_entry_p = NULL;
    char dir_name[MAX_SHORT_LENGTH];
    char target_name[MAX_SHORT_LENGTH];
    char exe_link[MAX_SHORT_LENGTH];
    int target_result = -1;
    int result = -1;

    dir_p = opendir("/proc/");
    while(NULL != (dir_entry_p = readdir(dir_p))) 
    { 
        if (strspn(dir_entry_p->d_name, "0123456789") 
                == strlen(dir_entry_p->d_name)) 
        {
            strcpy(dir_name, "/proc/");
            strcat(dir_name, dir_entry_p->d_name);
            strcat(dir_name, "/"); 
            exe_link[0] = 0;
            strcat(exe_link, dir_name);
            strcat(exe_link, "exe");  
            target_result = readlink(exe_link, 
                target_name, sizeof(target_name)-1); 
            
            if (target_result > 0) 
            {
                target_name[target_result] = 0;
                if (strstr(target_name, app_name) != NULL)
                {                            
                    result = atoi(dir_entry_p->d_name);
                    //printf("getProcessID(%s) :Found. id = %d\n", app_name, result);
                    closedir(dir_p);
                    return result;
                }
            }
        }
    }
    closedir(dir_p);
    return result;
}

int main(int argc, char *argv[])
{
    printf("smbd id is %d\n", get_process_id_fun("smbd"));
    return 0;
}



Result:
smbd id is 3895415

[C/C++] 網路IP和MAC位置

說明:
網路IP和MAC位置

Code:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netdevice.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

BOOL get_mac_address_fun(char *name, char *mac)
{
    BOOL ret = FALSE;
    struct ifreq s;
    BOOL fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);

    strcpy(s.ifr_name, name);
    if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) 
    {
        sprintf(mac, "%02x-%02x-%02x-%02x-%02x-%02x",
        (unsigned char) s.ifr_addr.sa_data[0],
        (unsigned char) s.ifr_addr.sa_data[1],
        (unsigned char) s.ifr_addr.sa_data[2],
        (unsigned char) s.ifr_addr.sa_data[3],
        (unsigned char) s.ifr_addr.sa_data[4],
        (unsigned char) s.ifr_addr.sa_data[5]);
        ret = TRUE;
    }

    return ret;
}

BOOL get_ip_address_fun(char *name, char *ip)
{
    int fd;
    BOOL ret = FALSE;
    struct ifreq ifr;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd)
    {
        ifr.ifr_addr.sa_family = AF_INET;
        strncpy(ifr.ifr_name, name, IFNAMSIZ-1);
        ioctl(fd, SIOCGIFADDR, &ifr);
        strcpy(ip, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
        close(fd);
        ret = TRUE;
    }
    
    return ret;
}

int main(int argc, char *argv[])
{
    char ip[MAX_SHORT_LENGTH];
    char mac[MAX_SHORT_LENGTH];
    
    get_ip_address_fun("eth0", ip);        
    get_mac_address_fun("eth0", mac);
    
    printf("ip : %s, mac : %s\n", ip, mac);

    return 0;
}

Result:
ip : 192.168.1.100, mac : 00-00-00-55-55-55

[C/C++] 目前網路連線狀態

說明:
目前網路連線狀態

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>

typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned char u8;

// if_name like "ath0", "eth0". Notice: call this function
// need root privilege.
// return value:
// -1 -- error , details can check errno
// 1 -- interface link up
// 0 -- interface link down.
int get_netlink_status_fun(const char *if_name)
{
    int skfd;
    struct ifreq ifr;
    struct ethtool_value edata;
    edata.cmd = ETHTOOL_GLINK;
    edata.data = 0;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
    ifr.ifr_data = (char *) &edata;
    
    if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 )) == 0)
        return -1;
    
    if(ioctl( skfd, SIOCETHTOOL, &ifr ) == -1)
    {
        close(skfd);
        return -1;
    }
    
    close(skfd);
    return edata.data;
}


int main(int argc, char *argv[])
{
    printf("eth0 : %s\n", get_netlink_status_fun("eth0")==1?"up":"down");
    return 0;
}

Result:
eth0 : up


[C/C++] 顯示目前mount的狀態

說明:
顯示目前mount的狀態

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <mntent.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

typedef struct mountInfo
{
    char  dev_name[MAX_SHORT_LENGTH];
    char  mount_path[MAX_SHORT_LENGTH];
    char  fs_type[MAX_SHORT_LENGTH];
    char  attribute[MAX_SHORT_LENGTH];
    struct mountInfo *next;
} mountInfoS;

BOOL load_file_fun(char *filename, char **p_content)
{
    int fd = -1;    
    int totalsize = 0;
    int readsize = 0;
    char buffer[MAX_SHORT_LENGTH];
    BOOL ret = FALSE;
    
    if ( (fd = open((char *)filename, O_RDONLY)) > 0 )
    {
        totalsize = 0;
        while( (readsize = read(fd, buffer, MAX_SHORT_LENGTH)) > 0)
            totalsize += readsize;

        if (totalsize <= 0)
        {
            printf("[ERROR] %s file size is wrong!\n", filename);
            return ret;
        }    
        
        if (lseek(fd, 0, SEEK_SET) == -1)
        {
            printf("[ERROR] %s can't seek!\n", filename);
            return ret;
        }
        
        *p_content = (char*)malloc( ( totalsize + 1) * sizeof(char));
        memset(*p_content, '\0', totalsize + 1);

        if (*p_content)
        {
            if(read(fd, *p_content, totalsize) > 0 )
            {
                ret = TRUE;
            }
            else
            {
                printf("[ERROR] %s can't read!\n", filename);
                free(*p_content);
            }

            close(fd);
        }
    }
    else
        printf("[ERROR] Open %s fail!\n", filename);

    return ret;    
}

void get_mount_info_fun(mountInfoS **p_output)
{
    char *p_content = NULL;
    char *p_tmp = NULL;
    char *p_feed = NULL;
    char *p_line = NULL;
    int len = 0;
    int loop = 0;
    char *sep = "\t ";
    char * pch;
    mountInfoS *p_new, *p_first, *p_cur;

    p_new = p_first = p_cur = NULL;
    
    if (load_file_fun("/proc/mounts", &p_content) == TRUE)
    {
        p_tmp = p_content;

        while((p_feed = strpbrk(p_tmp, "\n")))
        {
            len = p_feed - p_tmp;
            p_line = (char*)malloc(len + 1);
            memset(p_line, '\0', len + 1);
            strncpy(p_line, p_tmp, len);
            
            pch = strtok(p_line, sep);

            if (pch)
            {
                p_new = malloc(sizeof(mountInfoS));
                memset(p_new, '\0', sizeof(mountInfoS));
                loop = 0;
                strcpy( p_new->dev_name, pch);
                
                while (pch != NULL)
                {
                    pch = strtok (NULL, sep);
                    loop++;
                    
                    if (loop == 1)                    
                        strcpy( p_new->mount_path, pch);
                    else if (loop == 2)                    
                        strcpy( p_new->fs_type, pch);    
                    else if (loop == 3)                    
                        strcpy( p_new->attribute, pch);                            
                }   

                if ( p_first == NULL )
                {
                    p_first = p_cur = p_new;
                }
                else
                {
                    p_cur->next = p_new;
                    p_cur = p_new;
                }                
            }            

            free(p_line);
            p_tmp = p_feed + 1;
        }
    }

    if (p_content)
        free(p_content);
        
    *p_output = p_first;    
}

void free_mount_info_fun(mountInfoS *p_input)
{
    mountInfoS *p_cur = p_input;
    mountInfoS *p_tmp;   
    
    p_tmp = p_cur;
    while( p_cur )
    {
        p_tmp = p_cur;
        p_cur = p_cur->next;
        free( p_tmp );
    }
}

int main(int argc, char *argv[])
{
    mountInfoS *p_info = NULL;
    mountInfoS *p_tmp = NULL;
    
    get_mount_info_fun(&p_info);
    
    if(p_info)
    {
        p_tmp = p_info;
        while(p_tmp)
        {
            printf("dev_name : %s  ", p_tmp->dev_name);
            printf("mount_path : %s  ", p_tmp->mount_path);
            printf("fs_type : %s  ", p_tmp->fs_type);
            printf("attribute : %s\n", p_tmp->attribute);            
            p_tmp = p_tmp->next;
        }
        
        free_mount_info_fun(p_info);
    }
    
    return 0;
}

Result:
dev_name : sysfs  mount_path : /sys  fs_type : sysfs  attribute : rw,nosuid,nodev,noexec,relatime
dev_name : proc  mount_path : /proc  fs_type : proc  attribute : rw,nosuid,nodev,noexec,relatime
dev_name : udev  mount_path : /dev  fs_type : devtmpfs  attribute : rw,nosuid,noexec,relatime,size=16359368k,nr_inodes=4089842,mode=755,inode64
dev_name : devpts  mount_path : /dev/pts  fs_type : devpts  attribute : rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000
dev_name : tmpfs  mount_path : /run  fs_type : tmpfs  attribute : rw,nosuid,nodev,noexec,relatime,size=3278556k,mode=755,inode64
......

[C/C++] 顯示記憶體狀況

說明:
顯示記憶體狀況

Code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>

int main(int argc, char *argv[])
{
    struct sysinfo sys_info;
    
    if ( sysinfo( &sys_info ) == 0 )
    {
        printf("Total Ram: %lluM\nFree: %lluM\n",
            sys_info.totalram *(unsigned long long)sys_info.mem_unit/1024/1024,
            sys_info.freeram *(unsigned long long)sys_info.mem_unit/1024/1024);
    }
    return 0;
}


Result:
Total Ram: 32017M
Free: 18635M

[C/C++] 列出資樂夾裡的資樂夾和檔案

 說明:
列出資樂夾裡的資樂夾和檔案

Code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <math.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <dirent.h>
#include <string.h>
#include <linux/usbdevice_fs.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128
#define MAX_MIDDLE_LENGTH       256

typedef enum FILEFOLDER_TYPE
{
    ATTRIBUTE_FILE,
    ATTRIBUTE_FOLDER,
}FILEFOLDER_TYPE_ENUM;

typedef struct filefolderInfo
{
    char                        pathname[MAX_MIDDLE_LENGTH];
    char                        name[MAX_MIDDLE_LENGTH];
    FILEFOLDER_TYPE_ENUM        type;
    struct filefolderInfo *next;
}filefolderInfoS;


BOOL get_file_folder_list_fun(char *path, filefolderInfoS **p_list)
{
    DIR *dir;
    struct dirent *p_ptr;
    filefolderInfoS *p_first = NULL;
    filefolderInfoS *p_current = NULL;

    dir =opendir(path);
    if (dir == NULL)
        return TRUE;

    while((p_ptr = readdir(dir))!=NULL) 
    {
        if ( strcmp(p_ptr->d_name, ".") == 0 
          || strcmp(p_ptr->d_name, "lost+found") == 0
          || strcmp(p_ptr->d_name, "..") == 0)
        {
            continue;
        }
        
        if (strlen(p_ptr->d_name) > 1 && p_ptr->d_name[0] == '.')
            continue;
        
        char pathname[MAX_MIDDLE_LENGTH];
        memset(pathname, '\0', MAX_MIDDLE_LENGTH);
        struct stat buf;
        sprintf(pathname,"%s%s", path, p_ptr->d_name);
        stat(pathname, &buf);
        
        filefolderInfoS *p_tmp = malloc(sizeof(filefolderInfoS));
        strcpy(p_tmp->pathname, pathname);
        strcpy(p_tmp->name, p_ptr->d_name);     
        p_tmp->next = NULL;
        
        if(S_ISREG(buf.st_mode))
            p_tmp->type = ATTRIBUTE_FILE;
        else
            p_tmp->type = ATTRIBUTE_FOLDER;
        
        //printf("%s, %s, %d\n", p_tmp->pathname, p_tmp->name, p_tmp->type);
        
        if (p_current == NULL)
        {
            p_first = p_tmp;
            p_current = p_tmp;
        }
        else
        {
            p_current->next = (filefolderInfoS*)p_tmp;
            p_current = p_tmp;
        }
            
    }
    closedir(dir);
    
    *p_list = p_first;
    
    return TRUE;

}

void free_file_folder_list(filefolderInfoS *p_list)
{
    filefolderInfoS *p_current, *p_next;
    p_current = p_list;

    while(p_current)
    {
        p_next = (filefolderInfoS*)p_current->next;
        free(p_current);
        p_current = p_next;
    }
}

int main(int argc, char *argv[])
{
    filefolderInfoS *p_info = NULL;
    filefolderInfoS *p_tmp = NULL;
    
    get_file_folder_list_fun("/etc/", &p_info);
    
    p_tmp = p_info;
    
    if (p_tmp)
    {
        while(p_tmp)
        {
            printf("file : %s, %s, %d\n", p_tmp->pathname, p_tmp->name, p_tmp->type);
            p_tmp = p_tmp->next;
        }
        
        free_file_folder_list(p_info);
    }
    
    return 0;
}

Result:
file : /etc/acpi, acpi, 1
file : /etc/profile, profile, 0
file : /etc/rc4.d, rc4.d, 1
file : /etc/openal, openal, 1
file : /etc/apparmor.d, apparmor.d, 1
.............

[C/C++] fork範例

 說明:
fork範例

Code:

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

/* fork()類似Thread,他會產生父進程和子進程分成二頭執行,就像是二條Thread. (雖然看似同時間進行,但事實上還是有一個先有一個後.) */
int fork_sample1()
{
    pid_t child_pid;
    printf("================sample1 getpid: %d ================\n", (int) getpid());
    child_pid = fork ();

    if (child_pid != 0)
    {
         // 子進程
        printf("sample1 child => getpid() : %d\n", (int) getpid());
        printf("sample1 child => child_pid : %d\n", (int) child_pid);
    }
    else
    {
        // 父進程
        printf("sample1 parent => getpid() : %d\n", (int) getpid());
        printf("sample1 parent => getppid() : %d\n", (int) getppid());
    }

    return 0;
}

/* 當某子進程先終止時(到程式最後return 0), 而父進程還未終止時,會照成程式不正常關閉,所以必須搭配wait來使用. */
int fork_sample2()
{
    pid_t child_pid;
    int child_status;

    printf("================sample2 getpid: %d ================\n", (int) getpid());
    
    child_pid = fork();

    if (child_pid != 0)
    {
        printf("sample2 child => getpid() : %d\n", (int) getpid());
        printf("sample2 child => child_pid : %d\n", (int) child_pid);

        /* Wait for the child process to complete. */
        wait (&child_status);
        
        if (WIFEXITED (child_status))
        {
            printf ("The child process exited normally, with exit code %d\n", WEXITSTATUS (child_status));
        }
       else
        {
           printf ("The child process exited abnormally\n");
        }
    }
    else
    {
        printf("sample2 parent => getpid() : %d\n", (int) getpid());
        printf("sample2 parent => getppid() : %d\n", (int) getppid());
        sleep(3);
    }

    return 0;
}

int main(int argc, char *argv[])
{
    //printf("fork_sample1\n");
    //fork_sample1();    
    //sleep(1)
    
    printf("\n\nfork_sample2\n");
    fork_sample2();
        
    return 0;
}

Result:
fork_sample2
================sample2 getpid: 3897923 ================
sample2 child => getpid() : 3897923
sample2 child => child_pid : 3897924
sample2 parent => getpid() : 3897924
sample2 parent => getppid() : 3897923
The child process exited normally, with exit code 0

[C/C++] 印出error code的字串

 說明:
印出error code的字串

Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

extern int errno;

int main(int argc, char *argv[])
{
    
    strtol("0xfffffffff", NULL, 0);
    char *err_str = strerror(errno);
    printf("Error : [%d], [%s]\n", errno, err_str);
    
    fopen("file.txt", "r");
    err_str = strerror(errno);
    printf("Error : [%d], [%s]\n", errno, err_str);
    
    return 0;
}

Result:
Error : [0], [Success]
Error : [2], [No such file or directory]

[C/C++] 利用define來印出debug message

說明:
定義_DEBUG為1時debug message會印出,_DEBUG為0時則不會.

Code:

#include <stdio.h>

#define _DEBUG    1

#ifdef _DEBUG
int (*printf_d)(const char*, ...) = printf;
#else
int printf_d(const char* fmt, ...) {return 0;}
#endif

int main(int argc, char *argv[])
{
    printf_d("test\n");
    return 0;
}



[C/C++] 使用read/write拷貝檔案範例

說明:
使用read/write拷貝檔案範例

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

BOOL copyfile_fun(char *src, char *dest)
{
    int  ret = TRUE;
    int  len = 0;;
    char buffer[MAX_LONG_LENGTH];

    int fd1 = open(src, O_RDONLY);
    int fd2 = open(dest, O_RDWR|O_CREAT, S_IRWXU);
   
    while((len = read(fd1, buffer, MAX_LONG_LENGTH)) > 0)
    {
        if (write(fd2, buffer, len) != len)
        {
            printf("[ERROR] write file %s failed\n", dest);    
            ret = FALSE;
            break;
        }
    }
          
    if (fd1) close(fd1);
    if (fd2) close(fd2);
   
    return ret;
}

int main(int argc, char *argv[])
{
    if (copyfile_fun("/etc/exports", "./exports") == TRUE)
        printf("[SUCCESS] copy file successfully!\n");
    else
        printf("[ERROR] copy file failed!\n");

    return 0;
}

Result:
[SUCCESS] copy file successfully!


[C/C++] 存取參數變數範例

說明:
存取參數變數範例. 例如setenv/getenv, set property/get property.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#define BOOL                    int
#define TRUE                    0
#define FALSE                   -1
#define MAX_LONG_LENGTH         1024
#define MAX_SHORT_LENGTH        128

typedef struct ConfigParam
{
    char   argument[MAX_SHORT_LENGTH];
    char   option[MAX_SHORT_LENGTH];
    struct ConfigParam *next;
}ConfigParamS;

BOOL is_file_exist_fun(char *filename)
{
    int bRet = FALSE;
    FILE* fp = fopen(filename, "r");
    if (fp) 
    {
        bRet = TRUE;
        fclose(fp);
    }
    return bRet;
}

BOOL load_file_fun(char *filename, char **p_content)
{
    int fd = -1;    
    int totalsize = 0;
    int readsize = 0;
    char buffer[MAX_SHORT_LENGTH];
    BOOL ret = FALSE;
    
    if ( (fd = open((char *)filename, O_RDONLY)) > 0 )
    {
        totalsize = 0;
        while( (readsize = read(fd, buffer, MAX_SHORT_LENGTH)) > 0)
            totalsize += readsize;

        if (totalsize <= 0)
        {
            printf("[ERROR] %s file size is wrong!\n", filename);
            return ret;
        }    
        
        if (lseek(fd, 0, SEEK_SET) == -1)
        {
            printf("[ERROR] %s can't seek!\n", filename);
            return ret;
        }
        
        *p_content = (char*)malloc( ( totalsize + 1) * sizeof(char));
        memset(*p_content, '\0', totalsize + 1);

        if (*p_content)
        {
            if(read(fd, *p_content, totalsize) > 0 )
            {
                ret = TRUE;
            }
            else
            {
                printf("[ERROR] %s can't read!\n", filename);
                free(*p_content);
            }

            close(fd);
        }
    }
    else
        printf("[ERROR] Open %s fail!\n", filename);

    return ret;    
}

BOOL save_file_fun(char *filename, char *buffer)
{
    int     fd = 0;
    int     length = 0;
    BOOL    ret = FALSE;

    length = strlen(buffer);
    
    if ( (fd = open( filename,
            O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) > 0 )
    {
        if ( write(fd, buffer, length) == length )
            ret = TRUE;
        else
            printf("[ERROR] write %s failed!\n", filename);

        if (fd) 
            close(fd);
        
        sync();
    }
    else
        printf("[ERROR] cannot creat %s!\n", filename);

    return ret;
}

void make_default_param_fun(ConfigParamS **p_argu)
{
    ConfigParamS *p_new;
    p_new = malloc(sizeof(ConfigParamS));
    memset(p_new->argument, '\0', sizeof(p_new->argument));
    memset(p_new->option, '\0', sizeof(p_new->option));
    p_new->next = NULL;
    *p_argu = p_new;
}

void get_param_option_fun(char *p_inargu, ConfigParamS **p_outargu)
{
    int nindex, nstart, nend;
    nindex = nstart = nend = 0;
    ConfigParamS *p_first, *p_current, *p_new;
    p_first = p_current = p_new = NULL;
    void *p_buffer = NULL; 
    p_buffer = malloc((strlen(p_inargu) + 1) * sizeof(char));
    char* p_bufferf = NULL;
    p_bufferf = (char *)p_buffer;
    strcpy(p_bufferf, p_inargu);

    while (nindex < strlen(p_inargu))
    {
        if (*(p_inargu + nindex) == '=')
        {
            make_default_param_fun(&p_new);
            if (p_first == NULL)
            {
                p_first = p_current = p_new;
            } else {
                p_current->next = p_new;
                p_current       = p_new;
            }
            
            nend = nindex;
            memcpy(p_current->argument, p_bufferf + nstart, nend - nstart);
            nstart = nindex + 1;
       }
       else if ( *(p_inargu + nindex) == '\n' || *(p_inargu + nindex + 1 ) == '\0')
       {
           nend = nindex;
           memcpy(p_current->option, p_bufferf + nstart, nend - nstart);
           nstart = nend + 1;
       }
       nindex ++;
    }
    *p_outargu = p_first;
}

void free_param_option_fun(ConfigParamS *p_inargu)
{
    ConfigParamS *p_current, *p_next;
    p_current = p_inargu;

    while(p_current)
    {
        p_next = p_current->next;
        free(p_current);
        p_current = p_next;
    }
}

BOOL set_config_value_fun(char *file, char *p_argument, char *p_option)
{
    char write_buffer[MAX_LONG_LENGTH];
    int ret = FALSE;
    char *p_buffer = NULL;
    ConfigParamS *p_outargu = NULL;
    ConfigParamS *p_tmp1 = NULL;
    ConfigParamS *p_tmp2 = NULL;
    
    memset(write_buffer, '\0', MAX_LONG_LENGTH);
    
    if (is_file_exist_fun(file) == TRUE)
        load_file_fun(file, &p_buffer);
    
    if (p_buffer)
    {
        get_param_option_fun(p_buffer, &p_outargu);
        if (p_outargu)
        {
            p_tmp1 = p_outargu;
            
            while(p_tmp1)
            {
                if (strcmp(p_tmp1->argument, p_argument) ==0)
                {
                    ret = TRUE;
                    strcpy(p_tmp1->option, p_option);
                    break;
                }
                p_tmp2 = p_tmp1;
                p_tmp1 = p_tmp1->next;
            }
            
            if (ret == FALSE)
            {
                ConfigParamS *p_new = malloc(sizeof(ConfigParamS));
                memset(p_new->argument, '\0', sizeof(p_new->argument));
                memset(p_new->option, '\0', sizeof(p_new->option));
                strcpy(p_new->argument, p_argument);
                strcpy(p_new->option, p_option);
                p_new->next = NULL;
                p_tmp2->next = p_new;
            }
            
            p_tmp1 = p_outargu;
            
            while(p_tmp1)
            {
                strcat(write_buffer, p_tmp1->argument);
                strcat(write_buffer, "=");
                strcat(write_buffer, p_tmp1->option);
                strcat(write_buffer, "\n");
                p_tmp1 = p_tmp1->next;
            }
            
            save_file_fun(file, write_buffer);
            
            free_param_option_fun(p_outargu);            
        }
        free(p_buffer);
    }  
    else
    {
        sprintf(write_buffer, "%s=%s\n", p_argument, p_option);
        save_file_fun(file, write_buffer);
    }
    
    return TRUE;
    
}

int get_config_value_fun(char *file, char *p_argument, char *p_option)
{
    int ret = FALSE;
    char *p_buffer = NULL;
    ConfigParamS *p_outargu = NULL;
    ConfigParamS *p_tmp1 = NULL;
    
    load_file_fun(file, &p_buffer);
    
    if (p_buffer)
    {
        get_param_option_fun(p_buffer, &p_outargu);
        if (p_outargu)
        {
            p_tmp1 = p_outargu;
            
            while(p_tmp1)
            {
                if (strcmp(p_tmp1->argument, p_argument) ==0)
                {
                    ret = TRUE;
                    strcpy((char *)p_option, p_tmp1->option);
                    break;
                }
                p_tmp1 = p_tmp1->next;
            }
            free_param_option_fun(p_outargu);            
        }
        
        free(p_buffer);
    }       
    
    return ret;
}

int main(int argc, char *argv[])
{
    char value[MAX_SHORT_LENGTH];
    
    set_config_value_fun("./test.conf", "AA", "123");
    set_config_value_fun("./test.conf", "BB", "456");
    set_config_value_fun("./test.conf", "CC", "456");
    
    if (get_config_value_fun("./test.conf", "BB", (char *)value) == TRUE)
        printf("BB : %s\n", value);
    else
        printf("[ERROR] get failed!\n");
    
    return 0;
}

Result:
BB : 456