Saturday, November 28, 2015

Save Edited File : FUSE & File System

Istilah Fuse tidak asing untuk beberapa orang. Istilah Fuse sering digunakan di game untuk istilah menggabungkan sesuatu. Namun Fuse yang digunakan pada sistem operasi berbeda. Fuse disini adalah Filesystem in Userspace (FUSE) yang merupakan mekanisme sistem operasi untuk sistem operasi Unix-like yang memungkinkan pengguna tidak ber-hak istimewa menciptakan file system mereka sendiri tanpa mengubah kode kernel. Hal ini dicapai dengan menjalankan kode file system di userspace, sedangkan modul FUSE hanya menyediakan "jembatan" untuk antarmuka kernel yang sebenarnya.


Cara mengompile & memasang Fuse :
1. pastikan FUSE sudah terinstal di Linux anda. jika belum, bisa di download di http://fuse.sourceforge.net/
cara install :
a. ekstrak hasil download
b. dari terminal masuk ke direktori hasil download nya
c. ketik ./configure, enter
d. ketik make dan enter
e. ketik make install dan enter

Nah, setelah penjelasan diatas muncul lagi istilah File System. File System adalah struktur logika yang digunakan untuk mengendalikan akses terhadap data yang ada pada harddisk. Terdapat berbagai jenis-jenisnya dan penggunaan algoritma yang berbeda. Semakin baru jenis dari sebuah File System, maka semakin bagus pula kualitas dari File System tersebut. 

Ada beberapa tipe dari File System yaitu:

1. File System Disk
2. File System Flash
3. File System Database
4. File System Transaksional
5. File System Jaringan
6. File System untuk Tujuan Khusus
7. File System Journaling

Salah satu yang bisa kita lakukan dengan fuse adalah mengamankan file kita, misal jika kita ingin membuat suatu fuse yang membuat suatu isi dari folder, jika kita edit filenya. Akan ada folder baru yang membuat file hasil editan langsung berpindah ke folder baru tesebut. Dan file aslinya tidak berubah sama sekali. Kemudian kita amankan file didalamnya agar tidak dapat dibukan dan diubah isinya.

Os yang saya gunakan untuk membuatnya adalah Linux Mint, dan Code Blocks(untuk mempermudah pembuatan file c). File C nya berisi:


#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <sys/stat.h>

static const char *dirpath = "/home/yaukings/Downloads/file";

static int xmp_getattr(const char *path, struct stat *stbuf)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = lstat(fpath, stbuf);

    if(res == -1)
    {
        return -errno;
    }

    return 0;
}

static int xmp_chmod(const char *path, mode_t mode)
{
    int res;
    char fpath[1000];
    char direktori[] = "/home/yaukings/Downloads/file/simpanan";
    //sprintf(fpath,"%s%s", dirpath, path);
    sprintf(fpath,"%s%s", direktori, path);
    res = chmod(fpath, mode);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s", dirpath, path);
    res = lchown(fpath, uid, gid);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
    char fpath[1000];
    if(strcmp(path,"/") == 0)
    {
        path=dirpath;
        sprintf(fpath,"%s",path);
    }
    else sprintf(fpath, "%s%s",dirpath,path);
    int res = 0;
    DIR *dp;
    struct dirent *de;
    dp = opendir(fpath);
    if(dp==NULL)
    {
        return -errno;
    }
    while((de = readdir(dp))!=NULL)
    {
        res = filler(h, de->d_name, de->d_type);
        if(res!=0) break;
    }
    closedir(dp);
    return res;
}

static int xmp_mkdir(const char *path,mode_t mode)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = mkdir (fpath,mode);
    if(res == -1)
        return -errno;
    return 0;
}

static int xmp_symlink(const char *from, const char *to)
{
    int res;
 char ffrom[1000];
 char fto[1000];
 sprintf(ffrom,"%s%s",dirpath,from);
 sprintf(fto,"%s%s",dirpath,to);
    res = symlink(ffrom, fto);
    if(res == -1)
        return -errno;

    return 0;
}

/*static int xmp_link(const char *from, const char *to)
{
    int res;
    char ffrom[1000];
    char fto[1000];
    sprintf(ffrom,"%s%s",dirpath,from);
    sprintf(fto,"%s%s",dirpath,to);
    res = link(ffrom, fto);
    if(res == -1)
        return -errno;

    return 0;
}*/

