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
...
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
+ 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:
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
+ 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:
+ 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
Compile & Execute:
Ex2:
getopt2.c
2. getopt_long
Ex:
getopt_long.c
Execute:
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
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
Advanced Topics: fcntl and mmap
1. fcntl
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
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.
#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
File and Directory Maintenance
Bìa viết liên quan:
+ Users and Groups
+ File Permissions
1. chmod
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:
+ 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
Execute
2. chown
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)
Execute
3. unlink, link and symlink
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
4. mkdir and rmdir
Các hàm tạo và xóa thư mục.
5. chdir and getcwd
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.
+ 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.
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;
}
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 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
gets.c
10. fputs, puts
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
puts.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
2. Low-level File Access
2.1 open
+ 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 .
Ex:
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:
+ mode
mode chỉ ra quyền truy cập - permission khi oflags = O_CREAT
Bài viết liên quan: File Permissions
Ex:
+ 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
+ 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
2.3 read
+ 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
Compile & Execute:
2.4 ioctl
+ 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:
2.5 close
+ 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
copy_block.c
3. Other System Calls for Managing Files
3.1 lseek
+ 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.
Ex:
lseek.c
Compile & Execute:
3.2 fstat, stat, and lstat
struct stat:
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
Compile & Execute:
3.3 dup and dup2
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
Compile & Execute:
dup2.c
Compile & Execute:
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 |
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.
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







