Saturday, 28 November 2015

FUSE, FUSEEETTT DAH

FUSE adalah Filesystem in Userspace, dengan FUSE kita dapat membuat filesystem kita sendiri dengan aturan yang kita inginkan.

Untuk menggunakan fuse, kita harus menginstallnya terlebih dahulu, kalian bisa mendownload file untuk fuse di

1. http://fuse.sourceforge.net/
2. Extract ke folder yang kalian inginkan.
3. Masuk ke folder hasil extraction melalui terminal
4. Ganti hak ases super user
5. ketik ./configure
6. ketik make
7. ketik make install

setelah itu fuse dapat digunakan.

Jadi bagaimana kita memodifikasi dalam fuse?

Didalam fuse terdapat beberapa fungsi dimana fungsi tersebut berguna untuk mengatur hal hal yang berhubungan dengan filesystem buatan kita sendiri ini.

fungsi yang bisa dimodifikasi yang tersedia di fuse ada dibawah ini:
struct fuse_operations {
    int (*getattr) (const char *, struct stat *); 
    int (*readlink) (const char *, char *, size_t);
    int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
    int (*mknod) (const char *, mode_t, dev_t);
    int (*mkdir) (const char *, mode_t);
    int (*unlink) (const char *);
    int (*rmdir) (const char *);
    int (*symlink) (const char *, const char *);
    int (*rename) (const char *, const char *);
    int (*link) (const char *, const char *);
    int (*chmod) (const char *, mode_t);
    int (*chown) (const char *, uid_t, gid_t);
    int (*truncate) (const char *, off_t);
    int (*utime) (const char *, struct utimbuf *);
    int (*open) (const char *, struct fuse_file_info *);
    int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
    int (*write) (const char *, const char *, size_t, off_t,struct fuse_file_info *);
    int (*statfs) (const char *, struct statfs *);
    int (*flush) (const char *, struct fuse_file_info *);
    int (*release) (const char *, struct fuse_file_info *);
    int (*fsync) (const char *, int, struct fuse_file_info *);
    int (*setxattr) (const char *, const char *, const char *, size_t, int);
    int (*getxattr) (const char *, const char *, char *, size_t);
    int (*listxattr) (const char *, char *, size_t);
    int (*removexattr) (const char *, const char *);
};
Berikut ini adalah contoh penggunaan fuse untuk filesystem yang apabila suatu file dicopy maka file asli akan di lock (tidak dapat dibuka atau di copy lagi)


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


static const char *dirpath = "/home/ariobimo/Documents";
char simpen[1000];

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_readlink(const char *path, char *buf, size_t size)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = readlink(fpath, buf, size - 1);
    if(res == -1)
        return -errno;

    buf[res] = '\0';
    return 0;
}


static int xmp_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
    DIR *dp;
    struct dirent *de;
    int res = 0;
    char fpath[1000];
  
 if(strcmp(path,"/") == 0)
    {
        path=dirpath;
        sprintf(fpath,"%s",path);
    }
    else sprintf(fpath, "%s%s",dirpath,path);

    dp = opendir(path);
    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_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_rmdir(const char *path)
{
    int res;
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = rmdir(fpath);
    if(res == -1)
        return -errno;

    return 0;
}

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

    return 0;
}

static int xmp_rename(const char *from, const char *to)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,from);
    char fpath2[1000];
    sprintf(fpath2,"%s%s",dirpath,to);
    res = rename(fpath, fpath2);
    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_link(const char *from, const char *to)
{
    int res;
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,from);
char fpath2[1000];
    sprintf(fpath2,"%s%s",dirpath,to);
    res = link(fpath, fpath2);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_chmod(const char *path, mode_t mode)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,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_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_open(const char *path, int flags)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    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);
    strcpy(simpen,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];
    char something[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    fd = open(fpath, O_WRONLY);
    if(fd == -1)
        return -errno;
   sprintf(something,"%s%s",dirpath,simpen);
   chmod(something,0000);
    res = pwrite(fd, buf, size, offset);
    if(res == -1)
        res = -errno;
 
    close(fd);

    return res;
}

