Se sei interessato a scrivere la programmazione di sistema Linux, dovresti imparare tutte le librerie di base/chiamate di sistema. Questo articolo contiene un programma C di esempio che copre una serie di chiamate di sistema che ti aiuteranno a comprendere l'utilizzo di queste chiamate di libreria di base.
Il codice C di esempio riportato di seguito esegue le seguenti operazioni:
- Apre automaticamente alcuni terminali
- Visualizza il messaggio che la sessione è in esecuzione come root o non root
- Visualizza il messaggio sopra su tutti i terminali aperti
Di seguito sono elencate le 13 importanti librerie o chiamate di sistema che sono trattate nel codice di esempio seguente.
- memset() :questa funzione riempie i primi n byte dell'area di memoria indicata da s con il byte costante c.
- fopen() :questa funzione apre il file il cui nome è la stringa puntata dal suo primo argomento e gli associa un flusso.
- getcwd() :questa funzione restituisce una stringa con terminazione null contenente un percorso assoluto che è la directory di lavoro corrente del processo chiamante
- getuid() :questa funzione restituisce l'ID utente reale del processo chiamante
- snprintf() :questa funzione produce output in base a un formato e scrive l'output in un buffer.
- fwrite() :questa funzione viene utilizzata per scrivere dati in un flusso
- fflush() :questa funzione forza la scrittura di tutti i dati bufferizzati nello spazio utente su un flusso particolare
- fclose() :questa funzione svuota il flusso associato e chiude il descrittore di file sottostante.
- system() :questa funzione esegue un comando
- sleep() :questa funzione mette in standby il processo di chiamata finché non sono trascorsi i secondi specificati o non arriva un segnale che non viene ignorato.
- openir() :questa funzione apre un flusso di directory
- readdir() :questa funzione legge la directory che viene aperta come flusso
- atoi() :questa funzione converte l'argomento ascii in intero.
Quello che segue è il codice C che mostra come utilizzare tutte le 13 chiamate di sistema precedenti.
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<dirent.h> #include<sys/types.h> #include<pwd.h> // A buffer to hold current working directory char cwd[512]; void inform(char *path, char *binary_name) { // Declare variables for file operations FILE *fp = NULL; // A counter to be used in loop unsigned int counter = 0; // A buffer to hold the information message char msg[1024]; // memset function initializes the bytes // in the buffer 'msg' with NULL characters memset(msg, '\0', sizeof(msg)); memset(cwd, '\0', sizeof(cwd)); // Check for the path to be non NULL if(NULL== path) { printf("\n NULL path detected\n"); return; } // fopen will open the file represented // by 'path' in read write mode. fp = fopen(path,"r+"); if(!fp) { printf("\n Failed to open %s\n",path); return; } else { printf("\n Successfully opened %s\n",path); } // getcwd() gives us the current working directory // of the environemt from which this binary was // executed if(NULL == getcwd(cwd,sizeof(cwd))) { printf("\n Failed to get current directory\n"); return; } // getuid() returns the real user ID of the calling // process. // getuid() returns 0 for root and non zero for // any other user. if( 0 != getuid()) { // This functions fills the buffer 'msg' with the formatted string by replacing %s in the harcoded string with the appropriate values snprintf(msg,sizeof(msg),"\n\n\nYOU ARE NOT ROOT!!!!!"); } else { snprintf(msg, sizeof(msg),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nYOU ARE ROOT!!!!!!!!!!!!!!"); } // Make sure the information8 is printed 25 times on each // open terminal for(counter=0;counter<25;counter++) { printf("\n fwrite()\n"); // Write the information message on to the terminal fwrite(msg, strlen(msg), 1, fp); // Flush the message to the stdout of the terminal fflush(fp); // Wait for one second. sleep(1); } // close the file representing the terminal fclose(fp); } int main(int argc, char *argv[]) { // Since we will do some directory operations // So declare some variables for it. DIR *dp = NULL; struct dirent *ptr = NULL; // This variable will contain the path to // terminal char *path = NULL; // Used as a counter in loops int i =0; // Step1 : // Open 5 terminals each after 2 seconds // of delay. for(;i<5;i++) { // The system API executes a shell command // We try to execute two commands here // Both of these commands will open up // a terminal. We have used two commands // just in case one of them fails. system("gnome-terminal"); system("/usr/bin/xterm"); // This call is used to cause a delay in // program execution. The argument to this // function is the number of seconds for // which the delay is required sleep(2); } // Give user some 60 seconds before issuing // a information message. sleep(60); // Now, open the directory /dev/pts which // corresponds to the open command terminals. dp = opendir("/dev/pts"); if(NULL == dp) { printf("\n Failed to open /dev/pts\n"); return 0; } // Now iterate over each element in the // directory untill all the elements are // iterated upon. while ( NULL != (ptr = readdir(dp)) ) { // ptr->d_name gives the current device // name or the terminal name as a device. // All the numeric names correspond to // open terminals. // To check the numeric values we use // atoi(). // Function atoi() converts the ascii // value into integer switch(atoi(ptr->d_name)) { // Initialize 'path' accordingly case 0:path = "/dev/pts/0"; break; case 1: path = "/dev/pts/1"; break; case 2: path = "/dev/pts/2"; break; case 3: path = "/dev/pts/3"; break; case 4: path = "/dev/pts/4"; break; case 5: path = "/dev/pts/5"; break; case 6: path = "/dev/pts/6"; break; case 7: path = "/dev/pts/8"; break; case 9: path = "/dev/pts/9"; break; default: break; } if(path) { // Call this function to throw some information. // Pass the path to terminal where the information // is to be sent and the binary name of this // program inform(path, argv[0]); // Before next iteration, make path point to // NULL path = NULL; } } sleep(60); return 0; }
Lo stesso codice sopra è autoesplicativo in quanto contiene commenti adeguati che spiegano cosa fanno quelle chiamate di sistema. Se non conosci la programmazione di sistema Linux, questo codice offre sufficiente visibilità sull'utilizzo di tutte queste importanti funzioni. Per maggiori dettagli e un utilizzo avanzato, leggere attentamente le loro pagine man.
Questo codice è una simulazione di un divertente programma antivirus di base. Dopo aver compilato ed eseguito il programma c sopra, eseguirà le seguenti operazioni. Questo codice è stato testato su Linux Mint. Ma dovrebbe funzionare su tutti i derivati di Ubuntu.
- L'utente vedrà 5 terminali aprirsi uno per uno ciascuno dopo 1 secondo.
- Mentre l'utente si chiederà cosa è appena successo, tutti i suoi terminali aperti inizieranno lentamente a ricevere informazioni ripetute sul login come root o non root.
- Tieni presente che la registrazione del debug è abilitata nel codice per il tuo scopo di apprendimento, per favore commenta i printf di debug e poi eseguilo se vuoi divertirti.