static int xmp_unlink(const char *path)
{
    int res;
 char fpath[1000];
 sprintf(fpath,"%s%s", dirpath, path);
    res = unlink(fpath);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_truncate(const char *path, off_t size)
{
    int res;
     char fpath[1000];
 sprintf(fpath,"%s%s", dirpath, path);
    res = truncate(fpath, size);
    if(res == -1)
        return -errno;

    return 0;
}

/*static int xmp_utime(const char *path, struct utimbuf *buf)
{
    int res;
     char fpath[1000];
 sprintf(fpath,"%s%s", dirpath, path);
    res = utime(fpath, buf);
    if(res == -1)
        return -errno;

    return 0;
}*/

static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
    int res;
 char fpath[1000];
 sprintf(fpath,"%s%s", dirpath, path);
    res = mknod(fpath, mode, rdev);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_open(const char *path, int flags)
{
    int res;
    int counter=0;
    char fpath[1000];
    char path2[1000];
    char path3[1000];
    sprintf(fpath,"%s%s", dirpath, path);
    sprintf(path2,"%s%s","/home/yaukings/Downloads/file",path);
    int i;
    for(i=0;i<strlen(path);i++)
    {
        if(path[i]=='/')
        {
            counter++;
        }
    }

    if(counter==2)
    {
        sprintf(path3,"%s%s","chmod 444 ",path2);
        system(path3);
        char temp[]="zenity --info --text=\"";
                strcat(temp,"File Tidak Bisa Dibuka");
                strcat(temp,"\"");
                system(temp);
    res = open(fpath, flags);
    if(res == -1)
        return -errno;
    }

    close(res);
    return 0;
}

static int xmp_read(const char *path, char *buf, size_t size, off_t offset)
{
    int fd;
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s", dirpath, path);
    fd = open(fpath, O_RDONLY);
    if(fd == -1)
        return -errno;

    res = pread(fd, buf, size, offset);
    if(res == -1)
        res = -errno;

    close(fd);
    return res;
}

static int xmp_write(const char *path, const char *buf, size_t size,
                     off_t offset)
{
    int fd;
    int res;
 char fpath[1000];
 sprintf(fpath,"%s%s", dirpath, path);
    fd = open(fpath, O_WRONLY);
    if(fd == -1)
        return -errno;

    res = pwrite(fd, buf, size, offset);
    if(res == -1)
        res = -errno;

    close(fd);
    return res;
}

static int xmp_rename(const char *from, const char *to)
{
    int res;
    char ffrom[1000];
    char fto[1000];
    system("mkdir /home/yaukings/Downloads/file/simpanan");
    //system("chmod 777 /home/yaukings/Downloads/file/simpanan");

    char direktori[] = "/home/yaukings/Downloads/file/simpanan";

    //system("zenity --info --text=\"INI ADALAH INFO: \" --title=\"INFO\"");
    sprintf(ffrom,"%s%s",dirpath,from);
    sprintf(fto,"%s%s",direktori,to);
    res = rename(ffrom, fto);

    if(res == -1)
    return -errno;

    return 0;
}
//system("zenity --error --text=\"An error occurred!\" --title=\"Warning!\"");

static struct fuse_operations xmp_oper =
{
    .getattr = xmp_getattr,
    //.readlink = xmp_readlink,
    .getdir = xmp_getdir,
    .mknod = xmp_mknod,
    .mkdir = xmp_mkdir,
    .symlink = xmp_symlink,
    .unlink = xmp_unlink,
    //.rmdir = xmp_rmdir,
    .rename = xmp_rename,
    //.link = xmp_link,
    .chmod = xmp_chmod,
    .chown = xmp_chown,
    .truncate = xmp_truncate,
    //.utime = xmp_utime,
    .open = xmp_open,
    .read = xmp_read,
    .write = xmp_write,
    //.release = xmp_release,
    //.fsync = xmp_fsync,
    //.readdir = hello_readdir
};

int main(int argc, char *argv[])
{
    return fuse_main(argc, argv, &xmp_oper);
}

Setelah dibuat file c nya maka jalankan lewat terminal  dengan menggunakan:

gcc -Wall [nama file].c `pkg-config fuse --cflags --libs` -o [nama file]

Sebelum dijalankan buat dulu folder yang akan dijadikan lokasi atau wadah mountingnya bisa lewat buat create folder biasa atau bisa juga menggunakan mkdir  atau jika sudah ada folder kosong sebelumnya gunakan saja folder kosong tersebut. Untuk eksekusinya dapat langsung dengan ./[nama file] [nama folder kosong]. Setelah itu langsung saja dicoba untuk mengedit file didalam lokasi mounting tadi yang biasanya langsung muncul drive baru, dan lihat hasilnya.

Ada cukup banyak istilah/Fungsi baru disini. tapi mungin untuk awalnya "apa yang kita mounting ke folder baru tadi?". jika kita lihat file c di atas maka ada di variabel dirpath.

Pengertian dari Beberapa Istilah/Fungsi:
getattr : agar memungkinkan FUSE dapat mengakses data-data yang unik seperti angka, karakter, array
getdir : untuk mendapatkan alamat asli dari folder yang di FUSE kan
mknod : untuk membuat file baru (berkas). jika fungsi ini hilang, maka di dalam FUSE tersebut kita tidak bisa membuat file baru
mkdir : untuk membuat folder baru
rmdir : untuk menghapus foler
truncate : mengganti alokasi memory untuk setiap file
open : membuka suatu file (seperti jika klik 2 kali menggunakan mouse\enter-button)
read :  untuk menerima dari pengguna yang nantinya disimpan di memory komputer.
write : untuk menuliskan data hasil READ yang telah disimpan di memory, ke file yang sedang dibuka.
rename : mengganti nama dari file/berkas (rename juga digunakan untuk menyimpan / menyimpan hasil perubahan isi berkas)
chmod : mengganti permisi file
chown : mengganti pemilik berkas
symlink : symbolic link

Sekian penjelasan tentang fuse dan salah satu contoh penerapannya, semoga dapat membantu :)


