/*
    losetup: Setup a loopback (/dev/loopX) device. Made for
        early userspace under klibc.
    Copyright (C) 2006, Aaron Griffin <aaronmgriffin@gmail.com>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/loop.h>

int main(int argc, const char ** argv)
{
    struct loop_info64 li64;
    struct loop_info   li32;
    int dfd = -1, ffd = -1;

    if (argc != 3)
    {
        fprintf(stderr,"Usage: losetup <loop device> <filename>\n");
        return 1;
    }

    if ((dfd = open(argv[1], O_RDONLY)) < 0)
    {
        perror(argv[1]);
        return 1;
    }

    if ((ffd = open(argv[2], O_RDONLY)) < 0)
    {
        perror(argv[2]);
        close(dfd);
        return 1;
    }

    memset(&li64, 0, sizeof(li64));
    strcpy((char*)li64.lo_file_name, argv[2]);
    li64.lo_offset = 0;
    li64.lo_encrypt_key_size = 0;

    if (ioctl(dfd, LOOP_SET_FD, (void*)ffd) < 0)
    {
        perror("LOOP_SET_FD");
        close(dfd);
        return 1;
    }
    close (ffd);

    if (ioctl(dfd, LOOP_SET_STATUS64, (void*)&li64) < 0)
    {
        memset(&li32, 0, sizeof(li32));
        strcpy(li32.lo_name, argv[2]);

        if (ioctl(dfd, LOOP_SET_STATUS, (void*)&li32) < 0) {
            perror("ioctl: LOOP_SET_STATUS");
            ioctl(dfd, LOOP_CLR_FD, 0);
            close(dfd);
            return 1;
        }
    }

    close(dfd);
    return 0;
}
