Showing posts with label Beginning Linux Programming. Show all posts

Resources and Limits




Monday, August 3, 2015

Logging

Log file là một file rất quan trong nên có cho mỗi chương trình để lưu lại tất cả thông tin về quá trình chạy của chương trình, từ đó có thể phân tích kiểm tra thông tin history, tìm kiếm lỗi nếu xảy ra, ...

1. syslog
 #include <syslog.h>  
 void syslog(int priority, const char *message, arguments...);  

syslog gửi log mesage đến file log hệ thống /var/log/messages và /var/log/debug bạn có thể dùng lệnh cat để xem log msg.

+ priority
Bitwire OR của level và facility value.

level:

Priority Level Description
LOG_EMERG An emergency situation
LOG_ALERT High-priority problem, such as database corruption
LOG_CRIT Critical error, such as hardware failure
LOG_ERR Errors
LOG_WARNING Warning
LOG_NOTICE Special conditions requiring attention
LOG_INFO Informational messages
LOG_DEBUG Debug messages

facility value:

Facility values Description
LOG_USER the message has come from a user application
LOG_LOCAL0 which can be assignedmeanings by the local administrator
... ...
LOG_LOCAL7

Tùy thuộc vào priority mà syslog sẽ có cách xử lý khác nhau đối với message, ví dụ với LOG_EMERG thì msg được gửi đến tất cả các user, LOG_ALERT thì msg được gửi mail đến administrator, LOG_DEBUG thì msg được bỏ qua, còn các trường hợp khác sẽ ghi vaog log file.

+ message
Message được syslog gửi đi.
+ arguments
Các đối số khác.
+ return

Ex:
syslog.c
   
 #include <syslog.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 int main()  
 {  
   FILE *f;  
   f = fopen("not_here","r");  
   if(!f)  
     syslog(LOG_ERR|LOG_USER,"oops hi hi ha ha - %m\n");  
   exit(0);  
 }  
   

Compile & Execute (root user):
 $ gcc syslog.c  
 $ su  
 # ./a.out  
 # cat /var/log/messages  
 Aug 2 11:24:00 localhost a.out: oops - No such file or directory  

2. openlog
 #include <syslog.h>  
 void closelog(void);  
 void openlog(const char *ident, int logopt, int facility);  
 int setlogmask(int maskpri);  

syslog không cho biết thông tin về user nào, chương trình nào tạo ra log msg, mà chỉ có một khuôn dạng log chung, vì thế trong nhiều trường hợp sẽ khó khăn để fixbug khi chương trình có lỗi. Chính vì thế cần có thêm các hàm để thay đổi hành vi của logger.

openlog mở logger ra để chỉnh sửa:
+ ident
Chuỗi string tùy ý bạn thêm vào dòng log msg.
+ logopt
log option của openlog:
 /*  
  * Option flags for openlog.  
  *  
  * LOG_ODELAY no longer does anything.  
  * LOG_NDELAY is the inverse of what it used to be.  
  */  
 #define     LOG_PID          0x01     /* log the pid with each message */  
 #define     LOG_CONS     0x02     /* log on the console if errors in sending */  
 #define     LOG_ODELAY     0x04     /* delay open until first syslog() (default) */  
 #define     LOG_NDELAY     0x08     /* don't delay open */  
 #define     LOG_NOWAIT     0x10     /* don't wait for console forks: DEPRECATED */  
 #define     LOG_PERROR     0x20     /* log to stderr as well */  

+ facility
Tương tự như trên syslog.

setlogmask điều khiển priority level của syslog:
+ maskpri
Set môt priority với LOG_MASK(priority) hoặc một dải priority với LOG_UPTO(priority)

Ex:
logmask.c
 #include <syslog.h>  
 #include <stdio.h>  
 #include <unistd.h>  
 #include <stdlib.h>  
   
 int main()  
 {  
   int logmask;  
   openlog("logmask", LOG_PID|LOG_CONS, LOG_USER);  
   
   /*  
    * ghi ra /var/log/messages  
    *  
    */  
   syslog(LOG_INFO,"informative message, pid = %d", getpid());  
   
   /*  
    * ghi ra /var/log/debug  
    *  
    */  
   syslog(LOG_DEBUG,"debug message, should appear");  
   
   /*  
    * Bỏ qua tất cả các msg có priority < LOG_NOTICE  
    *  
    */  
   logmask = setlogmask(LOG_UPTO(LOG_NOTICE));  
   syslog(LOG_DEBUG,"debug message, should not appear");  
   
   exit(0);  
 }  
   

Compile & Execute:
 $ gcc logmask.c   
 $ su  
 # ./a.out   
 # cat /var/log/messages  
 Aug 2 22:14:29 localhost logmask[4676]: informative message, pid = 4676  
   



Temporary Files

Trong lúc chương trình chạy, đôi lúc chương trình cần có một file tạm để ghi các thông tin tam thời vào, Unix/Linux cung cấp một số hàm để thực hiện điều đó:

 #include <stdio.h>  
 char *tmpnam(char *s);  
 FILE *tmpfile(void);

tmpnam tạo ta một file tạm:
+ s
File trả về được ghi vào đây, s có độ dài ít nhất bằng L_tmpnam.
+ return
Trả về một file có tên không trình với bất kỳ tên nào đã tồn tại.


tmpfile mở file tạm được trả về từ tmpnam, hàm này tương đương với fopen w+
+ return
Trả về file stream của file tạm.

Ex:
tmpfile.c
 #include <stdio.h>  
 #include <stdlib.h>  
 int main()  
 {  
   char tmpname[L_tmpnam];  
   char *filename;  
   FILE *tmpfp;  
   filename = tmpnam(tmpname);  
   printf("Temporary file name is: %s \n", filename); //filename == tmpname  
   tmpfp = tmpfile();  
   if(tmpfp)  
     printf("Opened a temporary file OK\n");  
   else  
     perror("tmpfile");  
   exit(0);  
 }  
   

Compile & Execute:
 $ gcc tmpname.c   
 $ ./a.out   
 Temporary file name is: /tmp/fileaNvouf   
 Opened a temporary file OK  
   


Sunday, August 2, 2015

Host Information

Trong Shell bạn dùng lệnh uname để lấy thông tin về host của mình đang sử dụng:

 $ uname  
 Linux  
 $ uname -a  
 Linux localhost.localdomain 3.18.6-100.fc20.x86_64 #1 SMP Fri Feb 6 22:55:01 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux  
 $   
 $ uname -i  
 x86_64  
   

Unix/Linux cung cấp các API:
 #include <unistd.h>  
 int gethostname(char *name, size_t namelen);  
+ name
Bufer, tên của host được trả về tại đây
+ namelen
Độc dài của buffer
+ return
Trả về 0 nếu thành công.

 #include <sys/utsname.h>  
 int uname(struct utsname *name);  

struct utsname:
 struct utsname {  
         char sysname[];  /* Operating system name (e.g., "Linux") */  
         char nodename[];  /* Name within "some implementation-defined  
                    network" */  
         char release[];  /* Operating system release (e.g., "2.6.28") */  
         char version[];  /* Operating system version */  
         char machine[];  /* Hardware identifier */  
       #ifdef _GNU_SOURCE  
         char domainname[]; /* NIS or YP domain name */  
       #endif  
       };  

+ name
Struct lưu trữ host information.
+ return
Trả về số > 0 nếu thành công; -1 nếu lỗi, kèm mã lỗi errno.

Ex:
hostget.c
 #include <sys/utsname.h>  
 #include <unistd.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
   
 int main()  
 {  
   char computer[256];  
   struct utsname uts;  
   if(gethostname(computer, 255) != 0 || uname(&uts) < 0) {  
     fprintf(stderr, "Could not get host information\n");  
     exit(1);  
   }  
   printf("Computer host name is %s\n", computer);  
   printf("System is %s on %s hardware\n", uts.sysname, uts.machine);  
   printf("Nodename is %s\n", uts.nodename);  
   printf("Version is %s, %s\n", uts.release, uts.version);  
   exit(0);  
 }  
   

Compile & Execute:
 $ gcc hostget.c   
 $ ./a.out   
 Computer host name is localhost.localdomain  
 System is Linux on x86_64 hardware  
 Nodename is localhost.localdomain  
 Version is 3.18.6-100.fc20.x86_64, #1 SMP Fri Feb 6 22:55:01 UTC 2015  


User Information

Bài viết liên quan:
+ Users and Groups

Một OS bao giờ cũng tạo ra các User và gom nhiều user có điểm chung lại với nhau thành Group, các user và group được định danh theo con số duy nhất gọi là UID (User IDentifier) và GID (Group IDentifier). Unix/Linux cung cấp các API để giúp chưng trình lấy được thông tin về User và Group mà nó thuộc về.