/*static int xmp_statfs(struct fuse_statfs *fst)
{
    struct statfs st;
    int rv = statfs("/",&st);
    if(!rv) {
        fst->block_size  = st.f_bsize;
        fst->blocks      = st.f_blocks;
        fst->blocks_free = st.f_bavail;
        fst->files       = st.f_files;
        fst->files_free  = st.f_ffree;
        fst->namelen     = st.f_namelen;
    }
    return rv;
}*/

static int xmp_release(const char *path, int flags)
{
    /* Just a stub.  This method is optional and can safely be left
       unimplemented */
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    (void) fpath;
    (void) flags;
    return 0;
}

static int xmp_fsync(const char *path, int isdatasync)
{
    /* Just a stub.  This method is optional and can safely be left
       unimplemented */
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    (void) fpath;
    (void) isdatasync;
    return 0;
}

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,
    //.statfs    = xmp_statfs,
    .release    = xmp_release,
    .fsync    = xmp_fsync
   
};

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

Bisa dilihat dikodingan diatas yang dimodify adalah fungsi write dan fungsi read, dimana saat kita mengcopy sebuah file, pastiya file yang akan dicopy akan di read terlebih dahulu, sehingga saat di read, kita menyimpan file pathnya (dengan menggunakan strcpy).

Kemudian saat di write, kita akan melakukan chmod untuk melakukan lock pada file source tersebut.

Setelah koding diatas selesai, simpan dalam bentuk .c . kemudian kalian bisa mengcompile .c tersebut dengan cara:
gcc -Wall [nama file].c `pkg-config fuse --cflags --libs` -o [nama file]
 setelah berhasil di compile kita dapat run file kita dengan cara:
./file /tmp/fuse

Diatas menunjukan bahwa kita akan melakukan mount pada folder /tmp/fuse .
Anda harus memastikan bahwa folder yang anda gunakan untuk mount adalah folder kosong.

Silakan mencoba hehe.

Saturday, 7 November 2015

Shared Memory

Jadi waktu itu gw ditanyain gitu, shared memory apa sih ? Cara kerjanya gimana sih? itu kenapa simple sih daripada piping?

well, basically dengan shared memory , kita dapat mengalokasikan suatu memory yang bisa digunakan antar process, jadi bisa membuat suatu Interprocess Communication. Walaupun ada cara IPC lain, tapi menurut saya shared memory lebih simple untuk dicoding. Karena, berbeda dengan misalnya piping dimana anda harus menentukan kapan setiap process harus read dan write, dengan shared memory, kamu bisa mengupdate variable yang di share secara otomatis.

CARA MEMBUAT SHARED MEMORY:

The Gist of it
1. Menentukan key
2. Membuat Shared Memory ID
3. Mendapatkan address dari shared memory

WAT? THAT SIMPLE? yeap yeap, bisa lah ya.

1.  Menentukan key
Jadi, key itu digunakan buat mendapatkan shared memory id. Kenapa kita perlu id? Karena bisa saja dalam satu process ada lebih dari 1 shared memory, jadi untuk membedakan shared memory satu dan yang lain. Key yang digunakan bisa bebas, intinya , key yang di set di satu process harus sama dengan key yang di process lain.
    key_t key;
   key = 1111;
Bisa dilihat diatas, saya melakukan set key menjadi 1111, key disini bebas bisa 1234 bisa 00000 atau yang lain asalkan key di process lain sama (tentunya pada shared memory yang sama).
Pembuatan key bisa juga menggunakan ftok()/
 key_t ftok(const char *path, int id);

2.Membuat Shared Memory ID
Dengan key yang telah dibuat kita bisa mendapatkan shared memory id dengan fungsi shmget.
shmid =  shmget(key,sizeof(struct barang), IPC_CREAT | 0666);
code diatas menunjukan bahwa saya akan menyimpan shared memory id ke shmid. Disitu ada IPC_CREAT |0666 dimana dia akan membuat interprocess communication yang memiliki premission untuk melakukan read dan juga write.