Sunday, November 8, 2015

Terminal X Terminal : 1 Client 1 Server 1 Memori

Sekarang banyak wadah online untuk berbagi informasi dokumen seperti google doc, spreadsheet dan sebagainya. Jika kita perhatikan jika satu pengguna mengubah data didalamnya maka akan berubah juga untuk pengguna lain. Bagaimana hal tersebut bisa terjadi? nah kali ini saya akan menjelaskan metode yang mirip dengan konsep yang telah kita bicarakan diatas, namun untuk linux dan bagaimana hal ini dilakukan antar terminal tanpa wadah berupa txt dan sebagainya.

Cara agar kita dapat melakukan hal tersebut adalah dengan menggunakan IPC, nah apa itu IPC? IPC adalah singkatan dari Interprocess Communication yang mana IPC ini adalah cara atau mekanisme pertukaran data antarasatu proses dengan proses lainnya, baik itu proses yang berada di dalam komputer yang sama, atau komputer jarak jauh yang terhubung melalui jaringan. Pada umumnya jenis IPC ada 4 yaitu:

PIPE

Pipe merupakan komunikasi sequensial antar proses yang saling terelasi, namun
pipe memiliki kelemahan yaitu hanya bisa digunakan untuk komunikasi antar prosesyang saling berhubungan, dan komunikasinya yang dilakukan adalah secarasequensial.

Message Queue

Sistem berkirim pesan adalah proses komunikasi antar bagian sistem untuk membagi variabel yang dibutuhkan. Proses ini menyediakan dua operasi yaitu mengirim pesan dan menerima pesan.

Shared Memory

Sistem Berbagi Memori merupakan salah satu cara komunikasi antar proses dengan cara mengalokasikan suatu alamat memori untuk dipakai berkomunikasi antar proses. Alamat dan besar alokasi memori yang digunakan biasanya ditentukan oleh pembuat program. Pada metode ini, sistem akan mengatur proses mana yang akanmemakai memori pada waktu tertentu sehingga pekerjaan dapat dilakukan secara efektif.

Socket

Bentuk dari komunikasi yaitu UDP dan TCP menggunakan abstraksi socket yang menyediakan endpoint untuk komunikasi antar proses. Socket bisa dijalankan di berbagai platform(BSD UNIIX, UNIX, Linux, Windows, & Machintos OS).

Nah bagaimana benda-benda diatas tersebut berjalan?  di sini saya akan menjelaskan tentang salah satu dari 4 yang telah di sebutkan diatas yaitu sharesd memory. Sebgai contoh persoalannya "Bagaimana penjual barang dan pembeli barang dapat menggunakan wadah yang sama untuk bertukar informasi". Untuk awalnya kita dapat membuat file .c yang akan kita gunakan. Kita akan menggunakan 2 file yang berbeda namun hampir sama. Untuk penjual kita anggap saja server dan untuk pembeli kita anggap client.