1. User and Groups 
 #include <sys/types.h>  
 #include <unistd.h>  
 uid_t getuid(void); //trả về UID
 gid_t getgid(void); //trả về GID
 int setuid(uid_t uid);
 int setgid(gid_t gid);
 char *getlogin(void); //trả về login name của user  

Các thông tin trên được lưu trong /etc/passwd có dạng:
 account:password:UID:GID:GECOS:directory:shell  

account is the user name
password is the user password
UID is the numerical user ID
GID is the numerical primary group ID for the user
GECOS is an optional field used for informational purposes; usually it contains the full user name
directory is the user's $HOME directory
shell is the user command interpreter (defaults to /bin/sh)

Ex:
 $ cat /etc/passwd | grep ninhld  
 ninhld:x:1000:1000:ninhld:/home/ninhld:/bin/bash  

2. Password Database
 #include <sys/types.h>  
 #include <pwd.h>  
 struct passwd *getpwuid(uid_t uid);  
 struct passwd *getpwnam(const char *name);  

struct passwd:

passwd Member Description
char *pw_name The user’s login name
uid_t pw_uid The UID number
gid_t pw_gid The GID number
char *pw_dir The user’s home directory
char *pw_gecos The user’s full name
char *pw_shell The user’s default shell

Thông tin về Password Database được lưu trong /etc/passwd

Để lấy tât cả thông tin trong Password Database:
 #include <pwd.h>  
 #include <sys/types.h>  
 void setpwent(void);           //trở về đầu database
 struct passwd *getpwent(void); //sacn tất cả entry, khi không còn thì trả về NULL
 void endpwent(void);           //đóng database khi scan xong 

Ex1:
user.c
 #include <sys/types.h>  
 #include <pwd.h>  
 #include <stdio.h>  
 #include <unistd.h>  
 #include <stdlib.h>  
   
 int main()  
 {  
   uid_t uid;  
   gid_t gid;  
   struct passwd *pw;  
   uid = getuid();  
   gid = getgid();  
   printf("User is %s\n", getlogin());  
   printf("User IDs: uid=%d, gid=%d\n", uid, gid);  
   pw = getpwuid(uid);  
   printf("UID passwd entry:\n name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",  
       pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);  
   pw = getpwnam("root");  
   printf("root passwd entry:\n");  
   printf("name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",  
       pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);  
   exit(0);  
 }  
   

Compile & Execute:
 $ gcc user.c   
 $ ./a.out   
 User is ninhld  
 User IDs: uid=1000, gid=1000  
 UID passwd entry:  
  name=ninhld, uid=1000, gid=1000, home=/home/ninhld, shell=/bin/bash  
 root passwd entry:  
 name=root, uid=0, gid=0, home=/root, shell=/bin/bash  


Ex2:
getpwent.c
 /*  
  * This program loops, reading a login name from standard  
  * input and checking to see if it is a valid name. If it  
  * is not valid, the entire contents of the name in the  
  * password database are printed.  
  */  
 #include <stdio.h>  
 #include <sys/types.h>  
 #include <pwd.h>  
   
 void main()  
 {  
   struct passwd *pw;  
   
   setpwent( );  
   while( ( pw=getpwent( ) ) != ( struct passwd * )0 )  
     printf( "%s\n", pw->pw_name );  
   endpwent();  
 }  
   

Compile & Execute:
 $ gcc getpwent.c   
 $ ./a.out   
 root  
 bin  
 daemon  
 adm  
 lp  
 sync  
 shutdown  
 halt  
 mail  
 operator  
 games  
 ftp  
 nobody  
 avahi-autoipd  
 dbus  
 polkitd  
 usbmuxd  
 rtkit  
 chrony  
 tss  
 unbound  
 openvpn  
 avahi  
 pulse  
 lightdm  
 nm-openconnect  
 colord  
 sshd  
 tcpdump  
 ninhld  
 abrt  
 rpc  
 rpcuser  
 nfsnobody  
 stap-server  
   





Time and Date

1. time
Unix/Linux cung cấp thư viện time.h bao gồm các cấu trúc và hàm để xác định thời gian. Chúng thường được dùng để làm bộ timer, đo tốc độ của một đoạn xử lý logic, ...Thời gian trong Unix/Linux được lấy mốc là 00:00:00 (hh:mm:ss) 01-01-1970 UTC.

 #include <time.h>  
 time_t time(time_t *tloc);  

Hàm time lấy thời gian hiện tại.
+ tloc
Thời gian hiện tại trả về được lưu vào tloc nếu tloc không NULL.
+ return
Trả về thời gian hiện tại lưu trong time_t tính bằng giây tính từ thời điểm bắt đầu 00:00:00 (hh:mm:ss) 01-01-1970 UTC.

Ex:
envtime.c
 #include <time.h>  
 #include <stdio.h>  
 #include <unistd.h>  
 #include <stdlib.h>  
   
 int main()  
 {  
   int i;  
   time_t the_time, timmer;  
   for(i = 1; i <= 5; i++) {  
     the_time = time(&timmer);  
     printf("The time is %ld\n", the_time); // the_time == timmer  
     sleep(1);  
   }  
   exit(0);  
 }  
   

Execute:
 $ gcc envtime.c   
 $ ./a.out   
 The time is 1438358154  
 The time is 1438358155  
 The time is 1438358156  
 The time is 1438358157  
 The time is 1438358158  
   

2. gmtime
 #include <time.h>  
 struct tm *gmtime(const time_t timeval);  

struct tm:

Ex:
gmtime.c
 #include <time.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 int main()  
 {  
   struct tm *tm_ptr;  
   time_t the_time;  
   (void) time(&the_time);  
   
   tm_ptr = gmtime(&the_time);  
   printf("Raw time is %ld\n", the_time);  
   printf("gmtime gives:\n");  
   printf("date: %02d/%02d/%02d\n",  
       tm_ptr->tm_year, tm_ptr->tm_mon+1, tm_ptr->tm_mday);  
   printf("time: %02d:%02d:%02d\n",  
       tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec);  
   exit(0);  
 }  
   

Execute:
 $ gcc gmtime.c   
 $ ./a.out   
 Raw time is 1438358295  
 gmtime gives:  
 date: 115/07/31  
 time: 15:58:15  
   

3. ctime
 #include <time.h>  
 char *asctime(const struct tm *timeptr);  
 char *ctime(const time_t *timeval);  

Ex:
ctime.c
 #include <time.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 int main()  
 {  
   time_t timeval;  
   (void)time(&timeval);  
   printf("The date is: %s", ctime(&timeval));  
   exit(0);  
 }  
   

 $ gcc ctime.c   
 $ ./a.out   
 The date is: Fri Jul 31 23:00:27 2015  

4. localtime
 #include <time.h>  
 struct tm *localtime(const time_t *timeval);  

Ex:
localtime.c
 /* localtime example */  
 #include <stdio.h>   /* puts, printf */  
 #include <time.h>    /* time_t, struct tm, time, localtime */  
   
 int main ()  
 {  
  time_t rawtime;  
  struct tm * timeinfo;  
   
  time (&rawtime);  
  timeinfo = localtime (&rawtime);  
  printf ("Current local time and date: %s", asctime(timeinfo));  
   
  return 0;  
 }  

Execute:
 $ gcc localtime.c  
 $ ./a.out  
 Current local time and date: Fri Jul 31 16:11:47 2015  

5. gettimeofday
 #include <sys/time.h>  
 int gettimeofday(struct timeval *tv, struct timezone *tz);  
 int settimeofday(const struct timeval *tv, const struct timezone *tz);  

 struct timeval {  
   time_t   tv_sec;   /* seconds */  
   suseconds_t tv_usec;  /* microseconds */  
 };  
   
 struct timezone {  
   int tz_minuteswest;   /* minutes west of Greenwich */  
   int tz_dsttime;     /* type of DST correction */  
 };  

Ex:
gettimeofday.c
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <sys/time.h>  
   
 int main()  
 {  
   long int cycle = 2000000;//us ~ 2s  
   struct timeval tv, tv2;  
   
   gettimeofday(&tv,NULL);  
   while(1){  
     gettimeofday(&tv2,NULL);  
     if(tv2.tv_sec * 1000000 + tv2.tv_usec >= tv.tv_sec * 1000000 + tv.tv_usec + cycle){  
       printf("Timer is starting ... \n");  
       break;  
     }  
   }  
   
   return 0;  
 }  
   

Saturday, August 1, 2015

Environment Variables