3.Mendapatkan address dari shared memory
Setelah mendapatkan ID, kita bisa langsung mendapatkan address dari shared memory tersebut.
 shmat(shmid,NULL,0);
Setelah menyimpan address kedalam suatu variable, kita dapat langsung mengubah variable  dan akan secara otomatis berpengaruh ke process lain yang memiliki akses ke shared memory.

Contoh:

Disini saya akan memberikan contoh dari penggunaan shared memory :
Contohnya yaitu IPC antara process pemilik toko dan process client. pemilik memiliki menu untuk menambahkan stok dan lihat stok. sedangkan pembeli atau client memiliki menu untuk membeli barang dan lihat stok.

Server:

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

struct barang{
    char name[6][20];
    int jumlah[6];
};

int main (int argc , char **argv)
{
    struct barang *barangs;
    int banyak;
    char stockname[20];
    int shmid, pilihan;
    key_t key;
    int i;
    key = 1111;
    shmid =  shmget(key,sizeof(struct barang), IPC_CREAT | 0666);
    barangs =(struct barang *) shmat(shmid,NULL,0);
    for(i=0;i<6;i++)
    {
        if(i==0) strcpy(barangs->name[i],"RAM");
        else if(i==1) strcpy(barangs->name[i], "harddisk");
        else if(i==2) strcpy(barangs->name[i], "motherboard");
        else if(i==3) strcpy(barangs->name[i], "PSU");
        else if(i==4) strcpy(barangs->name[i], "VGA");
        else if(i==5) strcpy(barangs->name[i], "processor");
        barangs->jumlah[i] = 0;
    }
    int flag;
    while(1)
    {
        printf("######SELAMAT DATANG DI TOKO OINK######\n");
        printf("##                     ##\n");
        printf("##1.Lihat stok         2.Tambah Stok##\n");
        printf("##                     ##\n");
        printf("#######################################\n");
        scanf("%d",&pilihan);
       
        if( pilihan == 1)
        {
            system("clear");
            printf("NAMA BARANG\tJUMLAHBARANG\n");
            for(i=0;i<6;i++)
            {
                if (i==0 || i== 3 || i== 4)
                {
                    printf("%s\t\t%d\n", barangs->name[i], barangs->jumlah[i]);
                }
                else printf("%s\t%d\n", barangs->name[i], barangs->jumlah[i]);
            }
        }
        else if( pilihan == 2)
        {
            flag =0;
            printf("Masukkan nama barang yang ingin ditambah stoknya > ");
            scanf("%s",stockname);
            printf("Masukkan jumlah penambahan > ");
            scanf("%d", &banyak);

            system("clear");
            for(i=0;i<6;i++)
            {
                if (strcmp(stockname, barangs->name[i]) == 0)
                {
                    flag =1;
                    barangs->jumlah[i] += banyak;
                    printf("Anda telah menambah stok barang %s sebanyak %d\n", barangs->name[i], banyak);
                    sleep(3);
                    system("clear");

                }
               
            }
            if (flag == 0) system("zenity --warning --text='INPUT INVALID'");
        }
        else {
            system("clear");
            system("zenity --warning --text='INPUT INVALID'");
            }
    }
}
Client , hmm , jadi gimana ya kalo kita di process client ada menu beli barang dan lihat stok?
Kurang lebih sama, bedanya, anda tak perlu melakukan inisialisasi, karena inisialisasi sudah dilakukan di server dan anda sudah bisa mengakses di process pembeli, karena sudah terupdate. bedanya lagi terletak dimana saat pemilik menambahkan stok, sudah pasti stok bertambah, tetapi jika client membeli stok, stok berkurang, perlu juga dibuat error handling  seperti apabila stok yang ingin dibeli oleh client tidak cukup dengan jumlah yang ada di gudang.

Gimana? gampang kan? bisa dehh, silakan mencoba ya...