int diskutil_loop (const char * path, const long long offset, char * lodev, int lodev_size) { int found = 0; int done = 0; int ret = OK; char * output; // we retry because we cannot atomically obtain a free loopback // device on all distros (some versions of 'losetup' allow a file // argument with '-f' options, but some do not) for (int i=0; i<LOOP_RETRIES; i++) { sem_p (loop_sem); output = pruntf (TRUE, "%s %s -f", helpers_path[ROOTWRAP], helpers_path[LOSETUP]); sem_v (loop_sem); if (output==NULL) // there was a problem break; if (strstr (output, "/dev/loop")) { strncpy (lodev, output, lodev_size); char * ptr = strrchr (lodev, '\n'); if (ptr) { *ptr = '\0'; found = 1; } } free (output); if (found) { boolean do_log = ((i+1)==LOOP_RETRIES); // log error on last try only logprintfl (EUCADEBUG, "{%u} attaching file %s\n", (unsigned int)pthread_self(), path); logprintfl (EUCADEBUG, "{%u} to %s at offset %lld\n", (unsigned int)pthread_self(), lodev, offset); sem_p (loop_sem); output = pruntf (do_log, "%s %s -o %lld %s %s", helpers_path[ROOTWRAP], helpers_path[LOSETUP], offset, lodev, path); sem_v (loop_sem); if (output==NULL) { logprintfl (EUCADEBUG, "{%u} cannot attach to loop device %s (will retry)\n", (unsigned int)pthread_self(), lodev); } else { free (output); done = 1; break; } } sleep (1); found = 0; } if (!done) { logprintfl (EUCAINFO, "{%u} error: cannot find free loop device or attach to one\n", (unsigned int)pthread_self()); ret = ERROR; } return ret; }
// TODO: since 'losetup' truncates paths in its output, this // check is not perfect. It may approve loopback devices // that are actually pointing at a different path. int diskutil_loop_check (const char * path, const char * lodev) { int ret = 0; char * output = pruntf (TRUE, "%s %s %s", helpers_path[ROOTWRAP], helpers_path[LOSETUP], lodev); if (output==NULL) return 1; // output is expected to look like: // /dev/loop4: [0801]:5509589 (/var/lib/eucalyptus/volumes/v*) char * oparen = strchr (output, '('); char * cparen = strchr (output, ')'); if (oparen==NULL || cparen==NULL) { // no parenthesis => unexpected `losetup` output ret = 1; } else if ((cparen - oparen) < 3) { // strange paren arrangement => unexpected ret = 1; } else { // extract just the path, possibly truncated, from inside the parens oparen++; cparen--; if (* cparen == '*') // handle truncated paths, identified with an asterisk cparen--; * cparen = '\0'; // truncate ')' or '*)' if (strstr (path, oparen) == NULL) { // see if path is in the blobstore ret = 1; } } free (output); return ret; }
int diskutil_unloop (const char * lodev) { int ret = OK; char * output; int retried = 0; logprintfl (EUCADEBUG, "{%u} detaching from loop device %s\n", (unsigned int)pthread_self(), lodev); // we retry because we have seen spurious errors from 'losetup -d' on Xen: // ioctl: LOOP_CLR_FD: Device or resource bus for (int i=0; i<LOOP_RETRIES; i++) { boolean do_log = ((i+1)==LOOP_RETRIES); // log error on last try only sem_p (loop_sem); output = pruntf (do_log, "%s %s -d %s", helpers_path[ROOTWRAP], helpers_path[LOSETUP], lodev); sem_v (loop_sem); if (!output) { ret = ERROR; } else { ret = OK; free (output); break; } logprintfl (EUCADEBUG, "{%u} cannot detach loop device %s (will retry)\n", (unsigned int)pthread_self(), lodev); retried++; sleep (1); } if (ret == ERROR) { logprintfl (EUCAWARN, "{%u} error: cannot detach loop device\n", (unsigned int)pthread_self()); } else if (retried) { logprintfl (EUCAINFO, "{%u} succeeded to detach %s after %d retries\n", (unsigned int)pthread_self(), lodev, retried); } return ret; }
//! //! //! //! @param[in] path //! @param[in] part //! @param[out] first //! @param[out] last //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if any issue occured. //! \li EUCA_INVALID_ERROR: if any paramter does not meet the preconditions. //! //! @pre The path, first and last parameters must not be NULL. //! //! @post On success, the partition information has been extracted and contained in first and last. //! int diskutil_sectors(const char *path, const int part, long long *first, long long *last) { int p = 0; int ret = EUCA_ERROR; char *ss = NULL; char *end = NULL; char *comma = NULL; char *output = NULL; char *section = NULL; boolean found = FALSE; if (path && first && last) { *first = 0L; *last = 0L; if ((output = pruntf(TRUE, "%s %s", helpers_path[FILECMD], path)) == NULL) { LOGERROR("failed to extract partition information for '%s'\n", path); } else { // parse the output, such as: // NAME: x86 boot sector; // partition 1: ID=0x83, starthead 1, startsector 63, 32769 sectors; // partition 2: ID=0x83, starthead 2, startsector 32832, 32769 sectors; // partition 3: ID=0x82, starthead 2, startsector 65601, 81 sectors found = FALSE; section = strtok(output, ";"); // split by semicolon for (p = 0; section != NULL; p++) { section = strtok(NULL, ";"); if (section && (p == part)) { found = TRUE; break; } } if (found) { if ((ss = strstr(section, "startsector")) != NULL) { ss += strlen("startsector "); if ((comma = strstr(ss, ", ")) != NULL) { *comma = '\0'; comma += strlen(", "); if ((end = strstr(comma, " sectors")) != NULL) { *end = '\0'; *first = atoll(ss); *last = *first + atoll(comma) - 1L; } } } } EUCA_FREE(output); } if (*last > 0) ret = EUCA_OK; return (ret); } LOGERROR("failed to extract partition information for '%s'\n", SP(path)); return (EUCA_INVALID_ERROR); }
int diskutil_mkdir (const char * path) { char * output; output = pruntf (TRUE, "%s %s -p %s", helpers_path[ROOTWRAP], helpers_path[MKDIR], path); if (!output) { return ERROR; } free (output); return OK; }
int diskutil_cp (const char * from, const char * to) { char * output; output = pruntf (TRUE, "%s %s %s %s", helpers_path[ROOTWRAP], helpers_path[CP], from, to); if (!output) { return ERROR; } free (output); return OK; }
int diskutil_sectors (const char * path, const int part, long long * first, long long * last) { int ret = ERROR; char * output; * first = 0L; * last = 0L; output = pruntf (TRUE, "%s %s", helpers_path[FILECMD], path); if (!output) { logprintfl (EUCAINFO, "ERROR: failed to extract partition information for '%s'\n", path); } else { // parse the output, such as: // NAME: x86 boot sector; // partition 1: ID=0x83, starthead 1, startsector 63, 32769 sectors; // partition 2: ID=0x83, starthead 2, startsector 32832, 32769 sectors; // partition 3: ID=0x82, starthead 2, startsector 65601, 81 sectors boolean found = FALSE; char * section = strtok (output, ";"); // split by semicolon for (int p = 0; section != NULL; p++) { section = strtok (NULL, ";"); if (section && p == part) { found = TRUE; break; } } if (found) { char * ss = strstr (section, "startsector"); if (ss) { ss += strlen ("startsector "); char * comma = strstr (ss, ", "); if (comma) { * comma = '\0'; comma += strlen (", "); char * end = strstr (comma, " sectors"); if (end) { * end = '\0'; * first = atoll (ss); * last = * first + atoll (comma) - 1L; } } } } free (output); } if ( * last > 0 ) ret = OK; return ret; }
int diskutil_ch (const char * path, const char * user, const char * group, const int perms) { int ret = OK; char * output; logprintfl (EUCAINFO, "{%u} ch(own|mod) '%s' %s.%s %o\n", (unsigned int)pthread_self(), path, user?user:"******", group?group:"*", perms); if (user) { output = pruntf (TRUE, "%s %s %s %s", helpers_path[ROOTWRAP], helpers_path[CHOWN], user, path); if (!output) { return ERROR; } free (output); } if (group) { output = pruntf (TRUE, "%s %s :%s %s", helpers_path[ROOTWRAP], helpers_path[CHOWN], group, path); if (!output) { return ERROR; } free (output); } if (perms>0) { output = pruntf (TRUE, "%s %s 0%o %s", helpers_path[ROOTWRAP], helpers_path[CHMOD], perms, path); if (!output) { return ERROR; } free (output); } return OK; }
int diskutil_mbr (const char * path, const char * type) { int ret = OK; char * output; output = pruntf (TRUE, "LD_PRELOAD='' %s %s --script %s mklabel %s", helpers_path[ROOTWRAP], helpers_path[PARTED], path, type); if (!output) { logprintfl (EUCAINFO, "ERROR: cannot create an MBR\n"); ret = ERROR; } else { free (output); } return ret; }
int diskutil_part (const char * path, char * part_type, const char * fs_type, const long long first_sector, const long long last_sector) { int ret = OK; char * output; output = pruntf (TRUE, "LD_PRELOAD='' %s %s --script %s mkpart %s %s %llds %llds", helpers_path[ROOTWRAP], helpers_path[PARTED], path, part_type, (fs_type)?(fs_type):(""), first_sector, last_sector); if (!output) { logprintfl (EUCAINFO, "ERROR: cannot add a partition\n"); ret = ERROR; } else { free (output); } return ret; }
int diskutil_mkswap (const char * lodev, const long long size_bytes) { int ret = OK; char * output; output = pruntf (TRUE, "%s %s %s %lld", helpers_path[ROOTWRAP], helpers_path[MKSWAP], lodev, size_bytes/1024); if (!output) { logprintfl (EUCAINFO, "{%u} error: cannot format partition on '%s' as swap\n", (unsigned int)pthread_self(), lodev); ret = ERROR; } else { free (output); } return ret; }
//! //! //! //! @param[in] from //! @param[in] to //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if we fail to copy the item. //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions //! //! @pre Both from and to parameters must not be NULL. //! //! @post On success the file has been copied. //! int diskutil_cp(const char *from, const char *to) { char *output = NULL; if (from && to) { if ((output = pruntf(TRUE, "%s %s %s %s", helpers_path[ROOTWRAP], helpers_path[CP], from, to)) == NULL) { return (EUCA_ERROR); } EUCA_FREE(output); return (EUCA_OK); } return (EUCA_INVALID_ERROR); }
//! //! //! //! @param[in] path //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if we fail to create the directory //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions. //! //! @pre The path parameter must not be NULL. //! //! @post On success, the directory is created. //! int diskutil_mkdir(const char *path) { char *output = NULL; if (path) { if ((output = pruntf(TRUE, "%s %s -p %s", helpers_path[ROOTWRAP], helpers_path[MKDIR], path)) == NULL) { return (EUCA_ERROR); } EUCA_FREE(output); return (EUCA_OK); } return (EUCA_INVALID_ERROR); }
int diskutil_mkfs (const char * lodev, const long long size_bytes) { int ret = OK; char * output; int block_size = 4096; output = pruntf (TRUE, "%s %s -b %d %s %lld", helpers_path[ROOTWRAP], helpers_path[MKEXT3], block_size, lodev, size_bytes/block_size); if (!output) { logprintfl (EUCAINFO, "{%u} error: cannot format partition on '%s' as ext3\n", (unsigned int)pthread_self(), lodev); ret = ERROR; } else { free (output); } return ret; }
int diskutil_tune (const char * lodev) { int ret = OK; char * output; sem_p (loop_sem); output = pruntf (TRUE, "%s %s %s -c 0 -i 0", helpers_path[ROOTWRAP], helpers_path[TUNE2FS], lodev); sem_v (loop_sem); if (!output) { logprintfl (EUCAINFO, "{%u} error: cannot tune file system on '%s'\n", (unsigned int)pthread_self(), lodev); ret = ERROR; } else { free (output); } return ret; }
int diskutil_dd (const char * in, const char * out, const int bs, const long long count) { int ret = OK; char * output; logprintfl (EUCAINFO, "{%u} copying data from '%s'\n", (unsigned int)pthread_self(), in); logprintfl (EUCAINFO, "{%u} to '%s' (blocks=%lld)\n", (unsigned int)pthread_self(), out, count); output = pruntf (TRUE, "%s %s if=%s of=%s bs=%d count=%lld", helpers_path[ROOTWRAP], helpers_path[DD], in, out, bs, count); if (!output) { logprintfl (EUCAERROR, "{%u} error: cannot copy '%s'\n", (unsigned int)pthread_self(), in); logprintfl (EUCAERROR, "{%u} to '%s'\n", (unsigned int)pthread_self(), out); } else { free (output); } return ret; }
int diskutil_umount (const char * dev) { int ret = OK; char * output; sem_p (loop_sem); output = pruntf (TRUE, "%s %s umount %s", helpers_path[ROOTWRAP], helpers_path[MOUNTWRAP], dev); sem_v (loop_sem); if (!output) { logprintfl (EUCAINFO, "{%u} error: cannot unmount device '%s'\n", (unsigned int)pthread_self(), dev); ret = ERROR; } else { free (output); } return ret; }
int diskutil_umount (const char * dev) { int ret = OK; char * output; sem_p (loop_sem); output = pruntf (TRUE, "%s %s umount %s", helpers_path[ROOTWRAP], helpers_path[MOUNTWRAP], dev); sem_v (loop_sem); if (!output) { logprintfl (EUCAERROR, "cannot unmount device '%s'\n", dev); ret = ERROR; } else { free (output); } return ret; }
//! //! //! //! @param[in] path //! @param[in] lodev //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if any error occured //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions //! //! @pre Both path and lodev parameters must not be NULL. //! //! @todo since 'losetup' truncates paths in its output, this check is not perfect. It //! may approve loopback devices that are actually pointing at a different path. //! int diskutil_loop_check(const char *path, const char *lodev) { int ret = EUCA_OK; char *output = NULL; char *oparen = NULL; char *cparen = NULL; if (path && lodev) { output = pruntf(TRUE, "%s %s %s", helpers_path[ROOTWRAP], helpers_path[LOSETUP], lodev); if (output == NULL) return (EUCA_ERROR); // output is expected to look like: /dev/loop4: [0801]:5509589 (/var/lib/eucalyptus/volumes/v*) oparen = strchr(output, '('); cparen = strchr(output, ')'); if ((oparen == NULL) || (cparen == NULL)) { // no parenthesis => unexpected `losetup` output ret = EUCA_ERROR; } else if ((cparen - oparen) < 3) { // strange paren arrangement => unexpected ret = EUCA_ERROR; } else { // extract just the path, possibly truncated, from inside the parens oparen++; cparen--; if (*cparen == '*') { // handle truncated paths, identified with an asterisk cparen--; } // truncate ')' or '*)' *cparen = '\0'; // see if path is in the blobstore if (strstr(path, oparen) == NULL) { ret = EUCA_ERROR; } } EUCA_FREE(output); return (ret); } LOGWARN("bad params: path=%s, lodev=%s\n", SP(path), SP(lodev)); return (EUCA_INVALID_ERROR); }
//! //! Creates a Master Boot Record (MBR) of the given type at the given path //! //! @param[in] path path where we need to create the MBR //! @param[in] type type of MBR to create //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if we fail to create the MBR //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions //! //! @pre Both path and type parameters must not be NULL. //! //! @post On success, the MBR is created //! int diskutil_mbr(const char *path, const char *type) { char *output = NULL; if (path && type) { output = pruntf(TRUE, "LD_PRELOAD='' %s %s --script %s mklabel %s", helpers_path[ROOTWRAP], helpers_path[PARTED], path, type); if (!output) { LOGERROR("cannot create an MBR\n"); return (EUCA_ERROR); } EUCA_FREE(output); return (EUCA_OK); } LOGWARN("bad params: path=%s, type=%s\n", SP(path), SP(type)); return (EUCA_INVALID_ERROR); }
//! //! Format a partition as a swap. //! //! @param[in] lodev //! @param[in] size_bytes //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if any error occured. //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions. //! //! @pre The lodev parameters must not be NULL. //! //! @post On success, the partition is formatted as swap. //! int diskutil_mkswap(const char *lodev, const long long size_bytes) { char *output = NULL; if (lodev) { output = pruntf(TRUE, "%s %s %s %lld", helpers_path[ROOTWRAP], helpers_path[MKSWAP], lodev, size_bytes / 1024); if (!output) { LOGERROR("cannot format partition on '%s' as swap\n", lodev); return (EUCA_ERROR); } EUCA_FREE(output); return (EUCA_OK); } LOGWARN("cannot format partition as swap. lodev=%s\n", SP(lodev)); return (EUCA_INVALID_ERROR); }
//! //! Creates a new partition of the given part_type at the given path. //! //! @param[in] path path where to create the partition //! @param[in] part_type the type of partition //! @param[in] fs_type the type of file system (if NULL, "" is assumed) //! @param[in] first_sector the first sector of the partition //! @param[in] last_sector the last sector of this partition //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if we fail to create the partition //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions //! //! @pre Both path and part_type parameters must not be NULL. //! //! @post On success, the partition is created //! int diskutil_part(const char *path, char *part_type, const char *fs_type, const long long first_sector, const long long last_sector) { char *output = NULL; if (path && part_type) { output = pruntf(TRUE, "LD_PRELOAD='' %s %s --script %s mkpart %s %s %llds %llds", helpers_path[ROOTWRAP], helpers_path[PARTED], path, part_type, ((fs_type != NULL) ? (fs_type) : ("")), first_sector, last_sector); if (!output) { LOGERROR("cannot add a partition\n"); return (EUCA_ERROR); } EUCA_FREE(output); return (EUCA_OK); } LOGWARN("bad params: path=%s, part_type=%s\n", SP(path), SP(part_type)); return (EUCA_INVALID_ERROR); }
int diskutil_dd2 (const char * in, const char * out, const int bs, const long long count, const long long seek, const long long skip) { int ret = OK; char * output; logprintfl (EUCAINFO, "{%u} copying data from '%s'\n", (unsigned int)pthread_self(), in); logprintfl (EUCAINFO, "{%u} to '%s'\n", (unsigned int)pthread_self(), out); logprintfl (EUCAINFO, "{%u} of %lld blocks (bs=%d), seeking %lld, skipping %lld\n", (unsigned int)pthread_self(), count, bs, seek, skip); output = pruntf (TRUE, "%s %s if=%s of=%s bs=%d count=%lld seek=%lld skip=%lld conv=notrunc,fsync", helpers_path[ROOTWRAP], helpers_path[DD], in, out, bs, count, seek, skip); if (!output) { logprintfl (EUCAERROR, "{%u} error: cannot copy '%s'\n", (unsigned int)pthread_self(), in); logprintfl (EUCAERROR, "{%u} to '%s'\n", (unsigned int)pthread_self(), out); ret = ERROR; } else { free (output); } return ret; }
//! //! //! //! @param[in] lodev //! @param[in] size_bytes //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if any error occured. //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions. //! //! @pre The lodev parameters must not be NULL. //! //! @post On success, the loop device is attached. //! int diskutil_mkfs(const char *lodev, const long long size_bytes) { int block_size = 4096; char *output = NULL; if (lodev) { output = pruntf(TRUE, "%s %s -b %d %s %lld", helpers_path[ROOTWRAP], helpers_path[MKEXT3], block_size, lodev, size_bytes / block_size); if (!output) { LOGERROR("cannot format partition on '%s' as ext3\n", lodev); return (EUCA_ERROR); } EUCA_FREE(output); return (EUCA_OK); } LOGWARN("cannot format partition as ext3. lodev=%s\n", SP(lodev)); return (EUCA_INVALID_ERROR); }
int diskutil_ddzero (const char * path, const long long sectors, boolean zero_fill) { int ret = OK; char * output; long long count = 1; long long seek = sectors - 1; if (zero_fill) { count = sectors; seek = 0; } output = pruntf (TRUE, "%s %s if=/dev/zero of=%s bs=512 seek=%lld count=%lld", helpers_path[ROOTWRAP], helpers_path[DD], path, seek, count); if (!output) { logprintfl (EUCAINFO, "ERROR: cannot create disk file %s\n", path); ret = ERROR; } else { free (output); } return ret; }
//! //! //! //! @param[in] lodev //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if any error occured. //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions. //! //! @pre The lodev parameters must not be NULL. //! //! @post On success, the loop device is attached. //! int diskutil_tune(const char *lodev) { char *output = NULL; if (lodev) { sem_p(loop_sem); { output = pruntf(TRUE, "%s %s %s -c 0 -i 0", helpers_path[ROOTWRAP], helpers_path[TUNE2FS], lodev); } sem_v(loop_sem); if (!output) { LOGERROR("cannot tune file system on '%s'\n", lodev); return (EUCA_ERROR); } EUCA_FREE(output); return (EUCA_OK); } LOGWARN("cannot tune file system. lodev=%s\n", SP(lodev)); return (EUCA_INVALID_ERROR); }
int diskutil_grub2_mbr (const char * path, const int part, const char * mnt_pt) { char cmd [1024]; int rc = 1; if (grub_version!=1 && grub_version!=2) { logprintfl (EUCAERROR, "{%u} internal error: invocation of diskutil_grub2_mbr without grub found\n", (unsigned int)pthread_self()); return ERROR; } else if (mnt_pt==NULL && grub_version!=1) { logprintfl (EUCAERROR, "{%u} internal error: invocation of diskutil_grub2_mbr with grub 1 params\n", (unsigned int)pthread_self()); return ERROR; } logprintfl (EUCAINFO, "{%u} installing grub in MBR\n", (unsigned int)pthread_self()); if (grub_version==1) { char tmp_file [EUCA_MAX_PATH] = "/tmp/euca-temp-XXXXXX"; int tfd = safe_mkstemp (tmp_file); if (tfd < 0) { logprintfl (EUCAINFO, "{%u} error: mkstemp() failed: %s\n", (unsigned int)pthread_self(), strerror (errno)); return ERROR; } // create a soft link of the first partition's device mapper entry in the // form that grub is looking for (not DISKp1 but just DISK1) boolean created_partition_softlink = FALSE; char part_path [EUCA_MAX_PATH]; snprintf (part_path, sizeof (EUCA_MAX_PATH), "%s1", path); if (check_path (part_path) != 0) { char *output = pruntf (TRUE, "%s /bin/ln -s %sp1 %s", helpers_path[ROOTWRAP], path, part_path); if (!output) { logprintfl (EUCAINFO, "{%u} warning: failed to create partition device soft-link (%s)\n", (unsigned int)pthread_self(), part_path); } else { created_partition_softlink = TRUE; free (output); } } // we now invoke grub through euca_rootwrap because it may need to operate on // devices that are owned by root (e.g. /dev/mapper/euca-dsk-7E4E131B-fca1d769p1) snprintf(cmd, sizeof (cmd), "%s %s --batch >%s 2>&1", helpers_path[ROOTWRAP], helpers_path[GRUB], tmp_file); logprintfl (EUCADEBUG, "{%u} running %s\n", (unsigned int)pthread_self(), cmd); errno = 0; FILE * fp = popen (cmd, "w"); if (fp!=NULL) { char s [EUCA_MAX_PATH]; #define _PR fprintf (fp, "%s", s); // logprintfl (EUCADEBUG, "\t%s", s) snprintf (s, sizeof (s), "device (hd0) %s\n", path); _PR; snprintf (s, sizeof (s), "root (hd0,%d)\n", part); _PR; snprintf (s, sizeof (s), "setup (hd0)\n"); _PR; snprintf (s, sizeof (s), "quit\n"); _PR; rc = pclose (fp); // base success on exit code of grub } if (rc) { logprintfl (EUCAERROR, "{%u} error: failed to run grub 1 on disk '%s': %s\n", (unsigned int)pthread_self(), path, strerror (errno)); } else { int read_bytes; char buf [1024]; bzero (buf, sizeof (buf)); boolean saw_done = FALSE; do { // read in a line int bytes_read = 0; while ((sizeof (buf) - 2 - bytes_read)>0 // there is space in buffer for \n and \0 && ((read_bytes = read (tfd, buf + bytes_read, 1)) > 0)) if (buf [bytes_read++] == '\n') break; if (read_bytes < 0) // possibly truncated output, ensure there is newline buf [bytes_read++] = '\n'; buf [bytes_read] = '\0'; logprintfl (EUCADEBUG, "\t%s", buf); // log grub 1 prompts and our inputs if (strstr (buf, "Done.")) // this indicates that grub 1 succeeded (the message has been there since 2000) saw_done = TRUE; } while (read_bytes>0); close (tfd); if (saw_done==FALSE) { logprintfl (EUCAERROR, "{%u} error: failed to run grub 1 on disk '%s'\n", (unsigned int)pthread_self(), path); rc = 1; } else { rc = 0; } } // try to remove the partition device soft link that may have been created above if (created_partition_softlink) { char * output = pruntf (TRUE, "%s /bin/rm %s", helpers_path[ROOTWRAP], part_path); if(!output) { logprintfl (EUCAINFO, "{%u} warning: failed to remove partition device soft-link\n", (unsigned int)pthread_self()); } else { free(output); } } } else if (grub_version==2) { // create device.map file char device_map_path [EUCA_MAX_PATH]; char device_map_buf [512]; snprintf (device_map_path, sizeof (device_map_path), "%s/boot/grub/device.map", mnt_pt); snprintf (device_map_buf, sizeof (device_map_buf), "(hd0) %s\n", path); if (diskutil_write2file (device_map_path, device_map_buf)!=OK) { logprintfl (EUCAWARN, "{%u} error: failed to create device.map file\n", (unsigned int)pthread_self()); } else { logprintfl (EUCAINFO, "{%u} wrote to '%s':\n", (unsigned int)pthread_self(), device_map_path); logprintfl (EUCAINFO, "{%u} %s", (unsigned int)pthread_self(), device_map_buf); } char * output = pruntf (TRUE, "%s %s --modules='part_msdos ext2' --root-directory=%s '(hd0)'", helpers_path[ROOTWRAP], helpers_path[GRUB_INSTALL], mnt_pt); if (!output) { logprintfl (EUCAINFO, "{%u} error: failed to install grub 2 on disk '%s' mounted on '%s'\n", (unsigned int)pthread_self(), path, mnt_pt); } else { free (output); rc = 0; } } if (rc==0) return OK; else return ERROR; }
int diskutil_grub_files (const char * mnt_pt, const int part, const char * kernel, const char * ramdisk) { int ret = OK; char * output = NULL; char * kfile = "euca-vmlinuz"; char * rfile = "euca-initrd"; logprintfl (EUCAINFO, "{%u} installing kernel and ramdisk\n", (unsigned int)pthread_self()); output = pruntf (TRUE, "%s %s -p %s/boot/grub/", helpers_path[ROOTWRAP], helpers_path[MKDIR], mnt_pt); if (!output) { logprintfl (EUCAINFO, "{%u} error: failed to create grub directory\n", (unsigned int)pthread_self()); return ERROR; } free (output); if (grub_version==1) { output = pruntf (TRUE, "%s %s %s/*stage* %s/boot/grub", helpers_path[ROOTWRAP], helpers_path[CP], stage_files_dir, mnt_pt); if (!output) { logprintfl (EUCAINFO, "{%u} error: failed to copy stage files into grub directory\n", (unsigned int)pthread_self()); return ERROR; } free (output); } output = pruntf (TRUE, "%s %s %s %s/boot/%s", helpers_path[ROOTWRAP], helpers_path[CP], kernel, mnt_pt, kfile); if (!output) { logprintfl (EUCAINFO, "{%u} error: failed to copy the kernel to boot directory\n", (unsigned int)pthread_self()); ret = ERROR; goto cleanup; } free (output); if (ramdisk) { output = pruntf (TRUE, "%s %s %s %s/boot/%s", helpers_path[ROOTWRAP], helpers_path[CP], ramdisk, mnt_pt, rfile); if (!output) { logprintfl (EUCAINFO, "{%u} error: failed to copy the ramdisk to boot directory\n", (unsigned int)pthread_self()); ret = ERROR; goto cleanup; } free (output); } char buf [1024]; char grub_conf_path [EUCA_MAX_PATH]; if (grub_version==1) { char menu_lst_path [EUCA_MAX_PATH]; snprintf (menu_lst_path, sizeof (menu_lst_path), "%s/boot/grub/menu.lst", mnt_pt); snprintf (grub_conf_path, sizeof (grub_conf_path), "%s/boot/grub/grub.conf", mnt_pt); snprintf (buf, sizeof (buf), "default=0\n" "timeout=2\n\n" "title TheOS\n" "root (hd0,%d)\n" "kernel /boot/%s root=/dev/sda1 ro\n", part, kfile); // grub 1 expects 0 for first partition if (ramdisk) { char buf2 [1024]; snprintf (buf2, sizeof (buf2), "initrd /boot/%s\n", rfile); strncat (buf, buf2, sizeof (buf) - 1); } if (diskutil_write2file (menu_lst_path, buf)!=OK) { ret = ERROR; goto cleanup; } } else if (grub_version==2) { snprintf (grub_conf_path, sizeof (grub_conf_path), "%s/boot/grub/grub.cfg", mnt_pt); char initrd [1024] = ""; if (ramdisk) { snprintf (initrd, sizeof (initrd), " initrd /boot/%s\n", rfile); } snprintf (buf, sizeof (buf), "set default=0\n" "set timeout=2\n" "insmod part_msdos\n" "insmod ext2\n" "set root='(hd0,%d)'\n" "menuentry 'TheOS' --class os {\n" " linux /boot/%s root=/dev/sda1 ro\n" "%s" "}\n", part+1, kfile, initrd); // grub 2 expects 1 for first partition } if (diskutil_write2file (grub_conf_path, buf)!=OK) { ret = ERROR; goto cleanup; } cleanup: return ret; }
int diskutil_get_parts(const char *path, struct partition_table_entry entries[], int num_entries) { assert(path); assert(entries); assert(num_entries > 0); bzero(entries, sizeof(struct partition_table_entry) * num_entries); // output of 'parted DEV unit s print' looks roughly like: // // Model: (file) // Disk /dev/loop8: 3072063s // Sector size (logical/physical): 512B/512B // Partition Table: msdos // // // Number Start End Size Type File system Flags // 2 63s 204862s 204800s primary ext3 // 1 204863s 3072062s 2867200s primary ext3 char *output = pruntf(TRUE, "LD_PRELOAD='' %s %s --script %s unit s print", helpers_path[ROOTWRAP], helpers_path[PARTED], path); if (!output) { LOGERROR("cannot obtain partition information on device %s\n", path); return -1; } char *s = strstr(output, "Number"); if (s == NULL) { LOGERROR("cannot parse 'parted print' output for device %s (no 'Number')\n", path); free(output); return -1; } s = strstr(output, "Flags\n"); if (s == NULL) { LOGERROR("cannot parse 'parted print' output for device %s (no 'Flags')\n", path); free(output); return -1; } s += strlen("Flags\n"); // onto the next line // parse the partitions lines thatfollow the headers returned by 'parted print' char *pline = strtok(s, "\n"); // split by semicolon for (int p = 0; pline != NULL; p++) { int index; long long start; long long end; long long size; char *type; char *filesystem; // expect syntax like: 1 204863s 3072062s 2867200s primary ext3 if (sscanf(pline, "%d %llds %llds %llds %ms %ms", &index, &start, &end, &size, &type, &filesystem) == 6) { int n = index - 1; if (n >= num_entries) { // do not have room for this entry break; } entries[n].start_sector = start; entries[n].end_sector = end; euca_strncpy(entries[n].type, type, sizeof(entries[n].type)); euca_strncpy(entries[n].filesystem, filesystem, sizeof(entries[n].filesystem)); free(type); free(filesystem); } pline = strtok(NULL, "\n"); } free(output); // run through the entries[], ensure they are contiguous, starting with [0] int count = 0; for (int n = 0; n < num_entries; n++) { if (entries[n].end_sector > 0) { count++; } else { break; } } return count; }
//! //! //! //! @param[in] path //! @param[in] offset //! @param[in] lodev name of the loop device //! @param[in] lodev_size //! //! @return EUCA_OK on success or the following error codes: //! \li EUCA_ERROR: if any error occured. //! \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions. //! //! @pre Both path and lodev parameters must not be NULL. //! //! @post On success, the loop device is attached. //! int diskutil_loop(const char *path, const long long offset, char *lodev, int lodev_size) { int i = 0; int ret = EUCA_OK; char *ptr = NULL; char *output = NULL; boolean done = FALSE; boolean found = FALSE; boolean do_log = FALSE; if (path && lodev) { // we retry because we cannot atomically obtain a free loopback device on all distros (some // versions of 'losetup' allow a file argument with '-f' options, but some do not) for (i = 0, done = FALSE, found = FALSE; i < LOOP_RETRIES; i++) { sem_p(loop_sem); { output = pruntf(TRUE, "%s %s -f", helpers_path[ROOTWRAP], helpers_path[LOSETUP]); } sem_v(loop_sem); if (output == NULL) { // there was a problem break; } if (strstr(output, "/dev/loop")) { strncpy(lodev, output, lodev_size); if ((ptr = strrchr(lodev, '\n')) != NULL) { *ptr = '\0'; found = TRUE; } } EUCA_FREE(output); if (found) { do_log = ((i + 1) == LOOP_RETRIES); // log error on last try only LOGDEBUG("attaching file %s\n", path); LOGDEBUG(" to %s at offset %lld\n", lodev, offset); sem_p(loop_sem); { char str_offset[64]; snprintf(str_offset, sizeof(str_offset), "%lld", offset); output = execlp_output(do_log, helpers_path[ROOTWRAP], helpers_path[LOSETUP], "-o", str_offset, lodev, path, NULL); } sem_v(loop_sem); if (output == NULL) { LOGDEBUG("cannot attach to loop device %s (will retry)\n", lodev); } else { EUCA_FREE(output); done = TRUE; break; } } sleep(1); found = FALSE; } if (!done) { LOGERROR("cannot find free loop device or attach to one\n"); ret = EUCA_ERROR; } return (ret); } LOGWARN("cannot attach to loop device. path=%s, lodev=%s\n", SP(path), SP(lodev)); return (EUCA_INVALID_ERROR); }