1. Get and Set environment variables
Thư viện stdlib.h cung cấp các hàm để chương trình tương tác với các biến môi trường bên ngoài.

 #include <stdlib.h>  
 char *getenv(const char *name);  
 int putenv(const char *string);  

getenv lấy giá trị của biến môi trường.
+ name
Tên của biến môi trường
+ return
Trả về NULL nếu name không tồn tại.
Trả về string rỗng nếu name tồn tại nhưng không có giá trị.
Trả về giá trị của name nếu name tồn tại và có giá trị.

putenv gán giá trị cho biến môi trường.
+ string
Chuỗi gán biến môi trường và giá trị của nó.
+ return
Trả về -1 nếu coa lỗi.

Ex:
environ.c
 #include <stdio.h>  
 #include <stdlib.h>  
   
 int main ()  
 {  
   char *tmp;  
   
   tmp = getenv("PATH");  
   if(tmp)  
     printf("PATH : %s\n", tmp);  
   
   tmp = getenv("HOME");  
   if(tmp)  
     printf("HOME : %s\n", tmp);  
   
   tmp = getenv("ROOT");  
   if(tmp){  
     printf("ROOT : %s\n", tmp);  
   } else{  
     char *root = "ROOT=/root";  
     putenv(root);  
     printf("set ROOT : %s\n", getenv("ROOT"));  
   }  
   
   return(0);  
 }  
   

Compile & Execute:
 $ gcc environ.c   
 $ ./a.out   
 PATH : /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin  
 HOME : /home/ninhld  
 set ROOT : /root  
   


2. The environ Variable
 #include <stdlib.h>  
 extern char **environ;  

environ là mảng chứa tất cả các biến môi trường và giá trị của chúng.

Ex:
showenv.c
 #include <stdlib.h>  
 #include <stdio.h>  
 extern char **environ;  
 int main()  
 {  
   char **env = environ;  
   while(*env) {  
     printf("%s\n",*env);  
     env++;  
   }  
   exit(0);  
 }  
   

Compile & Execute:
 $ gcc showenv.c   
 $ ./a.out   
 XDG_VTNR=1  
 MATE_DESKTOP_SESSION_ID=this-is-deprecated  
 SSH_AGENT_PID=1418  
 XDG_SESSION_ID=1  
 HOSTNAME=localhost.localdomain  
 XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/ninhld  
 IMSETTINGS_INTEGRATE_DESKTOP=yes  
 GPG_AGENT_INFO=/home/ninhld/.cache/keyring-PhSdLU/gpg:0:1  
 TERM=xterm-256color  
 SHELL=/bin/bash  
 HISTSIZE=1000  
 HELLO=hello  
 WINDOWID=67108895  
 OLDPWD=/home/ninhld  
 GNOME_KEYRING_CONTROL=/home/ninhld/.cache/keyring-PhSdLU  
 QTDIR=/usr/lib64/qt-3.3  
 QTINC=/usr/lib64/qt-3.3/include  
 IMSETTINGS_MODULE=IBus  
 QT_GRAPHICSSYSTEM_CHECKED=1  
 USER=ninhld  
 ...

Program Arguments

Một chương trình C/C++ sẽ bắt đầu với hàm main và các đối số được truyền từ môi trường ngoài vào.

args.c
 #include <stdio.h>  
 #include <stdlib.h>  
 int main(int argc, char **argv)  
 {  
   int arg;  
   
   printf("Program name: %s \n", argv[0]);  
   for(arg = 1; arg < argc; arg++) {  
       printf("argument %d: %s\n", arg, argv[arg]);  
   }  
   
   return 0;  
 }   

+ argc
Số tham số được truyền vào cho hàm main, argc >= 1 bởi vì mặc định luôn có ít nhất một đối số được truyền vào đó là tên của chính chương trình đó được lưu trong argv[0].
+ argv
Mảng chứa các tham số truyền vào cho hàm main. argv[0] là tên của chương trình; argv[1], argv[2], ... lần lượt là các tham số của người dùng truyền vào.

Compile & Execute:
 $ gcc args.c   
 $ ./a.out par1 par2  
 Program name: ./a.out   
 argument 1: par1  
 argument 2: par2  
   

Unix/Linux cung cấp thêm các hàm dưới đây để truyền các đối số phức tạp hơn.

1. getopt
 #include <unistd.h>  
 int getopt(int argc, char *const argv[], const char *optstring);  
 extern char *optarg;  
 extern int optind, opterr, optopt;  

+ argc
Số các đối số, được lấy từ argc của hàm main.
+ argv
Mảng các đối số, được lấy từ argv của hàm main
+ optstring
Các option để phân tích các đối số từ mảng mảng argv. Khi truyền trước các option phải có dấu trừ '-'. Trong trường hợp phía sau option là dấu hai chấm ':' thì option đó phải có giá trị đối số đi kèm, và nó sẽ được lưu trong optarg.

Ex:
 getopt(argc, argv,"apl:b:")  
tương ứng với -a, -p, -l value1, -b value2.

+ return
    - Trả về các option truyền từ ngoài vào mà nó trùng với một trong những option được liệt trong optstring, nếu có giá trị đi kèm option thì được lưu ở biến optarg
    - Trả về ':' nếu có option trùng với một trong những option trong optstring và option đó bắt buộc phải có giá trị đi kèm, tuy nhiên lúc này nó lại không có giá trị đi kèm
    - Trả về '?' nếu không có option trùng, biến optopt lưu option không trùng đó
    - Trả về -1 nếu không còn option nào để phân tích (kết thúc quá trình phân tích)

+ optind
Số thứ tự các đối số truyền vào argv[optind]

Ex:
getopt.c
 #include <stdio.h>  
 #include <unistd.h>  
 #include <stdlib.h>  
   
 /*  
  *  
  * ./a.out -i -lr 'hi there' -f fred.c -q  
  *  
  * */  
 int main(int argc, char *argv[])  
 {  
   int opt;  
   while((opt = getopt(argc, argv, ":if:lr")) != -1) {  
     switch(opt) {  
     case 'i':  
     case 'l':  
     case 'r':  
       printf("option: %c\n", opt);  
       break;  
     case 'f':  
       printf("filename: %s\n", optarg);  
       break;  
     case ':':  
       printf("option needs a value\n");  
       break;  
     case '?':  
       printf("unknown option: %c\n", optopt);  
       break;  
     }  
   }  
   for(; optind < argc; optind++)  
     printf("argument: %s\n", argv[optind]);  
   exit(0);  
 }  
   

Compile & Execute:
 $ gcc getopt.c  
 $ ./a.out -i  
 option: i  
 $   
 $ ./a.out -i 5  
 option: i  
 argument: 5  
 $   
 $   
 $ ./a.out -f  
 option needs a value  
 $   
 $ ./a.out -f fread.c  
 filename: fread.c  
 $   
 $ ./a.out -q  
 unknown option: q  
 $   
 $   
 $ ./a.out -lr  
 option: l  
 option: r  
 $   
 $ ./a.out -i -lr 'hi there' -f fred.c -q  
 option: i  
 option: l  
 option: r  
 filename: fred.c  
 unknown option: q  
 argument: hi there  
   

Ex2:
getopt2.c
 #include <unistd.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <getopt.h>  
   
 /** Program to calculate the area and perimeter of   
  * a rectangle using command line arguments  
  */  
 void print_usage() {  
   printf("Usage: rectangle [ap] -l num -b num\n");  
 }  
   
 int main(int argc, char *argv[]) {  
   int option = 0;  
   int area = -1, perimeter = -1, breadth = -1, length =-1;  
   
   //Specifying the expected options  
   //The two options l and b expect numbers as argument  
   while ((option = getopt(argc, argv,"apl:b:")) != -1) {  
     switch (option) {  
        case 'a' : area = 0;  
          break;  
        case 'p' : perimeter = 0;  
          break;  
        case 'l' : length = atoi(optarg);   
          break;  
        case 'b' : breadth = atoi(optarg);  
          break;  
        default: print_usage();   
          exit(EXIT_FAILURE);  
     }  
   }  
   if (length == -1 || breadth ==-1) {  
     print_usage();  
     exit(EXIT_FAILURE);  
   }  
   
   // Calculate the area  
   if (area == 0) {  
     area = length * breadth;  
     printf("Area: %d\n",area);  
   }  
   
   // Calculate the perimeter  
   if (perimeter == 0) {  
     perimeter = 2 * (length + breadth);  
     printf("Perimeter: %d\n",perimeter);  
   }  
   return 0;  
 }  

2. getopt_long

 struct option {  
   const char *name;  
   int has_arg;  
   int *flag;  
   int val;  
 };  