*saya menggunakan linux mint dan tidak ada chdir jadi directory tidak berpindah, tetap di /home/user/

Untuk file server.c kita isi dengan:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>



int Cek_Request()
{

    fprintf(stdout, "Masukkan barang lagi? (Y/N) ");
    char masuk;
    masuk=getchar();
        if(masuk=='n' || masuk=='N') return 0;
        else if(masuk=='y' || masuk=='Y') return 1;
        else
        {
            fprintf(stdout, "Kode yang dimasukkan salah\n\n");
            Cek_Request();
        }
}

int main()
{
    int *RAM,*harddisk,*motherboard,*PSU,*VGA,*Processor;
    int shmid,jumlah,menu;
    char pilihan[100],text[100];
    //prepare();
    key_t key;

    key = 1;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    RAM = shmat(shmid, NULL, 0);
    key = 2;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    harddisk = shmat(shmid, NULL, 0);
    key = 3;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    motherboard = shmat(shmid, NULL, 0);
    key = 4;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    PSU = shmat(shmid, NULL, 0);
    key = 5;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    VGA = shmat(shmid, NULL, 0);
    key = 6;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    Processor = shmat(shmid, NULL, 0);

    //inisialisasi
    *RAM=0,*harddisk=0,*motherboard=0,*PSU=0,*VGA=0,*Processor=0;

    while(1)
    {

      fprintf(stdout, "MENU\n---------------\n1. lihat_stok\n2. tambah_stok\n3. keluar\nKode : ");
      scanf("%s", text);

        if(strcmp(text,"1")==0)
            fprintf(stdout, "STOK BARANG\nRAM\t\t= %d\nharddisk\t= %d\nmotherboard\t= %d\nPSU\t\t= %d\nVGA\t\t= %d\nProcessor\t= %d\n\n", *RAM, *harddisk, *motherboard, *PSU, *VGA, *Processor);
        else if(strcmp(text,"2")==0)
        {
            while(1)
            {
                fprintf(stdout, "RAM\nharddisk\nmotherboard\nPSU\nVGA\nprocessor\n-------------\nKode barang\t: ");
                scanf("%s", pilihan);
                if(strcmp("RAM",pilihan)!=0 && strcmp("harddisk",pilihan)!=0 && strcmp("motherboard",pilihan)!=0 && strcmp("PSU",pilihan)!=0 && strcmp("VGA",pilihan)!=0 && strcmp("processor",pilihan)!=0)
                {
                    fprintf(stdout, "Kode yang dimasukkan salah\n\n");
                    continue;
                }

                //fprintf(stdout, "Banyak\t\t: ");
                scanf("%d", &jumlah);

                if(strcmp("RAM",pilihan)==0)
                {
                    (*RAM)=(*RAM)+jumlah;
                }
                else if(strcmp("harddisk",pilihan)==0) (*harddisk)+=jumlah;
                else if(strcmp("motherboard",pilihan)==0) (*motherboard)+=jumlah;
                else if(strcmp("PSU",pilihan)==0) (*PSU)+=jumlah;
                else if(strcmp("VGA",pilihan)==0) (*VGA)+=jumlah;
                else if(strcmp("processor",pilihan)==0) (*Processor)+=jumlah;


                getchar();
                if(!Cek_Request())
                {
                    fprintf(stdout, "\n");
                    break;
                }
            }
        }
        else if(strcmp(text,"3")==0) return 0;
        else
        {
            fprintf(stdout, "Kode yang dimasukkan salah\n\n");
            continue;
        }
    }
    return 0;
}

Dan untuk client.c kita isi dengan:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int taken()
{
    fprintf(stdout, "Ambil barang lagi? (Y/N) ");
    char ambil;
    ambil=getchar();
        if(ambil=='n' || ambil=='N') return 0;
        else if(ambil=='y' || ambil=='Y') return 1;
        else
        {
            fprintf(stdout, "Kode yang dimasukkan salah\n\n");
            taken();
        }
}

