syslinux/libinstaller/syslxcom.c
<<
>>
Prefs
   1/* ----------------------------------------------------------------------- *
   2 *
   3 *   Copyright 2010 Intel Corp. - All Rights Reserved
   4 *
   5 *   This program is free software; you can redistribute it and/or modify
   6 *   it under the terms of the GNU General Public License as published by
   7 *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
   8 *   Boston MA 02111-1307, USA; either version 2 of the License, or
   9 *   (at your option) any later version; incorporated herein by reference.
  10 *
  11 * ----------------------------------------------------------------------- */
  12
  13/*
  14 * syslxcom.c
  15 *
  16 * common functions for extlinux & syslinux installer
  17 *
  18 */
  19#define  _GNU_SOURCE
  20
  21#include <stdio.h>
  22#include <stdlib.h>
  23#include <stddef.h>
  24#include <stdint.h>
  25#include <string.h>
  26#include <getopt.h>
  27#include <unistd.h>
  28#include <errno.h>
  29#include <sys/stat.h>
  30#include <sys/types.h>
  31#include <sys/mount.h>
  32#include <sys/vfs.h>
  33
  34#include "linuxioctl.h"
  35#include "syslxcom.h"
  36#include "syslxfs.h"
  37
  38const char *program;
  39
  40int fs_type;
  41
  42#ifdef DEBUG
  43# define dprintf printf
  44#else
  45# define dprintf(...) ((void)0)
  46#endif
  47
  48#define SECTOR_SHIFT    9
  49
  50static void die(const char *msg)
  51{
  52    fputs(msg, stderr);
  53    exit(1);
  54}
  55
  56/*
  57 * read/write wrapper functions
  58 */
  59ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
  60{
  61    char *bufp = (char *)buf;
  62    ssize_t rv;
  63    ssize_t done = 0;
  64
  65    while (count) {
  66        rv = pread(fd, bufp, count, offset);
  67        if (rv == 0) {
  68            die("short read");
  69        } else if (rv == -1) {
  70            if (errno == EINTR) {
  71                continue;
  72            } else {
  73                die(strerror(errno));
  74            }
  75        } else {
  76            bufp += rv;
  77            offset += rv;
  78            done += rv;
  79            count -= rv;
  80        }
  81    }
  82
  83    return done;
  84}
  85
  86ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
  87{
  88    const char *bufp = (const char *)buf;
  89    ssize_t rv;
  90    ssize_t done = 0;
  91
  92    while (count) {
  93        rv = pwrite(fd, bufp, count, offset);
  94        if (rv == 0) {
  95            die("short write");
  96        } else if (rv == -1) {
  97            if (errno == EINTR) {
  98                continue;
  99            } else {
 100                die(strerror(errno));
 101            }
 102        } else {
 103            bufp += rv;
 104            offset += rv;
 105            done += rv;
 106            count -= rv;
 107        }
 108    }
 109
 110    return done;
 111}
 112
 113/*
 114 * Set and clear file attributes
 115 */
 116void clear_attributes(int fd)
 117{
 118    struct stat st;
 119
 120    if (!fstat(fd, &st)) {
 121        switch (fs_type) {
 122        case EXT2:
 123        {
 124            int flags;
 125
 126            if (!ioctl(fd, FS_IOC_GETFLAGS, &flags)) {
 127                flags &= ~FS_IMMUTABLE_FL;
 128                ioctl(fd, FS_IOC_SETFLAGS, &flags);
 129            }
 130            break;
 131        }
 132        case VFAT:
 133        {
 134            uint32_t attr = 0x00; /* Clear all attributes */
 135            ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
 136            break;
 137        }
 138    case NTFS:
 139        break;
 140        default:
 141            break;
 142        }
 143        fchmod(fd, st.st_mode | S_IWUSR);
 144    }
 145}
 146
 147void set_attributes(int fd)
 148{
 149    struct stat st;
 150
 151    if (!fstat(fd, &st)) {
 152        fchmod(fd, st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH));
 153        switch (fs_type) {
 154        case EXT2:
 155        {
 156            int flags;
 157
 158            if (st.st_uid == 0 && !ioctl(fd, FS_IOC_GETFLAGS, &flags)) {
 159                flags |= FS_IMMUTABLE_FL;
 160                ioctl(fd, FS_IOC_SETFLAGS, &flags);
 161            }
 162            break;
 163        }
 164        case VFAT:
 165        {
 166            uint32_t attr = 0x07; /* Hidden+System+Readonly */
 167            ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
 168            break;
 169        }
 170    case NTFS:
 171        break;
 172        default:
 173            break;
 174        }
 175    }
 176}
 177
 178/* New FIEMAP based mapping */
 179static int sectmap_fie(int fd, sector_t *sectors, int nsectors)
 180{
 181    struct fiemap *fm;
 182    struct fiemap_extent *fe;
 183    unsigned int i, nsec;
 184    sector_t sec, *secp, *esec;
 185    struct stat st;
 186    uint64_t maplen;
 187
 188    if (fstat(fd, &st))
 189        return -1;
 190
 191    fm = alloca(sizeof(struct fiemap)
 192                + nsectors * sizeof(struct fiemap_extent));
 193
 194    memset(fm, 0, sizeof *fm);
 195
 196    maplen = (uint64_t)nsectors << SECTOR_SHIFT;
 197    if (maplen > (uint64_t)st.st_size)
 198        maplen = st.st_size;
 199
 200    fm->fm_start        = 0;
 201    fm->fm_length       = maplen;
 202    fm->fm_flags        = FIEMAP_FLAG_SYNC;
 203    fm->fm_extent_count = nsectors;
 204
 205    if (ioctl(fd, FS_IOC_FIEMAP, fm))
 206        return -1;
 207
 208    memset(sectors, 0, nsectors * sizeof *sectors);
 209    esec = sectors + nsectors;
 210
 211    fe = fm->fm_extents;
 212
 213    if (fm->fm_mapped_extents < 1 ||
 214        !(fe[fm->fm_mapped_extents-1].fe_flags & FIEMAP_EXTENT_LAST))
 215        return -1;
 216
 217    for (i = 0; i < fm->fm_mapped_extents; i++) {
 218        if (fe->fe_flags & FIEMAP_EXTENT_LAST) {
 219            /* If this is the *final* extent, pad the length */
 220            fe->fe_length = (fe->fe_length + SECTOR_SIZE - 1)
 221                & ~(SECTOR_SIZE - 1);
 222        }
 223
 224        if ((fe->fe_logical | fe->fe_physical| fe->fe_length) &
 225            (SECTOR_SIZE - 1))
 226            return -1;
 227
 228        if (fe->fe_flags & (FIEMAP_EXTENT_UNKNOWN|
 229                            FIEMAP_EXTENT_DELALLOC|
 230                            FIEMAP_EXTENT_ENCODED|
 231                            FIEMAP_EXTENT_DATA_ENCRYPTED|
 232                            FIEMAP_EXTENT_UNWRITTEN))
 233            return -1;
 234
 235        secp = sectors + (fe->fe_logical >> SECTOR_SHIFT);
 236        sec  = fe->fe_physical >> SECTOR_SHIFT;
 237        nsec = fe->fe_length >> SECTOR_SHIFT;
 238
 239        while (nsec--) {
 240            if (secp >= esec)
 241                break;
 242            *secp++ = sec++;
 243        }
 244
 245        fe++;
 246    }
 247
 248    return 0;
 249}
 250
 251/* Legacy FIBMAP based mapping */
 252static int sectmap_fib(int fd, sector_t *sectors, int nsectors)
 253{
 254    unsigned int blk, nblk;
 255    unsigned int i;
 256    unsigned int blksize;
 257    sector_t sec;
 258
 259    /* Get block size */
 260    if (ioctl(fd, FIGETBSZ, &blksize))
 261        return -1;
 262
 263    /* Number of sectors per block */
 264    blksize >>= SECTOR_SHIFT;
 265
 266    nblk = 0;
 267    while (nsectors) {
 268        blk = nblk++;
 269        if (ioctl(fd, FIBMAP, &blk))
 270            return -1;
 271
 272        sec = (sector_t)blk * blksize;
 273        for (i = 0; i < blksize; i++) {
 274            *sectors++ = sec++;
 275            if (! --nsectors)
 276                break;
 277        }
 278    }
 279
 280    return 0;
 281}
 282
 283/*
 284 * Produce file map
 285 */
 286int sectmap(int fd, sector_t *sectors, int nsectors)
 287{
 288    if (!sectmap_fie(fd, sectors, nsectors))
 289        return 0;
 290
 291    return sectmap_fib(fd, sectors, nsectors);
 292}
 293
 294/*
 295 * SYSLINUX installs the string 'SYSLINUX' at offset 3 in the boot
 296 * sector; this is consistent with FAT filesystems.  Earlier versions
 297 * would install the string "EXTLINUX" instead, handle both.
 298 */
 299int syslinux_already_installed(int dev_fd)
 300{
 301    char buffer[8];
 302
 303    xpread(dev_fd, buffer, 8, 3);
 304    return !memcmp(buffer, "SYSLINUX", 8) || !memcmp(buffer, "EXTLINUX", 8);
 305}
 306