Option Member Description
name The name of the long option. Abbreviations will be accepted as longas they cannot be confused with other options.
has_arg Whether this option takes an argument. Set to 0 for options that donot take an argument, 1 for options that must have a value, and 2 forthose that have an optional argument.
flag Set to NULL to have getopt_long return the value given in val whenthis option is found. Otherwise, getopt_long returns 0 and writesthe value of val into the variable pointed to by flag .
val The value getopt_long is to return for this option.


Ex:
getopt_long.c
 #include <stdio.h>  
 #include <unistd.h>  
 #include <stdlib.h>  
   
 #define _GNU_SOURCE  
 #include <getopt.h>  
   
 /*  
  *  
  * ./longopt --init –l --file=fred.c 'hi there'  
  *  
  * */  
 int main(int argc, char *argv[])  
 {  
   int opt;  
   struct option longopts[] = {  
   {"initialize", 0, NULL, 'i'},  
   {"file", 1, NULL, 'f'},  
   {"list", 0, NULL, 'l'},  
   {"restart", 0, NULL, 'r'},  
   {0,0,0,0}};  
   while((opt = getopt_long(argc, argv, ":if:lr", longopts, NULL)) != -1) {  
     switch(opt) {  
     case 'i':  
     case 'l':  
     case 'r':  
       printf("option: %c\n", opt);  
       break;  
     case 'f':  
       printf("filename: %s\n", optarg);  
       break;  
     case ':':  
       printf("option needs a value\n");  
       break;  
     case '?':  
       printf("unknown option: %c\n", optopt);  
       break;  
     }  
   }  
   for(; optind < argc; optind++)  
     printf("argument: %s\n", argv[optind]);  
   exit(0);  
 }  
   

Execute:
 $ ./longopt --init –l --file=fred.c ‘hi there’  
 option: i  
 option: l  
 filename: fred.c  
 argument: hi there  

Friday, July 31, 2015

The Linux Environment


Một chương trình khi chạy không chỉ có mình nó mà trong một không gian bao gồm nhiều thành phần khác mà nó sẽ tương tác với chúng, đó có thể là các đối số đầu vào của chương trình, các biến môi trường, các tiện ích hệ thống khác... tất cả chúng gọi chung là môi trường Linux.
Trong chương này sẽ đề cập đến các vấn đề sau:
+ Passing arguments to programs
+ Environment variables
+ Finding out what the time is
+ Temporary files
+ Getting information about the user and the host computer
+ Causing and configuring log messages
+ Discovering the limits imposed by the system


Thursday, July 30, 2015

Advanced Topics: fcntl and mmap

1. fcntl
 #include <unistd.h>   
 #include <fcntl.h>   
   
 int fcntl(int fd, int cmd);   
 int fcntl(int fd, int cmd, long arg);   
 int fcntl(int fd, int cmd, struct flock *lock);   

fcntc system call cung cấp một phương tiện để tác động đến low-level file descriptor. Một số thao tác như duplicating file descriptor, getting and setting file descriptor flags, getting and setting file descriptor status flags, file locking.

Chi tiết fcntl.

2. mmap
 #include <sys/mman.h>   
   
 void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);   
 int munmap(void *start, size_t length);   

mmap cung cấp một share memory để cho nhiều chương trình có thể cùng truy cập.

Chi tiết mmap.


Errors


Trong quá trình thực hiện các function, không phải lúc nào cũng thành công; một số các lỗi sẽ được liệt kê dưới đây thông qua mã lỗi errno nằm trong thư viện errono.h:
+ EPERM : Operation not permitted
+ ENOENT : No such file or directory
+ EINTR : Interrupted system call
+ EIO : I/O Error
+ EBUSY : Device or resource busy
+ EEXIST : File exists
+ EINVAL : Invalid argument
+ EMFILE : Too many open files
+ ENODEV : No such device
+ EISDIR : Is a directory
+ ENOTDIR : Isn’t a directory

Các hàm strerror và perror có mối liên hệ với giá trị của mã lỗi errno.

1. strerror
 #include <string.h>  
 char *strerror(int errnum);  

+ errnum
Mã lỗi, bằng giá trị errno.
+ return
Trả về string biểu diễn lý do lỗi.

2. perror
 #include <stdio.h>  
 void perror(const char *s);  

In ra lỗi tương ứng với errno.
+ s
Chuỗi thông tin được in kèm với lỗi.

Ex:
error.c
 #include<stdio.h>  
 #include<errno.h>  
 #include<string.h>  
   
 int main(void)  
 {  
   FILE *fd = NULL;  
   
   // Reset errno to zero before calling fopen().  
   errno = 0;  
   
   // Lets open a file that does not exist  
   fd = fopen("Linux.txt","r");  
   if(errno || (NULL == fd))  
   {  
     // Use strerror to display the error string  
   
 #if 1  
     perror("The function fopen failed due to");  
 #else  
     printf("The function fopen failed due to %s \n", strerror(errno));  
 #endif  
     return -1;  
   }  
   
   return 0;  
 }  
   



Scanning Directories


Scan thư mục là một công việc cơ bản được thực hiện khi chúng ta mở  Window Explorer để duyệt thư mục. Trong lập trình hệ thống nhúng thường dùng scan khi bạn cắm USB vào.
Dưới đây là một số function được dùng:
+ opendir
+ readdir
+ telldir
+ seekdir
+ closedir

Cấu trúc chứa thông tin về file/directory được chứa trong các struct cung cấp bởi các thư viện stat.h và dirent.h.

1. opendir
 #include <sys/types.h>  
 #include <dirent.h>  
 DIR *opendir(const char *name);  

opendir mở thư mục và khởi tạo một directory stream.
+ name
Đường dẫn đến thư mục muốn mở.
+ return
Trả về con trỏ đến cấu trúc DIR, trả về NULL nếu lỗi.

2. readdir
 #include <sys/types.h>  
 #include <dirent.h>  
 struct dirent *readdir(DIR *dirp);  

readdir đọc thư mục.
+ dirp
Con trỏ DIR được trả về từ opendir.
+ return
Trả về con troe đến cấu trúc dirent diễn tả chi tiết về thư mục được đọc. Trả về NULL khi đọc hết thư mục hoặc có lỗi, errno lưu trữ mã lỗi.

struct dirent chứa hai trường cơ bản:
+ ino_t d_ino : The inode of the file
+ char d_name[] : The name of the file

3. telldir
 #include <sys/types.h>  
 #include <dirent.h>  
 long int telldir(DIR *dirp);

telldir trả về vị trí hiện tại trong directory stream.

4. seekdir
 #include <sys/types.h>  
 #include <dirent.h>  
 void seekdir(DIR *dirp, long int loc);  

seekdir di chuyển vị trí của con trỏ directory stream.
+ dirp
Directory stream.
+ loc
Vị trí ofset so với vị trí hiện tại của con trỏ (có được từ telldir)

5. closedir
 #include <sys/types.h>  
 #include <dirent.h>  
 int closedir(DIR *dirp); 

Đóng directory stream.

Ex:
scandir.c
 #include <unistd.h>  
 #include <stdio.h>  
 #include <dirent.h>  
 #include <string.h>  
 #include <sys/stat.h>  
 #include <stdlib.h>  
   
 void printdir(char *dir, int depth)  
 {  
   DIR *dp;  
   struct dirent *entry;  
   struct stat statbuf;  
   if((dp = opendir(dir)) == NULL) {  
     fprintf(stderr,"cannot open directory: %s\n", dir);  
     return;  
   }  
   chdir(dir);  
   while((entry = readdir(dp)) != NULL) {  
     lstat(entry->d_name,&statbuf);  
     if(S_ISDIR(statbuf.st_mode)) {  
       /* Found a directory, but ignore . and .. */  
       if(strcmp(".",entry->d_name) == 0 ||  
           strcmp("..",entry->d_name) == 0)  
         continue;  
       printf("%*s%s/\n",depth,"",entry->d_name);  
       /* Recurse at a new indent level */  
       printdir(entry->d_name,depth+4);  
     }  
     else printf("%*s%s\n",depth,"",entry->d_name);  
   }  
   chdir("..");  
   closedir(dp);  
 }  
   
 int main(int argc, char **argv)  
 {  
   if(argc != 2) return;  
   printf("Directory scan of %s:\n", argv[1]);  
   printdir(argv[1],0);  
   exit(0);  
 }  
   

Compile & Execute:
 $ gcc scandir.c   
 $ ./a.out /home/ninhld/Github/eslinuxprogramming  
 Directory scan of /home/ninhld/Github/eslinuxprogramming:  
 simple_read.c  
 gets.c  
 dup2.c  
 dup.c  
 chmod.c   
 lseek.c  

