/* * FTP - send single character * wait for echo & handle timeout */ static void send(char c) { char cc; int retry = 0; cc = c; xpwrite(FD, &cc, 1); if (number(value(CDELAY)) > 0 && c != '\r') nap(number(value(CDELAY))); if (!boolean(value(ECHOCHECK))) { if (number(value(LDELAY)) > 0 && c == '\r') nap(number(value(LDELAY))); return; } tryagain: timedout = 0; alarm(number(value(ETIMEOUT))); read(FD, &cc, 1); alarm(0); if (timedout) { printf("\r\ntimeout error (%s)\r\n", ctrl(c)); if (retry++ > 3) return; xpwrite(FD, &null, 1); /* poke it */ goto tryagain; } }
static int update_epoch_from_v0_to_v1(uint32_t epoch) { char path[PATH_MAX]; struct sd_node_v0 nodes_v0[SD_MAX_NODES]; struct sd_node_v1 nodes_v1[SD_MAX_NODES]; size_t nr_nodes; time_t *t; int len, fd, ret; snprintf(path, sizeof(path), "%s%08u", epoch_path, epoch); fd = open(path, O_RDWR | O_DSYNC); if (fd < 0) { if (errno == ENOENT) return 0; sd_eprintf("failed to open epoch %"PRIu32" log", epoch); return -1; } ret = xread(fd, nodes_v0, sizeof(nodes_v0)); if (ret < 0) { sd_eprintf("failed to read epoch %"PRIu32" log", epoch); close(fd); return ret; } nr_nodes = ret / sizeof(nodes_v0[0]); for (int i = 0; i < nr_nodes; i++) { memcpy(&nodes_v1[i].nid, &nodes_v0[i].nid, sizeof(struct node_id_v1)); nodes_v1[i].nr_vnodes = nodes_v0[i].nr_vnodes; nodes_v1[i].zone = nodes_v0[i].zone; nodes_v1[i].space = 0; } len = sizeof(nodes_v1[0]) * nr_nodes; ret = xpwrite(fd, nodes_v1, len, 0); if (ret != len) { sd_eprintf("failed to write epoch %"PRIu32" log", epoch); close(fd); return -1; } t = (time_t *)&nodes_v0[nr_nodes]; ret = xpwrite(fd, t, sizeof(*t), len); if (ret != sizeof(*t)) { sd_eprintf("failed to write time to epoch %" PRIu32" log", epoch); close(fd); return -1; } close(fd); return 0; }
/* * ****TIPIN TIPIN**** */ void tipin(void) { int i; char gch, bol = 1; atexit(killchild); /* * Kinda klugey here... * check for scripting being turned on from the .tiprc file, * but be careful about just using setscript(), as we may * send a SIGEMT before tipout has a chance to set up catching * it; so wait a second, then setscript() */ if (boolean(value(SCRIPT))) { sleep(1); setscript(); } while (1) { i = getchar(); if (i == EOF) break; gch = i&0177; if ((gch == character(value(ESCAPE))) && bol) { if (!(gch = escape())) continue; } else if (!cumode && gch == character(value(RAISECHAR))) { boolean(value(RAISE)) = !boolean(value(RAISE)); continue; } else if (gch == '\r') { bol = 1; xpwrite(FD, &gch, 1); if (boolean(value(HALFDUPLEX))) printf("\r\n"); continue; } else if (!cumode && gch == character(value(FORCE))) { i = getchar(); if (i == EOF) break; gch = i & 0177; } bol = any(gch, value(EOL)); if (boolean(value(RAISE)) && islower(gch)) gch = toupper(gch); xpwrite(FD, &gch, 1); if (boolean(value(HALFDUPLEX))) printf("%c", gch); } }
int default_write(uint64_t oid, struct siocb *iocb) { int flags = get_open_flags(oid, false), fd, ret = SD_RES_SUCCESS; char path[PATH_MAX]; ssize_t size; if (iocb->epoch < sys_epoch()) { dprintf("%"PRIu32" sys %"PRIu32"\n", iocb->epoch, sys_epoch()); return SD_RES_OLD_NODE_VER; } get_obj_path(oid, path); if (iocb->flags & SD_FLAG_CMD_CACHE && is_disk_cache_enabled()) flags &= ~O_DSYNC; fd = open(path, flags, def_fmode); if (fd < 0) return err_to_sderr(oid, errno); size = xpwrite(fd, iocb->buf, iocb->length, iocb->offset); if (size != iocb->length) { eprintf("failed to write object %"PRIx64", path=%s, offset=%" PRId64", size=%"PRId32", result=%zd, %m\n", oid, path, iocb->offset, iocb->length, size); ret = err_to_sderr(oid, errno); goto out; } out: close(fd); return ret; }
static int jrnl_apply_to_target_object(struct jrnl_descriptor *jd) { char *buf = NULL; int buf_len, res = 0; ssize_t retsize; /* FIXME: handle larger size */ buf_len = (1 << 22); buf = zalloc(buf_len); if (!buf) { eprintf("failed to allocate memory\n"); return SD_RES_NO_MEM; } /* Flush out journal to disk (VDI object) */ retsize = xpread(jd->fd, &jd->head, sizeof(jd->head), 0); retsize = xpread(jd->fd, buf, jd->head.size, sizeof(jd->head)); retsize = xpwrite(jd->target_fd, buf, jd->head.size, jd->head.offset); if (retsize != jd->head.size) { if (errno == ENOSPC) res = SD_RES_NO_SPACE; else res = SD_RES_EIO; } /* Clean up */ free(buf); return res; }
/* * Copy the initrd to /dev/ram0, copy from the end to the beginning * to avoid taking 2x the memory. */ static int rd_copy_uncompressed(int ffd, int dfd) { char buffer[BUF_SIZE]; off_t bytes; struct stat st; dprintf("kinit: uncompressed initrd\n"); if (ffd < 0 || fstat(ffd, &st) || !S_ISREG(st.st_mode) || (bytes = st.st_size) == 0) return -1; while (bytes) { ssize_t blocksize = ((bytes - 1) & (BUF_SIZE - 1)) + 1; off_t offset = bytes - blocksize; dprintf("kinit: copying %zd bytes at offset %llu\n", blocksize, offset); if (xpread(ffd, buffer, blocksize, offset) != blocksize || xpwrite(dfd, buffer, blocksize, offset) != blocksize) return -1; ftruncate(ffd, offset); /* Free up memory */ bytes = offset; } return 0; }
/* * Escape handler -- * called on recognition of ``escapec'' at the beginning of a line */ char escape(void) { char gch; esctable_t *p; char c = character(value(ESCAPE)); int i; i = getchar(); if (i == EOF) return 0; gch = (i&0177); for (p = etable; p->e_char; p++) if (p->e_char == gch) { if ((p->e_flags&PRIV) && uid) continue; printf("%s", ctrl(c)); (*p->e_func)(gch); return (0); } /* ESCAPE ESCAPE forces ESCAPE */ if (c != gch) xpwrite(FD, &c, 1); return (gch); }
int default_write(uint64_t oid, const struct siocb *iocb) { int flags = prepare_iocb(oid, iocb, false), fd, ret = SD_RES_SUCCESS; char path[PATH_MAX]; ssize_t size; uint32_t len = iocb->length; uint64_t offset = iocb->offset; static bool trim_is_supported = true; if (iocb->epoch < sys_epoch()) { sd_debug("%"PRIu32" sys %"PRIu32, iocb->epoch, sys_epoch()); return SD_RES_OLD_NODE_VER; } if (uatomic_is_true(&sys->use_journal) && unlikely(journal_write_store(oid, iocb->buf, iocb->length, iocb->offset, false)) != SD_RES_SUCCESS) { sd_err("turn off journaling"); uatomic_set_false(&sys->use_journal); flags |= O_DSYNC; sync(); } get_store_path(oid, iocb->ec_index, path); /* * Make sure oid is in the right place because oid might be misplaced * in a wrong place, due to 'shutdown/restart with less/more disks' or * any bugs. We need call err_to_sderr() to return EIO if disk is broken */ if (!default_exist(oid, iocb->ec_index)) return err_to_sderr(path, oid, ENOENT); fd = open(path, flags, sd_def_fmode); if (unlikely(fd < 0)) return err_to_sderr(path, oid, errno); if (trim_is_supported && is_sparse_object(oid)) { if (default_trim(fd, oid, iocb, &offset, &len) < 0) { trim_is_supported = false; offset = iocb->offset; len = iocb->length; } } size = xpwrite(fd, iocb->buf, len, offset); if (unlikely(size != len)) { sd_err("failed to write object %"PRIx64", path=%s, offset=%" PRId32", size=%"PRId32", result=%zd, %m", oid, path, iocb->offset, iocb->length, size); ret = err_to_sderr(path, oid, errno); goto out; } out: close(fd); return ret; }
static int farm_write(uint64_t oid, struct siocb *iocb) { ssize_t size = xpwrite(iocb->fd, iocb->buf, iocb->length, iocb->offset); if (size != iocb->length) return SD_RES_EIO; trunk_update_entry(oid); return SD_RES_SUCCESS; }
/* * ****TIPIN TIPIN**** */ static void tipin(void) { char gch, bol = 1; /* * Kinda klugey here... * check for scripting being turned on from the .tiprc file, * but be careful about just using setscript(), as we may * send a SIGEMT before tipout has a chance to set up catching * it; so wait a second, then setscript() */ if (boolean(value(SCRIPT))) { (void)sleep(1); setscript(); } for (;;) { gch = getchar()&STRIP_PAR; if ((gch == character(value(ESCAPE))) && bol) { if (!(gch = escape())) continue; } else if (!cumode && gch && gch == character(value(RAISECHAR))) { setboolean(value(RAISE), !boolean(value(RAISE))); continue; } else if (gch == '\r') { bol = 1; xpwrite(FD, &gch, 1); if (boolean(value(HALFDUPLEX))) (void)printf("\r\n"); continue; } else if (!cumode && gch && gch == character(value(FORCE))) gch = getchar()&STRIP_PAR; bol = any(gch, value(EOL)); if (boolean(value(RAISE)) && islower((unsigned char)gch)) gch = toupper((unsigned char)gch); xpwrite(FD, &gch, 1); if (boolean(value(HALFDUPLEX))) (void)printf("%c", gch); } }
static int farm_write(uint64_t oid, struct siocb *iocb, int create) { int flags = def_open_flags, fd, ret = SD_RES_SUCCESS; char path[PATH_MAX]; ssize_t size; if (iocb->epoch < sys_epoch()) { dprintf("%"PRIu32" sys %"PRIu32"\n", iocb->epoch, sys_epoch()); return SD_RES_OLD_NODE_VER; } if (!is_data_obj(oid)) flags &= ~O_DIRECT; if (create) flags |= O_CREAT | O_TRUNC; sprintf(path, "%s%016"PRIx64, obj_path, oid); fd = open(path, flags, def_fmode); if (fd < 0) return err_to_sderr(oid, errno); if (flock(fd, LOCK_EX) < 0) { ret = SD_RES_EIO; eprintf("%m\n"); goto out; } if (create && !(iocb->flags & SD_FLAG_CMD_COW)) { ret = prealloc(fd, get_objsize(oid)); if (ret != SD_RES_SUCCESS) { if (flock(fd, LOCK_UN) < 0) { ret = SD_RES_EIO; eprintf("%m\n"); goto out; } goto out; } } size = xpwrite(fd, iocb->buf, iocb->length, iocb->offset); if (flock(fd, LOCK_UN) < 0) { ret = SD_RES_EIO; eprintf("%m\n"); goto out; } if (size != iocb->length) { eprintf("%m\n"); ret = SD_RES_EIO; goto out; } trunk_update_entry(oid); out: close(fd); return ret; }
int default_create_and_write(uint64_t oid, struct siocb *iocb) { char path[PATH_MAX], tmp_path[PATH_MAX]; int flags = get_open_flags(oid, true); int ret, fd; uint32_t len = iocb->length; get_obj_path(oid, path); get_tmp_obj_path(oid, tmp_path); fd = open(tmp_path, flags, def_fmode); if (fd < 0) { if (errno == EEXIST) /* This happens if node membership changes during object * creation; while gateway retries a CREATE request, * recovery process could also recover the object at the * same time. They should try to write the same date, * so it is okay to simply return success here. */ dprintf("%s exists\n", tmp_path); return SD_RES_SUCCESS; eprintf("failed to open %s: %m\n", tmp_path); return err_to_sderr(oid, errno); } if (iocb->offset != 0 || iocb->length != get_objsize(oid)) { ret = prealloc(fd, get_objsize(oid)); if (ret != SD_RES_SUCCESS) goto out; } ret = xpwrite(fd, iocb->buf, len, iocb->offset); if (ret != len) { eprintf("failed to write object. %m\n"); ret = err_to_sderr(oid, errno); goto out; } ret = rename(tmp_path, path); if (ret < 0) { eprintf("failed to rename %s to %s: %m\n", tmp_path, path); ret = err_to_sderr(oid, errno); goto out; } dprintf("%"PRIx64"\n", oid); ret = SD_RES_SUCCESS; out: if (ret != SD_RES_SUCCESS) unlink(tmp_path); close(fd); return ret; }
static int migrate_from_v0_to_v1(void) { int ret, fd; struct sheepdog_config_v1 config; fd = open(config_path, O_RDWR); if (fd < 0) { sd_eprintf("failed to open config file, %m"); return -1; } memset(&config, 0, sizeof(config)); ret = xread(fd, &config, sizeof(config)); if (ret < 0) { sd_eprintf("failed to read config file, %m"); close(fd); return ret; } config.version = 1; ret = xpwrite(fd, &config, sizeof(config), 0); if (ret != sizeof(config)) { sd_eprintf("failed to write config data, %m"); close(fd); return -1; } /* 0.5.1 could wrongly extend the config file, so truncate it here */ ret = ftruncate(fd, sizeof(config)); if (ret != 0) { sd_eprintf("failed to truncate config data, %m"); close(fd); return -1; } close(fd); /* * If the config file contains a space field, the store layout * is compatible with v1. In this case, what we need to do is * only adding version number to the config file. */ if (config.space > 0) return 0; /* upgrade epoch log */ for_each_epoch(update_epoch_from_v0_to_v1); return ret; }
static int jrnl_write_header(struct jrnl_descriptor *jd) { ssize_t ret; struct jrnl_head *head = (struct jrnl_head *) &jd->head; ret = xpwrite(jd->fd, head, sizeof(*head), 0); if (ret != sizeof(*head)) { if (errno == ENOSPC) ret = SD_RES_NO_SPACE; else ret = SD_RES_EIO; } else ret = SD_RES_SUCCESS; return ret; }
static int jrnl_write_end_mark(struct jrnl_descriptor *jd) { ssize_t retsize; int ret; uint32_t end_mark = JRNL_END_MARK; struct jrnl_head *head = (struct jrnl_head *) &jd->head; retsize = xpwrite(jd->fd, &end_mark, sizeof(end_mark), sizeof(*head) + head->size); if (retsize != sizeof(end_mark)) { if (errno == ENOSPC) ret = SD_RES_NO_SPACE; else ret = SD_RES_EIO; } else ret = SD_RES_SUCCESS; return ret; }
int default_write(uint64_t oid, const struct siocb *iocb) { int flags = get_open_flags(oid, false, iocb->flags), fd, ret = SD_RES_SUCCESS; char path[PATH_MAX]; ssize_t size; if (iocb->epoch < sys_epoch()) { sd_dprintf("%"PRIu32" sys %"PRIu32"\n", iocb->epoch, sys_epoch()); return SD_RES_OLD_NODE_VER; } get_obj_path(oid, path); if (uatomic_is_true(&sys->use_journal) && journal_file_write(oid, iocb->buf, iocb->length, iocb->offset, false) != SD_RES_SUCCESS) { sd_eprintf("turn off journaling\n"); uatomic_set_false(&sys->use_journal); flags |= O_DSYNC; sync(); } fd = open(path, flags, def_fmode); if (fd < 0) return err_to_sderr(oid, errno); size = xpwrite(fd, iocb->buf, iocb->length, iocb->offset); if (size != iocb->length) { sd_eprintf("failed to write object %"PRIx64", path=%s, offset=%" PRId64", size=%"PRId32", result=%zd, %m\n", oid, path, iocb->offset, iocb->length, size); ret = err_to_sderr(oid, errno); goto out; } out: close(fd); return ret; }
/* * Escape handler -- * called on recognition of ``escapec'' at the beginning of a line */ int escape(void) { char gch; esctable_t *p; char c = character(value(ESCAPE)); gch = (getchar()&STRIP_PAR); for (p = etable; p->e_char; p++) if (p->e_char == gch) { if ((p->e_flags&PRIV) && uid) continue; (void)printf("%s", ctrl(c)); (*p->e_func)(gch); return (0); } /* ESCAPE ESCAPE forces ESCAPE */ if (c != gch) xpwrite(FD, &c, 1); return (gch); }
int default_write(uint64_t oid, const struct siocb *iocb) { int flags = prepare_iocb(oid, iocb, false), fd, ret = SD_RES_SUCCESS; char path[PATH_MAX]; ssize_t size; if (iocb->epoch < sys_epoch()) { sd_debug("%"PRIu32" sys %"PRIu32, iocb->epoch, sys_epoch()); return SD_RES_OLD_NODE_VER; } if (uatomic_is_true(&sys->use_journal) && unlikely(journal_write_store(oid, iocb->buf, iocb->length, iocb->offset, false)) != SD_RES_SUCCESS) { sd_err("turn off journaling"); uatomic_set_false(&sys->use_journal); flags |= O_DSYNC; sync(); } get_obj_path(oid, path); fd = open(path, flags, sd_def_fmode); if (unlikely(fd < 0)) return err_to_sderr(path, oid, errno); size = xpwrite(fd, iocb->buf, iocb->length, iocb->offset); if (unlikely(size != iocb->length)) { sd_err("failed to write object %"PRIx64", path=%s, offset=%" PRId64", size=%"PRId32", result=%zd, %m", oid, path, iocb->offset, iocb->length, size); ret = err_to_sderr(path, oid, errno); goto out; } out: close(fd); return ret; }
int default_write(uint64_t oid, const struct siocb *iocb) { int flags = prepare_iocb(oid, iocb, false), fd, ret = SD_RES_SUCCESS; char path[PATH_MAX]; ssize_t size; if (iocb->epoch < sys_epoch()) { sd_debug("%"PRIu32" sys %"PRIu32, iocb->epoch, sys_epoch()); return SD_RES_OLD_NODE_VER; } get_store_path(oid, iocb->ec_index, path); /* * Make sure oid is in the right place because oid might be misplaced * in a wrong place, due to 'shutdown/restart with less/more disks' or * any bugs. We need call err_to_sderr() to return EIO if disk is broken */ if (!default_exist(oid, iocb->ec_index)) return err_to_sderr(path, oid, errno); fd = open(path, flags, sd_def_fmode); if (unlikely(fd < 0)) return err_to_sderr(path, oid, errno); size = xpwrite(fd, iocb->buf, iocb->length, iocb->offset); if (unlikely(size != iocb->length)) { sd_err("failed to write object %"PRIx64", path=%s, offset=%" PRId32", size=%"PRId32", result=%zd, %m", oid, path, iocb->offset, iocb->length, size); ret = err_to_sderr(path, oid, errno); goto out; } out: close(fd); return ret; }
static int write_last_sector(int fd, uint32_t length) { const int size = SECTOR_SIZE; char *buf; int ret; off_t off = length - size; buf = valloc(size); if (!buf) { eprintf("failed to allocate memory\n"); return SD_RES_NO_MEM; } memset(buf, 0, size); ret = xpwrite(fd, buf, size, off); if (ret != size) ret = err_to_sderr(0, errno); /* FIXME: set oid */ else ret = SD_RES_SUCCESS; free(buf); return ret; }
ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset) { const char *p = buf; ssize_t total = 0; while (count > 0) { ssize_t nr; nr = xpwrite(fd, p, count, offset); if (nr < 0) return -1; if (nr == 0) { errno = ENOSPC; return -1; } count -= nr; total += nr; p += nr; offset += nr; } return total; }
static int jrnl_apply_to_target_object(struct jrnl_descriptor *jd) { char *buf = NULL; int res = 0; ssize_t retsize; /* Flush out journal to disk (VDI object) */ retsize = xpread(jd->fd, &jd->head, sizeof(jd->head), 0); buf = xzalloc(jd->head.size); retsize = xpread(jd->fd, buf, jd->head.size, sizeof(jd->head)); retsize = xpwrite(jd->target_fd, buf, jd->head.size, jd->head.offset); if (retsize != jd->head.size) { if (errno == ENOSPC) res = SD_RES_NO_SPACE; else res = SD_RES_EIO; } /* Clean up */ free(buf); return res; }
int main(int argc, char *argv[]) { static unsigned char sectbuf[512]; int dev_fd; struct stat st; int status; char **argp, *opt; char mtools_conf[] = "/tmp/syslinux-mtools-XXXXXX"; const char *subdir = NULL; int mtc_fd; FILE *mtc, *mtp; struct libfat_filesystem *fs; libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ int32_t ldlinux_cluster; int nsectors; const char *errmsg; int force = 0; /* -f (force) option */ int stupid = 0; /* -s (stupid) option */ int raid_mode = 0; /* -r (RAID) option */ (void)argc; /* Unused */ mypid = getpid(); program = argv[0]; device = NULL; for ( argp = argv+1 ; *argp ; argp++ ) { if ( **argp == '-' ) { opt = *argp + 1; if ( !*opt ) usage(); while ( *opt ) { if ( *opt == 's' ) { stupid = 1; } else if ( *opt == 'r' ) { raid_mode = 1; } else if ( *opt == 'f' ) { force = 1; /* Force install */ } else if ( *opt == 'd' && argp[1] ) { subdir = *++argp; } else if ( *opt == 'o' && argp[1] ) { filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); /* Byte offset */ } else { usage(); } opt++; } } else { if ( device ) usage(); device = *argp; } } if ( !device ) usage(); /* * First make sure we can open the device at all, and that we have * read/write permission. */ dev_fd = open(device, O_RDWR); if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) { perror(device); exit(1); } if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) { fprintf(stderr, "%s: not a block device or regular file (use -f to override)\n", device); exit(1); } xpread(dev_fd, sectbuf, 512, filesystem_offset); /* * Check to see that what we got was indeed an MS-DOS boot sector/superblock */ if( (errmsg = syslinux_check_bootsect(sectbuf)) ) { die(errmsg); } /* * Create an mtools configuration file */ mtc_fd = mkstemp(mtools_conf); if ( mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")) ) { perror(program); exit(1); } fprintf(mtc, /* "MTOOLS_NO_VFAT=1\n" */ "MTOOLS_SKIP_CHECK=1\n" /* Needed for some flash memories */ "drive s:\n" " file=\"/proc/%lu/fd/%d\"\n" " offset=%llu\n", (unsigned long)mypid, dev_fd, (unsigned long long)filesystem_offset); fclose(mtc); /* * Run mtools to create the LDLINUX.SYS file */ if ( setenv("MTOOLSRC", mtools_conf, 1) ) { perror(program); exit(1); } /* This command may fail legitimately */ system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null"); mtp = popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w"); if ( !mtp || (fwrite(syslinux_ldlinux, 1, syslinux_ldlinux_len, mtp) != syslinux_ldlinux_len) || (status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status)) ) { die("failed to create ldlinux.sys"); } /* * Now, use libfat to create a block map */ fs = libfat_open(libfat_xpread, dev_fd); ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); secp = sectors; nsectors = 0; s = libfat_clustertosector(fs, ldlinux_cluster); while ( s && nsectors < 65 ) { *secp++ = s; nsectors++; s = libfat_nextsector(fs, s); } libfat_close(fs); /* Patch ldlinux.sys and the boot sector */ syslinux_patch(sectors, nsectors, stupid, raid_mode); /* Write the now-patched first sector of ldlinux.sys */ xpwrite(dev_fd, syslinux_ldlinux, 512, filesystem_offset + ((off_t)sectors[0] << 9)); /* Move ldlinux.sys to the desired location */ if (subdir) { char target_file[4096], command[5120]; char *cp = target_file, *ep = target_file+sizeof target_file-16; const char *sd; int slash = 1; cp += sprintf(cp, "'s:/"); for (sd = subdir; *sd; sd++) { if (*sd == '/' || *sd == '\\') { if (slash) continue; /* Remove duplicated slashes */ slash = 1; } else if (*sd == '\'' || *sd == '!') { slash = 0; if (cp < ep) *cp++ = '\''; if (cp < ep) *cp++ = '\\'; if (cp < ep) *cp++ = *sd; if (cp < ep) *cp++ = '\''; continue; } else { slash = 0; } if (cp < ep) *cp++ = *sd; } if (!slash) *cp++ = '/'; strcpy(cp, "ldlinux.sys'"); /* This command may fail legitimately */ sprintf(command, "mattrib -h -r -s %s 2>/dev/null", target_file); system(command); sprintf(command, "mmove -D o -D O s:/ldlinux.sys %s", target_file); status = system(command); if ( !WIFEXITED(status) || WEXITSTATUS(status) ) { fprintf(stderr, "%s: warning: unable to move ldlinux.sys\n", program); status = system("mattrib +r +h +s s:/ldlinux.sys"); } else { sprintf(command, "mattrib +r +h +s %s", target_file); status = system(command); } } else { status = system("mattrib +r +h +s s:/ldlinux.sys"); } if ( !WIFEXITED(status) || WEXITSTATUS(status) ) { fprintf(stderr, "%s: warning: failed to set system bit on ldlinux.sys\n", program); } /* * Cleanup */ unlink(mtools_conf); /* * To finish up, write the boot sector */ /* Read the superblock again since it might have changed while mounted */ xpread(dev_fd, sectbuf, 512, filesystem_offset); /* Copy the syslinux code into the boot sector */ syslinux_make_bootsect(sectbuf); /* Write new boot sector */ xpwrite(dev_fd, sectbuf, 512, filesystem_offset); close(dev_fd); sync(); /* Done! */ return 0; }
int default_create_and_write(uint64_t oid, const struct siocb *iocb) { char path[PATH_MAX], tmp_path[PATH_MAX]; int flags = prepare_iocb(oid, iocb, true); int ret, fd; uint32_t len = iocb->length; size_t obj_size; uint64_t offset = iocb->offset; sd_debug("%"PRIx64, oid); get_store_path(oid, iocb->ec_index, path); get_store_tmp_path(oid, iocb->ec_index, tmp_path); if (uatomic_is_true(&sys->use_journal) && journal_write_store(oid, iocb->buf, iocb->length, iocb->offset, true) != SD_RES_SUCCESS) { sd_err("turn off journaling"); uatomic_set_false(&sys->use_journal); flags |= O_DSYNC; sync(); } fd = open(tmp_path, flags, sd_def_fmode); if (fd < 0) { if (errno == EEXIST) { /* * This happens if node membership changes during object * creation; while gateway retries a CREATE request, * recovery process could also recover the object at the * same time. They should try to write the same date, * so it is okay to simply return success here. */ sd_debug("%s exists", tmp_path); return SD_RES_SUCCESS; } sd_err("failed to open %s: %m", tmp_path); return err_to_sderr(path, oid, errno); } obj_size = get_store_objsize(oid); trim_zero_blocks(iocb->buf, &offset, &len); if (offset != 0 || len != get_objsize(oid)) { if (is_sparse_object(oid)) ret = xftruncate(fd, obj_size); else ret = prealloc(fd, obj_size); if (ret < 0) { ret = err_to_sderr(path, oid, errno); goto out; } } ret = xpwrite(fd, iocb->buf, len, offset); if (ret != len) { sd_err("failed to write object. %m"); ret = err_to_sderr(path, oid, errno); goto out; } ret = rename(tmp_path, path); if (ret < 0) { sd_err("failed to rename %s to %s: %m", tmp_path, path); ret = err_to_sderr(path, oid, errno); goto out; } ret = SD_RES_SUCCESS; objlist_cache_insert(oid); out: if (ret != SD_RES_SUCCESS) unlink(tmp_path); close(fd); return ret; }
int default_create_and_write(uint64_t oid, const struct siocb *iocb) { char path[PATH_MAX], tmp_path[PATH_MAX]; int flags = get_open_flags(oid, true, iocb->flags); int ret, fd; uint32_t len = iocb->length; get_obj_path(oid, path); get_tmp_obj_path(oid, tmp_path); if (uatomic_is_true(&sys->use_journal) && journal_file_write(oid, iocb->buf, iocb->length, iocb->offset, true) != SD_RES_SUCCESS) { sd_eprintf("turn off journaling"); uatomic_set_false(&sys->use_journal); flags |= O_DSYNC; sync(); } fd = open(tmp_path, flags, def_fmode); if (fd < 0) { if (errno == EEXIST) { /* * This happens if node membership changes during object * creation; while gateway retries a CREATE request, * recovery process could also recover the object at the * same time. They should try to write the same date, * so it is okay to simply return success here. */ sd_dprintf("%s exists", tmp_path); return SD_RES_SUCCESS; } sd_eprintf("failed to open %s: %m", tmp_path); return err_to_sderr(oid, errno); } if (iocb->offset != 0 || iocb->length != get_objsize(oid)) { ret = prealloc(fd, get_objsize(oid)); if (ret < 0) { ret = err_to_sderr(oid, errno); goto out; } } ret = xpwrite(fd, iocb->buf, len, iocb->offset); if (ret != len) { sd_eprintf("failed to write object. %m"); ret = err_to_sderr(oid, errno); goto out; } ret = rename(tmp_path, path); if (ret < 0) { sd_eprintf("failed to rename %s to %s: %m", tmp_path, path); ret = err_to_sderr(oid, errno); goto out; } sd_dprintf("%"PRIx64, oid); ret = SD_RES_SUCCESS; out: if (ret != SD_RES_SUCCESS) unlink(tmp_path); close(fd); return ret; }
static int update_epoch_from_v1_to_v2(uint32_t epoch) { char path[PATH_MAX]; struct sd_node_v1 nodes_v1[SD_MAX_NODES]; struct sd_node_v2 nodes_v2[SD_MAX_NODES]; size_t nr_nodes; time_t *t; int len, fd, ret; snprintf(path, sizeof(path), "%s%08u", epoch_path, epoch); fd = open(path, O_RDWR | O_DSYNC); if (fd < 0) { if (errno == ENOENT) return 0; sd_eprintf("failed to open epoch %"PRIu32" log", epoch); return -1; } /* * sheepdog 0.5.6 was released without incrementing the config version. * We detect it by 1) checking the size of epoch file, and 2) checking * the value of sd_node.nid.port */ if ((get_file_size(path) - sizeof(time_t)) % sizeof(nodes_v1[0]) != 0) { sd_dprintf("%s is not a v1 format", path); close(fd); return 0; } ret = xread(fd, nodes_v1, sizeof(nodes_v1)); if (ret < 0) { sd_eprintf("failed to read epoch %"PRIu32" log", epoch); close(fd); return ret; } nr_nodes = ret / sizeof(nodes_v1[0]); for (int i = 0; i < nr_nodes; i++) { if (nodes_v1[i].nid.port == 0) { sd_dprintf("%s is not a v1 format", path); return 0; } memset(&nodes_v2[i].nid, 0, sizeof(nodes_v2[i].nid)); memcpy(nodes_v2[i].nid.addr, nodes_v1[i].nid.addr, sizeof(nodes_v2[i].nid.addr)); nodes_v2[i].nid.port = nodes_v1[i].nid.port; nodes_v2[i].nr_vnodes = nodes_v1[i].nr_vnodes; nodes_v2[i].zone = nodes_v1[i].zone; nodes_v2[i].space = nodes_v1[i].space; } len = sizeof(nodes_v2[0]) * nr_nodes; ret = xpwrite(fd, nodes_v2, len, 0); if (ret != len) { sd_eprintf("failed to write epoch %"PRIu32" log", epoch); close(fd); return -1; } t = (time_t *)&nodes_v1[nr_nodes]; ret = xpwrite(fd, t, sizeof(*t), len); if (ret != sizeof(*t)) { sd_eprintf("failed to write time to epoch %" PRIu32" log", epoch); close(fd); return -1; } close(fd); return 0; }
int default_create_and_write(uint64_t oid, const struct siocb *iocb) { char path[PATH_MAX], tmp_path[PATH_MAX]; int flags = prepare_iocb(oid, iocb, true); int ret, fd; uint32_t len = iocb->length; size_t obj_size; sd_debug("%"PRIx64, oid); get_store_path(oid, iocb->ec_index, path); get_store_tmp_path(oid, iocb->ec_index, tmp_path); fd = open(tmp_path, flags, sd_def_fmode); if (fd < 0) { if (errno == EEXIST) { /* * This happens if node membership changes during object * creation; while gateway retries a CREATE request, * recovery process could also recover the object at the * same time. They should try to write the same date, * so it is okay to simply return success here. */ sd_debug("%s exists", tmp_path); return SD_RES_SUCCESS; } sd_err("failed to open %s: %m", tmp_path); return err_to_sderr(path, oid, errno); } obj_size = get_store_objsize(oid); ret = prealloc(fd, obj_size); if (ret < 0) { ret = err_to_sderr(path, oid, errno); goto out; } ret = xpwrite(fd, iocb->buf, len, iocb->offset); if (ret != len) { sd_err("failed to write object. %m"); ret = err_to_sderr(path, oid, errno); goto out; } /* * Modern FS like ext4, xfs defaults to automatic syncing of files after * replace-via-rename and replace-via-truncate operations. So rename * without fsync() is actually safe. */ ret = rename(tmp_path, path); if (ret < 0) { sd_err("failed to rename %s to %s: %m", tmp_path, path); ret = err_to_sderr(path, oid, errno); goto out; } ret = SD_RES_SUCCESS; objlist_cache_insert(oid); out: if (ret != SD_RES_SUCCESS && unlink(tmp_path) != 0) sd_err("failed to unlink %s: %m", tmp_path); close(fd); return ret; }
/* * Bulk transfer routine -- * used by getfl(), cu_take(), and pipefile() */ static void transfer(char *buf, int fd, char *eofchars) { register int ct; char c; register int cnt, eof, v; time_t start; sig_t f; char r; FILE *ff; v = boolean(value(VERBOSE)); if ((ff = fdopen (fd, "w")) == NULL) { warn("file open"); return; } if ((cnt = number(value(FRAMESIZE))) != BUFSIZ) if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) { warn("file allocation"); (void)fclose(ff); return; } xpwrite(FD, buf, size(buf)); quit = 0; kill(pid, SIGIOT); read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ /* * finish command */ r = '\r'; xpwrite(FD, &r, 1); do read(FD, &c, 1); while ((c&0177) != '\n'); usedefchars (); (void) setjmp(intbuf); f = signal(SIGINT, intcopy); start = time(0); for (ct = 0; !quit;) { eof = read(FD, &c, 1) <= 0; c &= 0177; if (quit) continue; if (eof || any(c, eofchars)) break; if (c == 0) continue; /* ignore nulls */ if (c == '\r') continue; if (c == '\n' && v) printf("\r%d", ++ct); fputc(c, ff); } if (v) prtime(" lines transferred in ", time(0)-start); usetchars (); write(fildes[1], (char *)&ccc, 1); signal(SIGINT, f); (void)fclose(ff); }
/* * Update the ADV in an existing installation. */ int write_adv(const char *path, const char *cfg) { unsigned char advtmp[2 * ADV_SIZE]; char *file; int fd = -1; struct stat st, xst; int err = 0; int rv; rv = asprintf(&file, "%s%s%s", path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/", cfg); if (rv < 0 || !file) { perror(program); return -1; } fd = open(file, O_RDONLY); if (fd < 0) { err = -1; } else if (fstat(fd, &st)) { err = -1; } else if (st.st_size < 2 * ADV_SIZE) { /* Too small to be useful */ err = -2; } else if (xpread(fd, advtmp, 2 * ADV_SIZE, st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) { err = -1; } else { /* We got it... maybe? */ err = syslinux_validate_adv(advtmp) ? -2 : 0; if (!err) { /* Got a good one, write our own ADV here */ clear_attributes(fd); /* Need to re-open read-write */ close(fd); fd = open(file, O_RDWR | O_SYNC); if (fd < 0) { fprintf(stderr, "Cannot open file '%s' in read/write mode !\nFatal error, exiting.\n", file); return -EACCES; } else if (fstat(fd, &xst) || xst.st_ino != st.st_ino || xst.st_dev != st.st_dev || xst.st_size != st.st_size) { fprintf(stderr, "%s: race condition on write\n", file); err = -2; } /* Write our own version ... */ if (xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) { err = -1; } sync(); set_attributes(fd); } } if (err == -2) fprintf(stderr, "%s: cannot write auxiliary data (need --update)?\n", file); else if (err == -1) perror(file); if (fd >= 0) close(fd); if (file) free(file); return err; }
int main(int argc, char *argv[]) { static unsigned char sectbuf[512]; unsigned char *dp; const unsigned char *cdp; int dev_fd, fd; struct stat st; int nb, left; int err = 0; pid_t f, w; int status; char mntname[64], devfdname[64]; char *ldlinux_name, **argp, *opt; int my_umask; int force = 0; /* -f (force) option */ int offset = 0; /* -o (offset) option */ program = argv[0]; mypid = getpid(); device = NULL; umask(077); for ( argp = argv+1 ; *argp ; argp++ ) { if ( **argp == '-' ) { opt = *argp + 1; if ( !*opt ) usage(); while ( *opt ) { if ( *opt == 's' ) { syslinux_make_stupid(); /* Use "safe, slow and stupid" code */ } else if ( *opt == 'f' ) { force = 1; /* Force install */ } else if ( *opt == 'o' && argp[1] ) { offset = strtoul(*++argp, NULL, 0); /* Byte offset */ } else { usage(); } opt++; } } else { if ( device ) usage(); device = *argp; } } if ( !device ) usage(); /* * First make sure we can open the device at all, and that we have * read/write permission. */ dev_fd = open(device, O_RDWR|O_LARGEFILE); if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) { perror(device); exit(1); } if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) { die("not a block device or regular file (use -f to override)"); } if ( !force && offset != 0 && !S_ISREG(st.st_mode) ) { die("not a regular file and an offset specified (use -f to override)"); } xpread(dev_fd, sectbuf, 512, offset); fsync(dev_fd); /* * Check to see that what we got was indeed an MS-DOS boot sector/superblock */ if(!syslinux_check_bootsect(sectbuf,device)) { exit(1); } /* * Now mount the device. */ if ( geteuid() ) { die("This program needs root privilege"); } else { int i = 0; struct stat dst; int rv; /* We're root or at least setuid. Make a temp dir and pass all the gunky options to mount. */ if ( chdir("/tmp") ) { perror(program); exit(1); } #define TMP_MODE (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH|S_ISVTX) if ( stat(".", &dst) || !S_ISDIR(dst.st_mode) || (dst.st_mode & TMP_MODE) != TMP_MODE ) { die("possibly unsafe /tmp permissions"); } for ( i = 0 ; ; i++ ) { snprintf(mntname, sizeof mntname, "syslinux.mnt.%lu.%d", (unsigned long)mypid, i); if ( lstat(mntname, &dst) != -1 || errno != ENOENT ) continue; rv = mkdir(mntname, 0000); if ( rv == -1 ) { if ( errno == EEXIST || errno == EINTR ) continue; perror(program); exit(1); } if ( lstat(mntname, &dst) || dst.st_mode != (S_IFDIR|0000) || dst.st_uid != 0 ) { die("someone is trying to symlink race us!"); } break; /* OK, got something... */ } mntpath = mntname; #if DO_DIRECT_MOUNT if ( S_ISREG(st.st_mode) ) { /* It's file, need to mount it loopback */ unsigned int n = 0; struct loop_info64 loopinfo; for ( n = 0 ; loop_fd < 0 ; n++ ) { snprintf(devfdname, sizeof devfdname, "/dev/loop%u", n); loop_fd = open(devfdname, O_RDWR); if ( loop_fd < 0 && errno == ENOENT ) { die("no available loopback device!"); } if ( ioctl(loop_fd, LOOP_SET_FD, (void *)dev_fd) ) { close(loop_fd); loop_fd = -1; if ( errno != EBUSY ) die("cannot set up loopback device"); else continue; } if ( ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo) || (loopinfo.lo_offset = offset, ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo)) ) die("cannot set up loopback device"); } } else { snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", (unsigned long)mypid, dev_fd); } if ( mount(devfdname, mntpath, "msdos", MS_NOEXEC|MS_NOSUID, "umask=077,quiet") ) die("could not mount filesystem"); #else snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", (unsigned long)mypid, dev_fd); f = fork(); if ( f < 0 ) { perror(program); rmdir(mntpath); exit(1); } else if ( f == 0 ) { char mnt_opts[128]; if ( S_ISREG(st.st_mode) ) { snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,loop,offset=%llu,umask=077,quiet", (unsigned long long)offset); } else { snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,umask=077,quiet"); } execl(_PATH_MOUNT, _PATH_MOUNT, "-t", "msdos", "-o", mnt_opts,\ devfdname, mntpath, NULL); _exit(255); /* execl failed */ } w = waitpid(f, &status, 0); if ( w != f || status ) { rmdir(mntpath); exit(1); /* Mount failed */ } #endif } ldlinux_name = alloca(strlen(mntpath)+13); if ( !ldlinux_name ) { perror(program); err = 1; goto umount; } sprintf(ldlinux_name, "%s/ldlinux.sys", mntpath); unlink(ldlinux_name); fd = open(ldlinux_name, O_WRONLY|O_CREAT|O_TRUNC, 0444); if ( fd < 0 ) { perror(device); err = 1; goto umount; } cdp = syslinux_ldlinux; left = syslinux_ldlinux_len; while ( left ) { nb = write(fd, cdp, left); if ( nb == -1 && errno == EINTR ) continue; else if ( nb <= 0 ) { perror(device); err = 1; goto umount; } dp += nb; left -= nb; } /* * I don't understand why I need this. Does the DOS filesystems * not honour the mode passed to open()? */ fchmod(fd, 0400); close(fd); umount: #if DO_DIRECT_MOUNT if ( umount2(mntpath, 0) ) die("could not umount path"); if ( loop_fd != -1 ) { ioctl(loop_fd, LOOP_CLR_FD, 0); /* Free loop device */ close(loop_fd); loop_fd = -1; } #else f = fork(); if ( f < 0 ) { perror("fork"); exit(1); } else if ( f == 0 ) { execl(_PATH_UMOUNT, _PATH_UMOUNT, mntpath, NULL); } w = waitpid(f, &status, 0); if ( w != f || status ) { exit(1); } #endif sync(); rmdir(mntpath); if ( err ) exit(err); /* * To finish up, write the boot sector */ /* Read the superblock again since it might have changed while mounted */ xpread(dev_fd, sectbuf, 512, offset); /* Copy the syslinux code into the boot sector */ syslinux_make_bootsect(sectbuf); /* Write new boot sector */ xpwrite(dev_fd, sectbuf, 512, offset); close(dev_fd); sync(); /* Done! */ return 0; }