Showing posts with label Beginning Linux Programming. Show all posts
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
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:
facility value:
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
Compile & Execute (root user):
2. openlog
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:
+ 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
Compile & Execute:
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 đó:
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
Compile & Execute:
#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
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:
Unix/Linux cung cấp các API:
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.
struct utsname:
+ 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
Compile & Execute:
$ 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);
+ nameBufer, 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
Các thông tin trên được lưu trong /etc/passwd có dạng:
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:
2. Password Database
struct passwd:
Thông tin về Password Database được lưu trong /etc/passwd
Để lấy tât cả thông tin trong Password Database:
Ex1:
user.c
Compile & Execute:
Ex2:
getpwent.c
Compile & Execute:
+ 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.
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
Execute:
2. gmtime
struct tm:
Ex:
gmtime.c
Execute:
3. ctime
Ex:
ctime.c
4. localtime
Ex:
localtime.c
Execute:
5. gettimeofday
Ex:
gettimeofday.c
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;
}
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.
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
Compile & Execute:
2. The environ Variable
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
Compile & Execute:
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
...