Wednesday, July 29, 2015

File and Directory Maintenance

Bìa viết liên quan:
+ Users and Groups
+ File Permissions

1. chmod
 #include <sys/stat.h>  
 int chmod(const char *path, mode_t mode);  

Hàm chmod trong C tương tự như lệnh chmod trong Shell.
+ path
Đường dẫn đến file/directory.
+ mode
Quyền sẽ cấp cho file/directory.
mode là phép OR của các quyền được define trong stat.h như dưới đây:
 S_IRUSR                    /* Read by owner. */  
 S_IWUSR                    /* Write by owner. */  
 S_IXUSR                    /* Execute by owner. */  
   
 S_IRGRP                    /* Read by group. */  
 S_IWGRP                    /* Write by group. */  
 S_IXGRP                    /* Execute by group. */  
   
 S_IROTH                    /* Read by others. */  
 S_IWOTH                    /* Write by others. */  
 S_IXOTH                    /* Execute by others. */  

+ return
Trả về 0 nếu thành công; trả về -1 nếu lỗi, errno chỉ ra lỗi.

Ex:
chmod.c
 #include <stdio.h>  
 #include <sys/stat.h>  
   
 int main(int argc, char **argv)  
 {  
   
   const char *path="/home/ninhld/Github/eslinuxprogramming/testfile.txt";  
   chmod(path, S_IRUSR|S_IRGRP|S_IROTH);  
   
   return 0;  
 }  
   

Execute
 $ ls -l  
 total 68  
 -rwxr-xr-x. 1 ninhld ninhld 139 Jul 26 10:21 testfile.txt  
 $   
 $ gcc chmod.c   
 $ ./a.out   
 $ ls -l  
 total 68  
 -r--r--r--. 1 ninhld ninhld 139 Jul 26 10:21 testfile.txt  

2. chown
 #include <sys/types.h>  
 #include <unistd.h>  
 int chown(const char *path, uid_t owner, gid_t group);  

Thay chủ sở hữu, chương trình cần chạy ở chế độ superuser.
+ path
Đương dẫn đễn file.
+ owner
ID của  chủ sở hữu mới.
+ group
ID của nhóm sở hữu mới.
+ return
Trả về 0 nếu thành công; trả về -1 nếu lỗi, errno chỉ ra lỗi.

Ex:
chown.c (thay đổi chủ sở hữu và nhóm sở hữu thành root và root)
 #include <stdio.h>  
 #include <sys/stat.h>  
 #include <sys/types.h>  
 #include <unistd.h>  
   
 int main(int argc, char **argv)  
 {  
   
   
   uid_t uid = getuid();  
   gid_t gid = getgid();  
   
   printf("current uid: %d, gid: %d \n", uid, gid);  
   
   int ret;  
   ret = chown("/home/ninhld/Github/eslinuxprogramming/testfile.txt",  
      0,  
      0);  
   printf("ret: %d \n", ret);  
   
   
   return 0;  
 }  
   

Execute
 $ ls -l  
 total 72  
 -rwxr-xr-x. 1 ninhld ninhld 139 Jul 26 10:21 testfile.txt  
 $   
 $ gcc chown.c   
 $ su  
 #   
 # ./a.out   
 current uid: 0, gid: 0   
 ret: 0   
 #   
 # ls -l  
 total 72  
 -rwxr-xr-x. 1 root  root  139 Jul 26 10:21 testfile.txt  
   

3. unlink, link and symlink
 #include <unistd.h>  
 int unlink(const char *path);  
 int link(const char *path1, const char *path2);  
 int symlink(const char *path1, const char *path2);  

link tạo ra một alias cho một file.
symlink tạo alias cho file/directory.
unlink làm ngược lại so với link và symlink.
+ path1
Đường dẫn file/directory đã tồn tại.
+ path2
Đường dẫn đến file/directory là alias của path1, path2 sẽ được tự động tạo ra.
+ path
Đường dẫn đến file/directory là alias cần được loại bỏ.
+ return
Trả về o nếu thành công.

Ex:
link.c
 #include <stdio.h>  
 #include <unistd.h>  
   
 int main(int argc, char **argv)  
 {  
   
   const char *from = "/home/ninhld/Github/eslinuxprogramming/testfile.txt";  
   const char *to = "/home/ninhld/Github/eslinuxprogramming/test-file.txt";  
   
   int ret = link(from, to); //or symlink
   printf("ret: %d \n", ret);  
   
   return 0;  
 }  
   

4. mkdir and rmdir
 #include <sys/types.h>  
 #include <sys/stat.h>  
 int mkdir(const char *path, mode_t mode);  

 #include <unistd.h>  
 int rmdir(const char *path);  

Các hàm tạo và xóa thư mục.

5. chdir and getcwd
 #include <unistd.h>  
 int chdir(const char *path);
 char *getcwd(char *buf, size_t size);  

chdir chuyển thư mục, tương đương lệnh "cd" trong Shell.
getcwd ghi tên thư mục hiện tại vào buf, size = sizeof(buf) kích thước buf, tương tự lệnh pwd trong Shell.

Formatted Input and Output


1. printf, sprintf and fprintf
 #include <stdio.h>  
 int printf(const char *format, ...);  
 int sprintf(char *s, const char *format, ...);  
 int fprintf(FILE *stream, const char *format, ...);  

printf xuất dữ liệu ra stdout.
sprintf ghi dữ liệu vào buffer được trỏ bởi s.
fprintf ghi dữ liệu vào stream.

Ex:
sprintf.c
 /* sprintf example */  
 #include <stdio.h>  
   
 int main ()  
 {  
  char buffer [50];  
  int n, a=5, b=3;  
  n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);  
  printf ("[%s] is a string %d chars long\n",buffer,n);  
  return 0;  
 }  

fprintf.c
 /* fprintf example */  
 #include <stdio.h>  
   
 int main ()  
 {  
   FILE * pFile;  
   int n;  
   char name [100];  
   
   pFile = fopen ("myfile.txt","w");  
   for (n=0 ; n<3 ; n++)  
   {  
    puts ("please, enter a name: ");  
    gets (name);  
    fprintf (pFile, "Name %d [%-10.10s]\n",n+1,name);  
   }  
   fclose (pFile);  
   
   return 0;  
 }  

2. scanf, fscanf, and sscanf
 #include <stdio.h>  
 int scanf(const char *format, ...); 
 int sscanf(const char *s, const char *format, ...); 
 int fscanf(FILE *stream, const char *format, ...);     

scanf đọc dữ liệu từ stdin và lưu trên format.
sscanf đọc dữ liệu từ buffer s và lưu trên format.
fscanf đọc dữ liệu từ stream và lưu trên format.

Ex:
scanf.c
 /* scanf example */  
 #include <stdio.h>  
   
 int main ()  
 {  
  char str [80];  
  int i;  
   
  printf ("Enter your family name: ");  
  scanf ("%79s",str);   
  printf ("Enter your age: ");  
  scanf ("%d",&i);  
  printf ("Mr. %s , %d years old.\n",str,i);  
  printf ("Enter a hexadecimal number: ");  
  scanf ("%x",&i);  
  printf ("You have entered %#x (%d).\n",i,i);  
    
  return 0;  
 }  

sscanf.c
 /* sscanf example */  
 #include <stdio.h>  
   
 int main ()  
 {  
  char sentence []="Rudolph is 12 years old";  
  char str [20];  
  int i;  
   
  sscanf (sentence,"%s %*s %d",str,&i);  
  printf ("%s -> %d\n",str,i);  
    
  return 0;  
 }  

fscanf.c
 /* fscanf example */  
 #include <stdio.h>  
   
 int main ()  
 {  
  char str [80];  
  float f;  
  FILE * pFile;  
   
  pFile = fopen ("myfile.txt","w+");  
  fprintf (pFile, "%f %s", 3.1416, "PI");  
  rewind (pFile);  
  fscanf (pFile, "%f", &f);  
  fscanf (pFile, "%s", str);  
  fclose (pFile);  
  printf ("I have read: %f and %s \n",f,str);  
  return 0;  
 }  


Monday, July 20, 2015

The Standard I/O Library


Standard I/O Library là thư viện vào/ra chuẩn, có file header là stdio.h. Thư viện cung cấp một tập các low-level I/O system calls. Như đã trình bày ở phần Low-Level File Access, file descriptor là thông số liên hệ với file/device được mở ra để thao tác; trong thư viện stdio, thông số stream có ý nghĩa tương đương với file descriptor, và stream được thể hiện qua cấu trúc FILE.
Ba file stream được tự động mở khi hệ thống khởi động được liệt kê dưới đây:
+ 0: Standard input, stdin (keyboard, mouse)
+ 1: Standard output, stdout (screen)
+ 2: Standard error, stderr (screen)