int main()
{
    int *RAM,*harddisk,*motherboard,*PSU,*VGA,*processor,shmid,jumlah,menu;
    char pilihan[100];
    key_t key;

    key = 1;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    RAM = shmat(shmid, NULL, 0);
    key = 2;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    harddisk = shmat(shmid, NULL, 0);
    key = 3;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    motherboard = shmat(shmid, NULL, 0);
    key = 4;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    PSU = shmat(shmid, NULL, 0);
    key = 5;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    VGA = shmat(shmid, NULL, 0);
    key = 6;
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666);
    processor = shmat(shmid, NULL, 0);

    while(1)
    {
        fprintf(stdout, "1. lihat stok\n2. beli barang\n3. Exit\nKode : ");
        scanf("%d", &menu);
        if(menu==1)
            fprintf(stdout, "STOK BARANG\nRAM\t\t= %d\nharddisk\t= %d\nmotherboard\t= %d\nPSU\t\t= %d\nVGA\t\t= %d\nProcessor\t= %d\n\n", *RAM, *harddisk, *motherboard, *PSU, *VGA, *processor);
        else if(menu==2)
        {
            while(1)
            {
                fprintf(stdout, "RAM\nharddisk\nmotherboard\nPSU\nVGA\nprocessor\n-------------\nKode barang\t: ");
                scanf("%s", pilihan);
                if(strcmp("RAM",pilihan)!=0 && strcmp("harddisk",pilihan)!=0 && strcmp("motherboard",pilihan)!=0 && strcmp("PSU",pilihan)!=0 && strcmp("VGA",pilihan)!=0 && strcmp("processor",pilihan)!=0)
                {
                    fprintf(stdout, "Kode yang dimasukkan salah\n\n");
                    continue;
                }

                fprintf(stdout, "Banyak\t\t: ");
                scanf("%d", &jumlah);

                if(strcmp("RAM",pilihan)==0)
                {
                    (*RAM)-=jumlah;
                    if(*RAM<0)
                    {
                        fprintf(stdout, "Pembelian gagal, Stok barang tidak cukup\n\n");
                        (*RAM)+=jumlah;
                    }
                }
                else if(strcmp("harddisk",pilihan)==0)
                {
                    (*harddisk)-=jumlah;
                    if(*harddisk<0)
                    {
                        fprintf(stdout, "Pembelian gagal, Stok barang tidak cukup\n\n");
                        (*harddisk)+=jumlah;
                    }
                }
                else if(strcmp("motherboard",pilihan)==0)
                {
                    (*motherboard)-=jumlah;
                    if(*motherboard<0)
                    {
                        fprintf(stdout, "Pembelian gagal, Stok barang tidak cukup\n\n");
                        (*motherboard)+=jumlah;
                    }
                }
                else if(strcmp("PSU",pilihan)==0)
                {
                    (*PSU)-=jumlah;
                    if(*PSU<0)
                    {
                        fprintf(stdout, "Pembelian gagal, Stok barang tidak cukup\n\n");
                        (*PSU)+=jumlah;
                    }
                }
                else if(strcmp("VGA",pilihan)==0)
                {
                    (*VGA)-=jumlah;
                    if(*VGA<0)
                    {
                        fprintf(stdout, "Pembelian gagal, Stok barang tidak cukup\n\n");
                        (*VGA)+=jumlah;
                    }
                }
                else if(strcmp("processor",pilihan)==0)
                {
                    (*processor)-=jumlah;
                    if(*processor<0)
                    {
                        fprintf(stdout, "Pembelian gagal, Stok barang tidak cukup\n\n");
                        (*processor)+=jumlah;
                    }
                }
                getchar();
                if(!taken())
                {
                    fprintf(stdout, "\n");
                    break;
                }
            }
        }
        else if(menu==3) return 0;
        else
        {
            fprintf(stdout, "Kode yang dimasukkan salah\n\n");
            continue;
        }
        sleep(1);
    }
    return 0;
}

*untuk key1,2,3,4,5,6 dapat dijadikan menjadi satu buah saja dengan menggunakan struct

Untuk menjalankan file .c nya sama dengan sebelumnya yaitu dengan membuka terminal. Untuk kasus kali ini yang dibuka 2 terminal dan ketik :

gcc -o nama_file nama_file_c      
dan jalankan dengan ./nama_file

Jika ./client dan ./server dijalankan maka jika di salah satu diupdate informasinya maka yang lain juga akan terupdate.

Untuk penejelasan dari shared memory nya:

shmget()  
System call untuk membuat suatu segmen shared memory 

shmat()
System call untuk mendaftarkan segment shared memory ke dalam data space dari suatu proses

shmdt()
System call untuk melepaskan shared memory segment dari data space dari proses. 
 
Nah, sekian penjelasan tentang ipc khususnya shared memory, semoga bermanfaat............