Trong bài viết này, một số hàm trong stdio dưới đây được đề cập đến:
+ fopen , fclose
+ fread , fwrite
+ fflush
+ fseek
+ fgetc , getc , getchar
+ fputc , putc , putchar
+ fgets , gets
+ fputs, puts

1. fopen
 #include <stdio.h>  
 FILE *fopen(const char *filename, const char *mode);  

+ filename
Đường dẫn đến file cần mở
+ mode
Chế độ mở file để làm gì

mode Description
"r" or "rb" Open for reading only
"w" or "wb" Open for writing, truncate to zero length
"a" or "ab" Open for writing, append to end of file
"r+" or "rb+" or "r+b" Open for update (reading and writing)
"w+" or "wb+" or "w+b" Open for update, truncate to zero length
"a+" or "ab+" or "a+b" Open for update, append to end of file

Với "r" chỉ có thể mở được file text (Ex: filename.txt); "b" nghĩa là binary file, với "rb" có thể mở file với đuôi mở rộng bất kỳ để đọc nội dung (Ex: filename.c).
+return
Trả về con trỏ FILE * non-null, trả về null nếu thất bại.

2. fread
 #include <stdio.h>  
 size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);  

+ ptr
Buffer chứa dữ liệu đọc được
+ size
Kích thước tính bằng byte của mỗi phần tử
+ nitems
Số phần tử muốn đọc
+ stream
Stream để đọc
+ return
Trả về số phần tử (items) đã đọc được, return items <= nitems, số byte đã đọc được: (return items) * size

Ex:
fread.c
 #include <stdio.h>  
 #include <string.h>  
   
 int main()  
 {  
   FILE *fp = NULL;  
   int nread;  
   char buffer[100];  
   memset(buffer, '\0', sizeof(buffer));  
   
   /* Open file for both reading */  
   fp = fopen("testfile.dt", "rb");  
   if(!fp) return 1;  
   
   /* Read and display data */  
   nread = fread(buffer, sizeof(char), 100, fp);  
   printf("nread: %d, str: %s\n", nread, buffer);  
   
   memset(buffer, '\0', sizeof(buffer));  
   nread = fread(buffer, sizeof(char)*2, 10, fp);  
   printf("nread: %d, str: %s\n", nread, buffer);  
   
   fclose(fp);  
   return(0);  
 }  
   

3. fwrite
 #include <stdio.h>  
 size_t fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream);  

+ ptr
Buffer chứa dữ liệu để ghi xuống stream
+ size
Kích thước tính bằng byte của mỗi phần tử
+ nitems
Số phần tử muốn ghi
+ stream
Stream để ghi
+ return
Trả về số phần tử (items) đã ghi được, return items <= nitems, số byte đã ghi được: (return items) * size

Ex:
fwrite.c
 /* fwrite example : write buffer */  
 #include <stdio.h>  
   
 int main ()  
 {  
  FILE * pFile;  
  char buffer[] = { 'x' , 'y' , 'z' };  
  pFile = fopen ("myfile.bin", "wb");  
  fwrite (buffer , sizeof(char), sizeof(buffer), pFile);  
  fclose (pFile);  
  return 0;  
 }  

4. fclose
 #include <stdio.h>  
 int fclose(FILE *stream);  

+ stream
Stream muốn đóng.
+ return
Trả về 0 nếu đóng thành công.

5. fflush
 #include <stdio.h>  
 int fflush(FILE *stream);  

fflush là thao tác thường được dùng sau các thao tác ghi dữ liệu xuống stream như fwrite để chắc chắn rằng mọi dữ liệu muốn ghi sẽ được hoàn thành trước khi bạn muốn thực hiện các thao tác khác với stream.
+ stream
Stream muốn flush.
+ return
Trả về 0 nếu thành công.

Ex:
fflush.c
 /* fflush example */  
 #include <stdio.h>  
 char mybuffer[80];  
 int main()  
 {  
   FILE * pFile;  
   pFile = fopen ("example.txt","r+");  
   if (pFile == NULL) perror ("Error opening file");  
   else {  
    fputs ("test",pFile);  
    fflush (pFile);  // flushing or repositioning required  
    fgets (mybuffer,80,pFile);  
    puts (mybuffer);  
    fclose (pFile);  
    return 0;  
  }  
 }  

6. fseek
fseek sẽ di chuyển con trỏ đến vị trí khác trong stream đang được mở.
 #include <stdio.h>  
 int fseek(FILE *stream, long int offset, int whence);  

+ stream
Stream đang mở
+ offset
Vị trí sẽ nhảy đến, tính bằng byte
+ whence
Điểm mốc để tính vị trí nhảy đến offset, có giá trị tương tự như với lseek.
+ return
Trả về 0 nếu thành công; -1 nếu lỗi, thông báo lỗi lưu trong errno.

Ex:
fseek.c
 /* fseek example */  
 #include <stdio.h>  
   
 int main ()  
 {  
  FILE * pFile;  
  pFile = fopen ( "example.txt" , "wb" );  
  fputs ( "This is an apple." , pFile );  
  fseek ( pFile , 9 , SEEK_SET );  
  fputs ( " sam" , pFile );  
  fclose ( pFile );  
  return 0;  
 }  

7. fgetc, getc, and getchar
 #include <stdio.h>  
 int fgetc(FILE *stream);  
 int getc(FILE *stream);  
 int getchar();  

fgetc và getc là tương đương, đều đọc từng byte từ stream (mỗi lần đọc 1 byte).
getchar() tương đương với getc(stdin), đọc từng byte từ stdin.

+ stream
Stream để đọc
+ return
Trả về ký tự đọc được theo bảng mã ASCII (Ex: return 65 tương đương với ký tự A), trả về EOF nếu hết file hoặc lỗi.

Ex:
fgetc.c
 /* fgetc example: money counter */  
 #include <stdio.h>  
 int main ()  
 {  
  FILE * pFile;  
  int c;  
  int n = 0;  
  pFile=fopen ("myfile.txt","r");  
  if (pFile==NULL) perror ("Error opening file");  
  else  
  {  
   do {  
    c = fgetc (pFile);  
    if (c == '$') n++;  
   } while (c != EOF);  
   fclose (pFile);  
   printf ("The file contains %d dollar sign characters ($).\n",n);  
  }  
  return 0;  
 }  

getc.c
 /* getc example: money counter */  
 #include <stdio.h>  
 int main ()  
 {  
  FILE * pFile;  
  int c;  
  int n = 0;  
  pFile=fopen ("myfile.txt","r");  
  if (pFile==NULL) perror ("Error opening file");  
  else  
  {  
   do {  
    c = getc (pFile);  
    if (c == '$') n++;  
   } while (c != EOF);  
   fclose (pFile);  
   printf ("File contains %d$.\n",n);  
  }  
  return 0;  
 }  

getchar.c
 /* getchar example : typewriter */  
 #include <stdio.h>  
   
 int main ()  
 {  
  int c;  
  puts ("Enter text. Include a dot ('.') in a sentence to exit:");  
  do {  
   c=getchar();  
   putchar (c);  
  } while (c != '.');  
  return 0;  
 }  

8. fputc, putc, and putchar
 #include <stdio.h>  
 int fputc(int c, FILE *stream);  
 int putc(int c, FILE *stream);  
 int putchar(int c);  

Ngược lại mới các hàm ở mục 7, các hàm ở mục 8 sẽ ghi từng byte xuống stream (mỗi lần ghi 1 byte), putchar ghi byte xuống stdout.

+ c
Ký tự (byte) sẽ được ghi
+ stream
Strem để ghi xuống
+ return
Trả về ký tự vừa được ghi nếu thành công, trả về EOF nếu lỗi.

Hàm putchar ghi byte xuống stdout.

Ex:
fputc.c
 /* fputc example: alphabet writer */  
 #include <stdio.h>  
   
 int main ()  
 {  
  FILE * pFile;  
  char c;  
   
  pFile = fopen ("alphabet.txt","w");  
  if (pFile!=NULL) {  
   
   for (c = 'A' ; c <= 'Z' ; c++)  
    fputc ( c , pFile );  
   
   fclose (pFile);  
  }  
  return 0;  
 }  

putc.c
 /* putc example: alphabet writer */  
 #include <stdio.h>  
   
 int main ()  
 {  
  FILE * pFile;  
  char c;  
   
  pFile=fopen("alphabet.txt","wt");  
  for (c = 'A' ; c <= 'Z' ; c++) {  
   putc (c , pFile);  
   }  
  fclose (pFile);  
  return 0;  
 }  

putchar.c
 /* putchar example: printing the alphabet */  
 #include <stdio.h>  
   
 int main ()  
 {  
  char c;  
  for (c = 'A' ; c <= 'Z' ; c++) putchar (c);  
   
  return 0;  
 }  

9. fgets and gets
 #include <stdio.h>  
 char *fgets(char *s, int n, FILE *stream);  
 char *gets(char *s);  

fgets nhiều byte từ stream (khác với fgetc chỉ đọc 1 byte):
+ s
Buffer để chứa chuỗi ký tự được đọc từ stream.
+ n
Có tối đa (n-1) byte sẽ được đọc, byte cuối cùng dành cho ký tự new line '\0' sẽ được chèn vào liền sau byte cuối cùng. Có 3 điều kiện để fgets kết thúc việc đọc ghi đatj ít nhất 1 trong 3 điều kiện sau:
    - Đọc đủ (n-1) byte
    - Chưa đọc đủ (n-1) nhưng gặp ký tự new line
    - Chưa đọc đủ (n-1) nhưng hết file (gặp End-Of-File - EOF)
+ stream
Stream để đọc.
+ return
Trả về con trỏ s nếu thành công, trả về NULL nếu gặp EOF hoặc có lỗi xảy ra.

gets đọc nhiều byte từ stdin (khác với getc chỉ đọc 1 byte)
+ Buffer để chứa chuỗi ký tự được đọc từ stdin.
+ return
Trả về con trỏ s nếu thành công, trả về NULL nếu gặp EOF hoặc có lỗi xảy ra.

Ex:
fgets.c
 /* fgets example */  
 #include <stdio.h>  
   
 int main()  
 {  
   FILE * pFile;  
   char mystring [100];  
   
   pFile = fopen ("testfile.txt" , "r");  
   if (pFile == NULL) perror ("Error opening file");  
   else {  
     if ( fgets (mystring , 10 , pFile) != NULL )  
       puts (mystring);  
     fclose (pFile);  
   }  
   return 0;  
 }  
   

gets.c
 /* gets example */  
 #include <stdio.h>  
   
 int main()  
 {  
   char string [256];  
   printf ("Insert your full address: ");  
   gets (string);   // warning: unsafe (see fgets instead)  
   printf ("Your address is: %s\n",string);  
   return 0;  
 }  
   

10. fputs, puts
 # include <stdio.h>  
 int fputs ( const char * str, FILE * stream );  
 int puts ( const char * str );  

fputs ghi chuỗi nhiều ký tự (nhiều byte) xuống stream, puts ghi chuỗi ký tự xuống stdout.
+str
Buffer chứa chuỗi ký tự để ghi.
+ stream
Stream để ghi xuống.
+ return
Trả về số không âm ( > 0) nếu thành công, trả về EOF nếu lỗi.

Ex:
fputs.c
 /* fputs example */  
 #include <stdio.h>  
   
 int main ()  
 {  
   FILE * pFile;  
   char sentence [256];  
   
   printf ("Enter sentence to append: ");  
   fgets (sentence,256,stdin);  
   pFile = fopen ("mylog.txt","a");  
   fputs (sentence,pFile);  
   fclose (pFile);  
   return 0;  
 }  

puts.c
 /* puts example : hello world! */  
 #include <stdio.h>  
   
 int main ()  
 {  
  char string [] = "Hello world!";  
  puts (string);  
 }  


Low-Level File Access

1. File Descriptor
Khi bạn muốn điều khiển một file/device, việc đầu tiên là phải open file/device đó, việc open sẽ trả về cho bạn một con số kiểu int có mối liên hệ với file/device bạn vừa mở, được gọi là File Descriptor. Các thao tác read, write, ioctl, close sau này sẽ thao tác trên file descriptor).
Khi khởi động hệ thống linux thì sẽ có 3 file desciptor mặc định được tạo ra như dưới đây:
+ 0: Standard input (keyboard, mouse)
+ 1: Standard output (screen)
+ 2: Standard error (screen)

Ex: Đọc tên từ bàn phím và print ra màn hình
 #!/bin/sh   
 echo "Type your name !"  
 read your_name  
 echo "Your name: $your_name"  

 $ ./test.sh   
 Type your name !  
 Obama  
 Your name: Obama  

2. Low-level File Access
2.1 open
 #include <fcntl.h>  
 #include <sys/types.h>  
 #include <sys/stat.h>  
   
 int open(const char *path, int oflags);              //(1)
 int open(const char *path, int oflags, mode_t mode); //(2)
 int creat(const char *pathname, mode_t mode);        //(3)

+ path
Là đường dẫn đến file (/home/ninhld/Documents/test.txt) hoặc device (/dev/ttyUSB0)
+ oflags
oflags là cờ chỉ ra kiểu truy cập như bảng dưới đây, oflags có thể được kết hợp bởi nhiều kiểu/thuộc tính với nhau thông qua phép OR .

oflags Description
O_RDONLY Open for read-only
O_WRONLY Open for write-only
O_RDWR Open for reading and writing

Ex:
 open("/home/ninhld/Documents/test.txt", O_WRONLY);  
 open("/dev/ttyUSB0", O_RDWR);  

oflags còn được dùng với các giá trị dưới đây để biểu diễn cách thức mở hoặc tạo ra một file mới chưa tồn tại, các cờ sau còn được gọi là file creation flag:

oflags Description
O_APPEND Place written data at the end of the file
O_TRUNC Set the length of the file to zero, discarding existing contents
O_CREAT Creates the file, if necessary, with permissions given in mode
O_EXCL Used with O_CREAT , ensures that the caller creates the file. The open is atomic; that is,it’s performed with just one function call. This protects against two programs creating the file atthe same time. If the file already exists, open will fail

+ mode
mode chỉ ra quyền truy cập - permission khi oflags = O_CREAT

mode Description
S_IRUSR Read permission, owner
S_IWUSR Write permission, owner
S_IXUSR Execute permission, owner
S_IRGRP Read permission, group
S_IWGRP Write permission, group
S_IXGRP Execute permission, group
S_IROTH Read permission, others
S_IWOTH Write permission, others
S_IXOTH Execute permission, others
Bài viết liên quan: File Permissions

Ex:
 open ("/home/ninhld/Documents/test.txt", O_CREAT, S_IRUSR|S_IXOTH);  

+ return
Trả về file descriptor > 0 nếu open thành công.

Hàm creat tương tự như open với oflags = O_CREAT|O_WRONLY|O_TRUNC

2.2 write
 #include <unistd.h>  
 size_t write(int fildes, const void *buf, size_t nbytes);  

+ fildes
File desriptor.
+ buf
Buffer có chưa giá trị để ghi.
+ nbytes
Số byte muốn ghi, nbytes <= sizeof(buf)
+ return
Số byte thực sự được ghi, lưu ý return byte <= nbytes; nếu return về 0 thì không có byte nào được ghi, nếu return về -1 thì có lỗi xảy ra.

Ex:
simple_write.c
 #include <unistd.h>  
 #include <stdlib.h>  
   
 /*  
  * write string to standard output / error (screen)  
  */  
 int main()  
 {  
   if ((write(1, "Here is some data\n", 18)) != 18)  
     write(2, "A write error has occurred on file descriptor 1\n",46);  
   exit(0);  
 }  
   

 $ gcc simple_write.c   
 $ ./a.out   
 Here is some data  
   

2.3 read
 #include <unistd.h>  
 size_t read(int fildes, void *buf, size_t nbytes);  

+ fildes
File desriptor.
+ buf
Buffer để lưu giá trị đọc được.
+ nbytes
Số byte muốn đọc, thường là kích thước của buf (sizeof(buf)).
+ return
Số byte thực sự được đọc, lưu ý return byte <= nbytes

Ex:
simple_read.c
 #include <unistd.h>  
 #include <stdlib.h>  
   
 /*  
  * read from standard input (keyboard)  
  * write to standard output (screen)  
  */  
   
 int main()  
 {  
   char buffer[128];  
   int nread;  
   nread = read(0, buffer, 128);  
   if (nread == -1)  
     write(2, "A read error has occurred\n", 26);  
   if ((write(1,buffer,nread)) != nread)  
     write(2, "A write error has occurred\n",27);  
   exit(0);  
 }  

Compile & Execute:
 $ gcc simple_read.c   
 $ ./a.out   
 hello     
 hello  
   

2.4 ioctl
 #include <unistd.h>  
 int ioctl(int fildes, int cmd, ...);  

+ fildes
File descriptor
+ cmd
Chỉ ra thao tác cần thực hiện với fildes, nó có thể là tổ hợp của nhiều thao tác thông qua phép OR.
+ ...
Các đối số để truyền dữ liệu đi kèm với cmd tương ứng.

ioctl viết tắt của Input Output Control, function này thường được dùng với file desciptor liên hệ với device chứ không dùng với file dữ liệu thông thường.
ioctl là một hàm mở rộng hơn của các hàm read/write để thực hiện thêm nhiều thao tác khác ngoài các thao tác đọc/ghi cơ bản, vì thế ioctl hoàn toàn có thể thay thế đươc read/write. Lưu ý với mỗi cmd được dùng thì dưới device driver cần được implement các thao tác tương ứng với cmd.

Ex:
 ioctl(sock_fd, CMD_SET, &data);  

2.5 close
 #include <unistd.h>  
 int close(int fildes);  

+ fildes
File descriptor cần đóng
+ return
Trả về 0 nếu đóng thành công, trả về -1 nếu xảy ra lỗi

2.6 Ví dụ
copy_system.c
 #include <unistd.h>  
 #include <sys/stat.h>  
 #include <fcntl.h>  
 #include <stdlib.h>  
   
 int main()  
 {  
   char c;  
   int in, out;  
   in = open("file.in", O_RDONLY);  
   out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);  
   while(read(in,&c,1) == 1)  
     write(out,&c,1);  
   exit(0);  
 }  
   

copy_block.c
 #include <unistd.h>  
 #include <sys/stat.h>  
 #include <fcntl.h>  
 #include <stdlib.h>  
   
 int main()  
 {  
   char block[1024];  
   int in, out;  
   int nread;  
   in = open("file.in", O_RDONLY);  
   out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);  
   while((nread = read(in,block,sizeof(block))) > 0)  
     write(out,block,nread);  
   exit(0);  
 }  
   

3. Other System Calls for Managing Files
3.1 lseek
 #include <unistd.h>  
 #include <sys/types.h>  
 off_t lseek(int fildes, off_t offset, int whence);  

+ fildes
File descriptor (thường liên hệ với file chứ không phải device)
+ offset
Khi mở file với hàm open, mặc định con trỏ sẽ trỏ đến vị trí đầu tiên của file; offset (tính bằng số byte) sẽ là vị trí mới của con trỏ sẽ nhảy đến.
+ whence
whence chỉ ra vị trí gọi là mốc để tính offset
+ return
lseek trả về offset tính từ vị trí mốc được xác định bởi whence, hoặc trả về -1 nếu có lỗi xảy ra.


mode Description
SEEK_SET offset is an absolute position
SEEK_CUR offset is relative to the current position
SEEK_END offset is relative to the end of the file



Ex:
lseek.c
 #include <stdio.h>  
 #include <unistd.h>  
 #include <fcntl.h>  
 #include <sys/types.h>   
 int main()  
 {  
   int file=0;  
   if((file=open("testfile.txt",O_RDONLY)) < -1)  
     return 1;  
   
   char buffer[19];  
   if(read(file,buffer,19) != 19) return 1;  
   printf("%s\n",buffer);  
   
   if(lseek(file,10,SEEK_SET) < 0) return 1;  
   
   if(read(file,buffer,19) != 19) return 1;  
   printf("%s\n",buffer);  
   
   return 0;  
 }  

Compile & Execute:
 $ gcc lseek.c  
 $ cat testfile.txt   
 This is a test file that will be used  
 to demonstrate the use of lseek.  
 $ ./a.out   
 This is a test file   
 test file that will  


3.2 fstat, stat, and lstat
 #include <unistd.h>  
 #include <sys/stat.h>  
 #include <sys/types.h>  
 int fstat(int fildes, struct stat *buf);  
 int stat(const char *path, struct stat *buf);  
 int lstat(const char *path, struct stat *buf);  

struct stat:

stat Member Description
st_mode File permissions and file-type information
st_mode The inode associated with the file
st_mode The device the file resides on
st_uid The user identity of the file owner
st_uid The group identity of the file owner
st_uid The time of last access
st_uid The time of last change to permissions, owner, group, or content
st_uid The time of last modification to contents
st_uid The number of hard links to the file

Lấy thông tin về trạng thái của file
+ fildes
File descriptor liên hệ với file đang mở
+ path
Đường dẫn đến file
+ buf
Cấu trúc để lưu trữ trông tin lấy được bởi fstat
+ return
Trả về giá trị âm nếu có lỗi.

Ex:
stat.c
 #include <unistd.h>  
 #include <stdio.h>  
 #include <sys/stat.h>  
 #include <sys/types.h>  
   
 int main(int argc, char **argv)  
 {  
   if(argc != 2)  
     return 1;  
   
   struct stat fileStat;  
   if(stat(argv[1],&fileStat) < 0)  
     return 1;  
   
   printf("Information for %s\n",argv[1]);  
   printf("---------------------------\n");  
   printf("File Size: \t\t%d bytes\n",fileStat.st_size);  
   printf("Number of Links: \t%d\n",fileStat.st_nlink);  
   printf("File inode: \t\t%d\n",fileStat.st_ino);  
   
   printf("File Permissions: \t");  
   printf( (S_ISDIR(fileStat.st_mode)) ? "d" : "-");  
   printf( (fileStat.st_mode & S_IRUSR) ? "r" : "-");  
   printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-");  
   printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-");  
   printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-");  
   printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-");  
   printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-");  
   printf( (fileStat.st_mode & S_IROTH) ? "r" : "-");  
   printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-");  
   printf( (fileStat.st_mode & S_IXOTH) ? "x" : "-");  
   printf("\n\n");  
   
   printf("The file %s a symbolic link\n", (S_ISLNK(fileStat.st_mode)) ? "is" : "is not");  
   
   return 0;  
 }  
   

Compile & Execute:
 $ gcc stat.c   
 $ ./a.out stat.c   
 Information for stat.c  
 ---------------------------  
 File Size:           1209 bytes  
 Number of Links:      1  
 File inode:           3039505  
 File Permissions:      -rw-rw-r--  
   
 The file is not a symbolic link  
   

3.3 dup and dup2
 #include <unistd.h>  
 int dup(int fildes);  
 int dup2(int fildes, int fildes2);  

Tạo ra một file descriptor mới cùng liên hệ với file đang mở.
+ fildes
File descriptor nguồn liên hệ với file đang mở.
+ fildes2
File descriptor đích cùng trỏ đến file mà fildes trỏ đến, dữ liệu từ file có liên hệ với fildes2 sẽ chuyển hướng đến file có liên hệ với fildes.
+ return
Trả về file descriptor mới, trả về giá trị âm nếu lỗi.

Ex:
dup.c
 #include <unistd.h> /*Included for dup(2) and write(2)*/  
 #include <stdlib.h> /*Included for exit(3)*/  
   
 #define MESSAGE "Hey! Who redirected me?\r\n\0"  
   
 int main() {  
   int newfd = dup(1); /*Call dup for an aliased fd*/  
   char buff[] = MESSAGE;  
   
   if (newfd < 0) { /*Negative file descriptors are errors*/  
     exit(EXIT_FAILURE);  
   }  
   else if (write(newfd, buff, sizeof(buff)) < 0) { /*See: man 2 write*/  
     exit(EXIT_FAILURE);  
   }  
   
   return EXIT_SUCCESS;  
 }  
   

Compile & Execute:
 $ gcc dup.c   
 $ ./a.out   
 Hey! Who redirected me?  
   


dup2.c
 #include <stdio.h>  
 #include <unistd.h>  
 #include <fcntl.h>  
   
   
 int main()  
 {  
   //First, we're going to open a file  
   int file = open("testfile.txt", O_APPEND | O_WRONLY);  
   if(file < 0)  return 1;  
   
   //Now we redirect standard output to the file using dup2  
   if(dup2(file, 1) < 0)  return 1;  
   
   //Now standard out has been redirected,  
   //we can write to the file  
   printf("This will print in testfile.txt\n");  
   
   return 0;  
 }//end of function main  
   

Compile & Execute:
 $ gcc dup2.c   
 $ cat testfile.txt   
 Hello, I am a testfile.txt  
 $ ./a.out   
 $ cat testfile.txt   
 Hello, I am a testfile.txt  
 This will print in myfile.txt  
 $ ./a.out   
 $ cat testfile.txt   
 Hello, I am a testfile.txt  
 This will print in myfile.txt  
 This will print in myfile.txt  



Sunday, July 19, 2015

- Copyright © Lập trình hệ thống nhúng Linux . Powered by Luong Duy Ninh -