static char *find_msg_start(char *msg) { char *p = msg; skip_nonspaces(&p); /* skip message type */ skip_spaces(&p); skip_nonspaces(&p); /* skip Job */ skip_spaces(&p); /* after spaces come the message */ return p; }
/* * Note, we receive the whole attribute record, but we select out only the stat * packet, VolSessionId, VolSessionTime, FileIndex, file type, and file name to * store in the catalog. */ static void update_attribute(JCR *jcr, char *msg, int32_t msglen) { unser_declare; uint32_t VolSessionId, VolSessionTime; int32_t Stream; uint32_t FileIndex; char *p; int len; char *fname, *attr; ATTR_DBR *ar = NULL; uint32_t reclen; /* * Start transaction allocates jcr->attr and jcr->ar if needed */ db_start_transaction(jcr, jcr->db); /* start transaction if not already open */ ar = jcr->ar; /* * Start by scanning directly in the message buffer to get Stream * there may be a cached attr so we cannot yet write into * jcr->attr or jcr->ar */ p = msg; skip_nonspaces(&p); /* UpdCat */ skip_spaces(&p); skip_nonspaces(&p); /* Job=nnn */ skip_spaces(&p); skip_nonspaces(&p); /* "FileAttributes" */ p += 1; /* * The following "SD header" fields are serialized */ unser_begin(p, 0); unser_uint32(VolSessionId); /* VolSessionId */ unser_uint32(VolSessionTime); /* VolSessionTime */ unser_int32(FileIndex); /* FileIndex */ unser_int32(Stream); /* Stream */ unser_uint32(reclen); /* Record length */ p += unser_length(p); /* Raw record follows */ /** * At this point p points to the raw record, which varies according * to what kind of a record (Stream) was sent. Note, the integer * fields at the beginning of these "raw" records are in ASCII with * spaces between them so one can use scanf or manual scanning to * extract the fields. * * File Attributes * File_index * File type * Filename (full path) * Encoded attributes * Link name (if type==FT_LNK or FT_LNKSAVED) * Encoded extended-attributes (for Win32) * Delta sequence number (32 bit int) * * Restore Object * File_index * File_type * Object_index * Object_len (possibly compressed) * Object_full_len (not compressed) * Object_compression * Plugin_name * Object_name * Binary Object data */ Dmsg1(400, "UpdCat msg=%s\n", msg); Dmsg5(400, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d reclen=%d\n", VolSessionId, VolSessionTime, FileIndex, Stream, reclen); jcr->SDJobBytes += reclen; /* update number of bytes transferred for quotas */ /* * Depending on the stream we are handling dispatch. */ switch (Stream) { case STREAM_UNIX_ATTRIBUTES: case STREAM_UNIX_ATTRIBUTES_EX: if (jcr->cached_attribute) { Dmsg2(400, "Cached attr. Stream=%d fname=%s\n", ar->Stream, ar->fname); if (!db_create_attributes_record(jcr, jcr->db, ar)) { Jmsg1(jcr, M_FATAL, 0, _("Attribute create error: ERR=%s"), db_strerror(jcr->db)); } jcr->cached_attribute = false; } /* * Any cached attr is flushed so we can reuse jcr->attr and jcr->ar */ jcr->attr = check_pool_memory_size(jcr->attr, msglen); memcpy(jcr->attr, msg, msglen); p = jcr->attr - msg + p; /* point p into jcr->attr */ skip_nonspaces(&p); /* skip FileIndex */ skip_spaces(&p); ar->FileType = str_to_int32(p); skip_nonspaces(&p); /* skip FileType */ skip_spaces(&p); fname = p; len = strlen(fname); /* length before attributes */ attr = &fname[len+1]; ar->DeltaSeq = 0; if (ar->FileType == FT_REG) { p = attr + strlen(attr) + 1; /* point to link */ p = p + strlen(p) + 1; /* point to extended attributes */ p = p + strlen(p) + 1; /* point to delta sequence */ /* * Older FDs don't have a delta sequence, so check if it is there */ if (p - jcr->attr < msglen) { ar->DeltaSeq = str_to_int32(p); /* delta_seq */ } } Dmsg2(400, "dird<stored: stream=%d %s\n", Stream, fname); Dmsg1(400, "dird<stored: attr=%s\n", attr); ar->attr = attr; ar->fname = fname; if (ar->FileType == FT_DELETED) { ar->FileIndex = 0; /* special value */ } else { ar->FileIndex = FileIndex; } ar->Stream = Stream; ar->link = NULL; if (jcr->mig_jcr) { ar->JobId = jcr->mig_jcr->JobId; } else { ar->JobId = jcr->JobId; } ar->Digest = NULL; ar->DigestType = CRYPTO_DIGEST_NONE; jcr->cached_attribute = true; Dmsg2(400, "dird<filed: stream=%d %s\n", Stream, fname); Dmsg1(400, "dird<filed: attr=%s\n", attr); break; case STREAM_RESTORE_OBJECT: { ROBJECT_DBR ro; memset(&ro, 0, sizeof(ro)); ro.Stream = Stream; ro.FileIndex = FileIndex; if (jcr->mig_jcr) { ro.JobId = jcr->mig_jcr->JobId; } else { ro.JobId = jcr->JobId; } Dmsg1(100, "Robj=%s\n", p); skip_nonspaces(&p); /* skip FileIndex */ skip_spaces(&p); ro.FileType = str_to_int32(p); /* FileType */ skip_nonspaces(&p); skip_spaces(&p); ro.object_index = str_to_int32(p); /* Object Index */ skip_nonspaces(&p); skip_spaces(&p); ro.object_len = str_to_int32(p); /* object length possibly compressed */ skip_nonspaces(&p); skip_spaces(&p); ro.object_full_len = str_to_int32(p); /* uncompressed object length */ skip_nonspaces(&p); skip_spaces(&p); ro.object_compression = str_to_int32(p); /* compression */ skip_nonspaces(&p); skip_spaces(&p); ro.plugin_name = p; /* point to plugin name */ len = strlen(ro.plugin_name); ro.object_name = &ro.plugin_name[len+1]; /* point to object name */ len = strlen(ro.object_name); ro.object = &ro.object_name[len+1]; /* point to object */ ro.object[ro.object_len] = 0; /* add zero for those who attempt printing */ Dmsg7(100, "oname=%s stream=%d FT=%d FI=%d JobId=%d, obj_len=%d\nobj=\"%s\"\n", ro.object_name, ro.Stream, ro.FileType, ro.FileIndex, ro.JobId, ro.object_len, ro.object); /* * Store it. */ if (!db_create_restore_object_record(jcr, jcr->db, &ro)) { Jmsg1(jcr, M_FATAL, 0, _("Restore object create error. %s"), db_strerror(jcr->db)); } break; } default: if (crypto_digest_stream_type(Stream) != CRYPTO_DIGEST_NONE) { fname = p; if (ar->FileIndex != FileIndex) { Jmsg3(jcr, M_WARNING, 0, _("%s not same File=%d as attributes=%d\n"), stream_to_ascii(Stream), FileIndex, ar->FileIndex); } else { /* * Update digest in catalog */ char digestbuf[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)]; int len = 0; int type = CRYPTO_DIGEST_NONE; switch(Stream) { case STREAM_MD5_DIGEST: len = CRYPTO_DIGEST_MD5_SIZE; type = CRYPTO_DIGEST_MD5; break; case STREAM_SHA1_DIGEST: len = CRYPTO_DIGEST_SHA1_SIZE; type = CRYPTO_DIGEST_SHA1; break; case STREAM_SHA256_DIGEST: len = CRYPTO_DIGEST_SHA256_SIZE; type = CRYPTO_DIGEST_SHA256; break; case STREAM_SHA512_DIGEST: len = CRYPTO_DIGEST_SHA512_SIZE; type = CRYPTO_DIGEST_SHA512; break; default: /* * Never reached ... */ Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. Unsupported digest stream type: %d"), Stream); } bin_to_base64(digestbuf, sizeof(digestbuf), fname, len, true); Dmsg3(400, "DigestLen=%d Digest=%s type=%d\n", strlen(digestbuf), digestbuf, Stream); if (jcr->cached_attribute) { ar->Digest = digestbuf; ar->DigestType = type; Dmsg2(400, "Cached attr with digest. Stream=%d fname=%s\n", ar->Stream, ar->fname); /* * Update BaseFile table */ if (!db_create_attributes_record(jcr, jcr->db, ar)) { Jmsg1(jcr, M_FATAL, 0, _("attribute create error. %s"), db_strerror(jcr->db)); } jcr->cached_attribute = false; } else { if (!db_add_digest_to_file_record(jcr, jcr->db, ar->FileId, digestbuf, type)) { Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. %s"), db_strerror(jcr->db)); } } } } break; } }
/** Decode a LinkFI field of encoded stat packet */ int32_t decode_LinkFI(char *buf, struct stat *statp, int stat_size) { char *p = buf; int64_t val; /* * We store into the stat packet so make sure the caller's conception * is the same as ours. They can be different if LARGEFILE is not * the same when compiling this library and the calling program. */ ASSERT(stat_size == (int)sizeof(struct stat)); skip_nonspaces(&p); /* st_dev */ p++; /* skip space */ skip_nonspaces(&p); /* st_ino */ p++; p += from_base64(&val, p); plug(statp->st_mode, val); /* st_mode */ p++; skip_nonspaces(&p); /* st_nlink */ p++; skip_nonspaces(&p); /* st_uid */ p++; skip_nonspaces(&p); /* st_gid */ p++; skip_nonspaces(&p); /* st_rdev */ p++; skip_nonspaces(&p); /* st_size */ p++; skip_nonspaces(&p); /* st_blksize */ p++; skip_nonspaces(&p); /* st_blocks */ p++; skip_nonspaces(&p); /* st_atime */ p++; skip_nonspaces(&p); /* st_mtime */ p++; skip_nonspaces(&p); /* st_ctime */ /* Optional FileIndex of hard linked file data */ if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) { p++; p += from_base64(&val, p); return (int32_t)val; } return 0; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Read and parse syslinux config file. // // return: // 0: ok, 1: error // int read_config_file(void) { FILE *f; char *s, *t, buf[MAX_CONFIG_LINE_LEN]; unsigned u, menu_idx = 0, label_size = 0, append_size = 0; menu_t *menu_ptr = NULL, **menu_next = &menu; menu_default = calloc(1, sizeof *menu_default); if(!(f = fopen(syslinux_config_file(), "r"))) return 1; while((s = fgets(buf, sizeof buf, f))) { chop_line(s); s = skip_spaces(s); if(!*s || *s == '#') continue; t = skip_nonspaces(s); if(*t) *t++ = 0; t = skip_spaces(t); if(!strcasecmp(s, "timeout")) { timeout = atoi(t); continue; } if(!strcasecmp(s, "default")) { menu_default->label = strdup(t); u = strlen(t); if(u > label_size) label_size = u; continue; } if(!strcasecmp(s, "label")) { menu_ptr = *menu_next = calloc(1, sizeof **menu_next); menu_next = &menu_ptr->next; menu_idx++; menu_ptr->label = menu_ptr->menu_label = strdup(t); u = strlen(t); if(u > label_size) label_size = u; continue; } if(!strcasecmp(s, "kernel") && menu_ptr) { menu_ptr->kernel = strdup(t); continue; } if(!strcasecmp(s, "linux") && menu_ptr) { menu_ptr->linux = strdup(t); continue; } if(!strcasecmp(s, "localboot") && menu_ptr) { menu_ptr->localboot = strdup(t); continue; } if(!strcasecmp(s, "initrd") && menu_ptr) { menu_ptr->initrd = strdup(t); continue; } if(!strcasecmp(s, "append")) { (menu_ptr ?: menu_default)->append = strdup(t); u = strlen(t); if(u > append_size) append_size = u; continue; } if(!strcasecmp(s, "ipappend")) { (menu_ptr ?: menu_default)->ipappend = strdup(t); continue; }
/* * Fill the fileWidget box with the contents of the current directory */ void restorePage::fillDirectory() { mainWin->waitEnter(); char modes[20], user[20], group[20], size[20], date[30]; char marked[10]; int pnl, fnl; POOLMEM *file = get_pool_memory(PM_FNAME); POOLMEM *path = get_pool_memory(PM_FNAME); fileWidget->clear(); m_console->write_dir(m_conn, "dir", false); QList<QTreeWidgetItem *> treeItemList; QStringList item; m_rx.setPattern("has no children\\.$"); bool first = true; while (m_console->read(m_conn) > 0) { char *p = m_console->msg(m_conn); char *l; strip_trailing_newline(p); if (*p == '$' || !*p) { continue; } if (first) { if (m_rx.indexIn(QString(p)) != -1) { continue; } first = false; } l = p; skip_nonspaces(&p); /* permissions */ *p++ = 0; bstrncpy(modes, l, sizeof(modes)); skip_spaces(&p); skip_nonspaces(&p); /* link count */ *p++ = 0; skip_spaces(&p); l = p; skip_nonspaces(&p); /* user */ *p++ = 0; skip_spaces(&p); bstrncpy(user, l, sizeof(user)); l = p; skip_nonspaces(&p); /* group */ *p++ = 0; bstrncpy(group, l, sizeof(group)); skip_spaces(&p); l = p; skip_nonspaces(&p); /* size */ *p++ = 0; bstrncpy(size, l, sizeof(size)); skip_spaces(&p); l = p; skip_nonspaces(&p); /* date/time */ skip_spaces(&p); skip_nonspaces(&p); *p++ = 0; bstrncpy(date, l, sizeof(date)); skip_spaces(&p); if (*p == '*') { bstrncpy(marked, "*", sizeof(marked)); p++; } else { bstrncpy(marked, " ", sizeof(marked)); } split_path_and_filename(p, path, &pnl, file, &fnl); item.clear(); item << "" << file << modes << user << group << size << date; if (item[1].endsWith("/")) { addDirectory(item[1]); } QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item); ti->setTextAlignment(5, Qt::AlignRight); /* right align size */ if (strcmp(marked, "*") == 0) { ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png"))); ti->setData(0, Qt::UserRole, true); } else { ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png"))); ti->setData(0, Qt::UserRole, false); } treeItemList.append(ti); } fileWidget->clear(); fileWidget->insertTopLevelItems(0, treeItemList); for (int i=0; i<7; i++) { fileWidget->resizeColumnToContents(i); } free_pool_memory(file); free_pool_memory(path); mainWin->waitExit(); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Read and parse syslinux config file. // // return: // 0: ok, 1: error // int read_config_file(const char *filename) { FILE *f; char *s, *t, buf[MAX_CONFIG_LINE_LEN]; unsigned u, top_level = 0, text = 0; if(!strcmp(filename, "~")) { top_level = 1; filename = syslinux_config_file(); gfx_menu.entries = 0; gfx_menu.label_size = 0; gfx_menu.arg_size = 0; menu_ptr = NULL; menu_next = &menu; menu_default = calloc(1, sizeof *menu_default); } if(!(f = fopen(filename, "r"))) return 1; while((s = fgets(buf, sizeof buf, f))) { chop_line(s); s = skipspace(s); if(!*s || *s == '#') continue; t = skip_nonspaces(s); if(*t) *t++ = 0; t = skipspace(t); if(!strcasecmp(s, "endtext")) { text = 0; continue; } if (text) continue; if(!strcasecmp(s, "timeout")) { timeout = atoi(t); continue; } if(!strcasecmp(s, "default")) { menu_default->label = strdup(t); u = strlen(t); if(u > gfx_menu.label_size) gfx_menu.label_size = u; continue; } if(!strcasecmp(s, "label")) { menu_ptr = *menu_next = calloc(1, sizeof **menu_next); menu_next = &menu_ptr->next; gfx_menu.entries++; menu_ptr->label = menu_ptr->menu_label = strdup(t); u = strlen(t); if(u > gfx_menu.label_size) gfx_menu.label_size = u; continue; } if(!strcasecmp(s, "kernel") && menu_ptr) { menu_ptr->kernel = strdup(t); continue; } if(!strcasecmp(s, "linux") && menu_ptr) { menu_ptr->linux = strdup(t); continue; } if(!strcasecmp(s, "localboot") && menu_ptr) { menu_ptr->localboot = strdup(t); continue; } if(!strcasecmp(s, "initrd") && menu_ptr) { menu_ptr->initrd = strdup(t); continue; } if(!strcasecmp(s, "append")) { (menu_ptr ?: menu_default)->append = strdup(t); u = strlen(t); if(u > gfx_menu.arg_size) gfx_menu.arg_size = u; continue; } if(!strcasecmp(s, "ipappend")) { (menu_ptr ?: menu_default)->ipappend = strdup(t); continue; }
/* * Get a message * Call appropriate processing routine * If it is not a Jmsg or a ReqCat message, * return it to the caller. * * This routine is called to get the next message from * another daemon. If the message is in canonical message * format and the type is known, it will be dispatched * to the appropriate handler. If the message is * in any other format, it will be returned. * * E.g. any message beginning with a digit will be passed * through to the caller. * All other messages are expected begin with some identifier * -- for the moment only the first character is checked, but * at a later time, the whole identifier (e.g. Jmsg, CatReq, ...) * could be checked. This is followed by Job=Jobname <user-defined> * info. The identifier is used to dispatch the message to the right * place (Job message, catalog request, ...). The Job is used to lookup * the JCR so that the action is performed on the correct jcr, and * the rest of the message is up to the user. Note, DevUpd uses * *System* for the Job name, and hence no JCR is obtained. This * is a *rare* case where a jcr is not really needed. * */ int bget_dirmsg(BSOCK *bs, bool allow_any_message) { int32_t n = BNET_TERMINATE; char Job[MAX_NAME_LENGTH]; char MsgType[20]; int type; utime_t mtime; /* message time */ JCR *jcr = bs->jcr(); char *msg; for ( ; !bs->is_stop() && !bs->is_timed_out(); ) { n = bs->recv(); Dmsg2(200, "bget_dirmsg %d: %s\n", n, bs->msg); if (bs->is_stop() || bs->is_timed_out()) { return n; /* error or terminate */ } if (n == BNET_SIGNAL) { /* handle signal */ /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */ switch (bs->msglen) { case BNET_EOD: /* end of data */ return n; case BNET_EOD_POLL: bs->fsend(OK_msg);/* send response */ return n; /* end of data */ case BNET_TERMINATE: bs->set_terminated(); return n; case BNET_POLL: bs->fsend(OK_msg); /* send response */ break; case BNET_HEARTBEAT: // encode_time(time(NULL), Job); // Dmsg1(100, "%s got heartbeat.\n", Job); break; case BNET_HB_RESPONSE: break; case BNET_STATUS: /* *****FIXME***** Implement more completely */ bs->fsend("Status OK\n"); bs->signal(BNET_EOD); break; case BNET_BTIME: /* send BAREOS time */ char ed1[50]; bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1)); break; default: Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen); return n; } continue; } /* * Handle normal data */ if (n > 0 && B_ISDIGIT(bs->msg[0])) { /* response? */ return n; /* yes, return it */ } /* * If we get here, it must be a request. Either * a message to dispatch, or a catalog request. * Try to fulfill it. */ if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) { /* * If the special flag allow_any_message is given ignore * the error and just return it as normal data. */ if (allow_any_message) { return n; } else { Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); continue; } } /* * Skip past "Jmsg Job=nnn" */ if (!(msg=find_msg_start(bs->msg))) { Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); continue; } /* * Here we are expecting a message of the following format: * Jmsg Job=nnn type=nnn level=nnn Message-string * Note, level should really be mtime, but that changes * the protocol. */ if (bs->msg[0] == 'J') { /* Job message */ if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%lld", Job, &type, &mtime) != 3) { Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); continue; } Dmsg1(900, "Got msg: %s\n", bs->msg); skip_spaces(&msg); skip_nonspaces(&msg); /* skip type=nnn */ skip_spaces(&msg); skip_nonspaces(&msg); /* skip level=nnn */ if (*msg == ' ') { msg++; /* skip leading space */ } Dmsg1(900, "Dispatch msg: %s", msg); dispatch_message(jcr, type, mtime, msg); continue; } /* * Here we expact a CatReq message * CatReq Job=nn Catalog-Request-Message */ if (bs->msg[0] == 'C') { /* Catalog request */ Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg); catalog_request(jcr, bs); continue; } if (bs->msg[0] == 'U') { /* SD sending attributes */ Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg); catalog_update(jcr, bs); continue; } if (bs->msg[0] == 'B') { /* SD sending file spool attributes */ Dmsg2(100, "Blast attributes jcr 0x%x: %s", jcr, bs->msg); char filename[256]; if (sscanf(bs->msg, "BlastAttr Job=%127s File=%255s", Job, filename) != 2) { Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); continue; } unbash_spaces(filename); if (despool_attributes_from_file(jcr, filename)) { bs->fsend("1000 OK BlastAttr\n"); } else { bs->fsend("1990 ERROR BlastAttr\n"); } continue; } if (bs->msg[0] == 'M') { /* Mount request */ Dmsg1(900, "Mount req: %s", bs->msg); mount_request(jcr, bs, msg); continue; } if (bs->msg[0] == 'S') { /* Status change */ int JobStatus; char Job[MAX_NAME_LENGTH]; if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) { set_jcr_sd_job_status(jcr, JobStatus); /* current status */ } else { Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); } continue; } #ifdef needed /* No JCR for Device Updates! */ if (bs->msg[0] = 'D') { /* Device update */ DEVICE *dev; POOL_MEM dev_name, changer_name, media_type, volume_name; int dev_open, dev_append, dev_read, dev_labeled; int dev_offline, dev_autochanger, dev_autoselect; int dev_num_writers, dev_max_writers, dev_reserved; uint64_t dev_read_time, dev_write_time, dev_write_bytes, dev_read_bytes; uint64_t dev_PoolId; Dmsg1(100, "<stored: %s", bs->msg); if (sscanf(bs->msg, Device_update, &Job, dev_name.c_str(), &dev_append, &dev_read, &dev_num_writers, &dev_open, &dev_labeled, &dev_offline, &dev_reserved, &dev_max_writers, &dev_autoselect, &dev_autochanger, changer_name.c_str(), media_type.c_str(), volume_name.c_str(), &dev_read_time, &dev_write_time, &dev_read_bytes, &dev_write_bytes) != 19) { Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg); } else { unbash_spaces(dev_name); dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str()); if (!dev) { continue; } unbash_spaces(changer_name); unbash_spaces(media_type); unbash_spaces(volume_name); bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName)); bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType)); bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName)); /* Note, these are copied because they are boolean rather than * integer. */ dev->open = dev_open; dev->append = dev_append; dev->read = dev_read; dev->labeled = dev_labeled; dev->offline = dev_offline; dev->autoselect = dev_autoselect; dev->autochanger = dev_autochanger > 0; dev->num_drives = dev_autochanger; /* does double duty */ dev->PoolId = dev_PoolId; dev->num_writers = dev_num_writers; dev->max_writers = dev_max_writers; dev->reserved = dev_reserved; dev->found = true; dev->DevReadTime = dev_read_time; /* TODO : have to update database */ dev->DevWriteTime = dev_write_time; dev->DevReadBytes = dev_read_bytes; dev->DevWriteBytes = dev_write_bytes; } continue; } #endif return n; } return n; }
/* * This routine is called only during a Verify */ void get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId) { BSOCK *fd; int n, len; FILE_DBR fdbr; struct stat statf; /* file stat */ struct stat statc; /* catalog stat */ char buf[MAXSTRING]; POOLMEM *fname = get_pool_memory(PM_MESSAGE); int do_Digest = CRYPTO_DIGEST_NONE; int32_t file_index = 0; memset(&fdbr, 0, sizeof(FILE_DBR)); fd = jcr->file_bsock; fdbr.JobId = JobId; jcr->FileIndex = 0; Dmsg0(20, "bdird: waiting to receive file attributes\n"); /* * Get Attributes and Signature from File daemon * We expect: * FileIndex * Stream * Options or Digest (MD5/SHA1) * Filename * Attributes * Link name ??? */ while ((n=bget_dirmsg(fd)) >= 0 && !job_canceled(jcr)) { int32_t stream, full_stream; char *attr, *p, *fn; char Opts_Digest[MAXSTRING]; /* Verify Opts or MD5/SHA1 digest */ if (job_canceled(jcr)) { free_pool_memory(fname); return; } fname = check_pool_memory_size(fname, fd->msglen); jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen); Dmsg1(200, "Atts+Digest=%s\n", fd->msg); if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &full_stream, fname)) != 3) { Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n" " mslen=%d msg=%s\n"), len, fd->msglen, fd->msg); free_pool_memory(fname); return; } stream = full_stream & STREAMMASK_TYPE; Dmsg4(30, "Got hdr: FilInx=%d FullStream=%d Stream=%d fname=%s.\n", file_index, full_stream, stream, fname); /* * We read the Options or Signature into fname * to prevent overrun, now copy it to proper location. */ bstrncpy(Opts_Digest, fname, sizeof(Opts_Digest)); p = fd->msg; skip_nonspaces(&p); /* skip FileIndex */ skip_spaces(&p); skip_nonspaces(&p); /* skip Stream */ skip_spaces(&p); skip_nonspaces(&p); /* skip Opts_Digest */ p++; /* skip space */ fn = fname; while (*p != 0) { *fn++ = *p++; /* copy filename */ } *fn = *p++; /* term filename and point to attribs */ attr = p; /* * Got attributes stream, decode it */ if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX) { int32_t LinkFIf, LinkFIc; Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr); jcr->JobFiles++; jcr->FileIndex = file_index; /* remember attribute file_index */ jcr->previous_jr.FileIndex = file_index; decode_stat(attr, &statf, sizeof(statf), &LinkFIf); /* decode file stat packet */ do_Digest = CRYPTO_DIGEST_NONE; jcr->fn_printed = false; pm_strcpy(jcr->fname, fname); /* move filename into JCR */ Dmsg2(040, "dird<filed: stream=%d %s\n", stream, jcr->fname); Dmsg1(020, "dird<filed: attr=%s\n", attr); /* * Find equivalent record in the database */ fdbr.FileId = 0; if (!db_get_file_attributes_record(jcr, jcr->db, jcr->fname, &jcr->previous_jr, &fdbr)) { Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname); Dmsg1(020, _("File not in catalog: %s\n"), jcr->fname); jcr->setJobStatus(JS_Differences); continue; } else { /* * mark file record as visited by stuffing the * current JobId, which is unique, into the MarkId field. */ db_mark_file_record(jcr, jcr->db, fdbr.FileId, jcr->JobId); } Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname, file_index, Opts_Digest); decode_stat(fdbr.LStat, &statc, sizeof(statc), &LinkFIc); /* decode catalog stat */ /* * Loop over options supplied by user and verify the * fields he requests. */ for (p=Opts_Digest; *p; p++) { char ed1[30], ed2[30]; switch (*p) { case 'i': /* compare INODEs */ if (statc.st_ino != statf.st_ino) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_ino differ. Cat: %s File: %s\n"), edit_uint64((uint64_t)statc.st_ino, ed1), edit_uint64((uint64_t)statf.st_ino, ed2)); jcr->setJobStatus(JS_Differences); } break; case 'p': /* permissions bits */ if (statc.st_mode != statf.st_mode) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_mode differ. Cat: %x File: %x\n"), (uint32_t)statc.st_mode, (uint32_t)statf.st_mode); jcr->setJobStatus(JS_Differences); } break; case 'n': /* number of links */ if (statc.st_nlink != statf.st_nlink) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_nlink differ. Cat: %d File: %d\n"), (uint32_t)statc.st_nlink, (uint32_t)statf.st_nlink); jcr->setJobStatus(JS_Differences); } break; case 'u': /* user id */ if (statc.st_uid != statf.st_uid) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_uid differ. Cat: %u File: %u\n"), (uint32_t)statc.st_uid, (uint32_t)statf.st_uid); jcr->setJobStatus(JS_Differences); } break; case 'g': /* group id */ if (statc.st_gid != statf.st_gid) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_gid differ. Cat: %u File: %u\n"), (uint32_t)statc.st_gid, (uint32_t)statf.st_gid); jcr->setJobStatus(JS_Differences); } break; case 's': /* size */ if (statc.st_size != statf.st_size) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_size differ. Cat: %s File: %s\n"), edit_uint64((uint64_t)statc.st_size, ed1), edit_uint64((uint64_t)statf.st_size, ed2)); jcr->setJobStatus(JS_Differences); } break; case 'a': /* access time */ if (statc.st_atime != statf.st_atime) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_atime differs\n")); jcr->setJobStatus(JS_Differences); } break; case 'm': if (statc.st_mtime != statf.st_mtime) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_mtime differs\n")); jcr->setJobStatus(JS_Differences); } break; case 'c': /* ctime */ if (statc.st_ctime != statf.st_ctime) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_ctime differs\n")); jcr->setJobStatus(JS_Differences); } break; case 'd': /* file size decrease */ if (statc.st_size > statf.st_size) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" st_size decrease. Cat: %s File: %s\n"), edit_uint64((uint64_t)statc.st_size, ed1), edit_uint64((uint64_t)statf.st_size, ed2)); jcr->setJobStatus(JS_Differences); } break; case '5': /* compare MD5 */ Dmsg1(500, "set Do_MD5 for %s\n", jcr->fname); do_Digest = CRYPTO_DIGEST_MD5; break; case '1': /* compare SHA1 */ do_Digest = CRYPTO_DIGEST_SHA1; break; case ':': case 'V': default: break; } } /* * Got Digest Signature from Storage daemon * It came across in the Opts_Digest field. */ } else if (crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) { Dmsg2(400, "stream=Digest inx=%d Digest=%s\n", file_index, Opts_Digest); /* * When ever we get a digest it MUST have been * preceded by an attributes record, which sets attr_file_index */ if (jcr->FileIndex != (uint32_t)file_index) { Jmsg2(jcr, M_FATAL, 0, _("MD5/SHA1 index %d not same as attributes %d\n"), file_index, jcr->FileIndex); free_pool_memory(fname); return; } if (do_Digest != CRYPTO_DIGEST_NONE) { db_escape_string(jcr, jcr->db, buf, Opts_Digest, strlen(Opts_Digest)); if (strcmp(buf, fdbr.Digest) != 0) { prt_fname(jcr); Jmsg(jcr, M_INFO, 0, _(" %s differs. File=%s Cat=%s\n"), stream_to_ascii(stream), buf, fdbr.Digest); jcr->setJobStatus(JS_Differences); } do_Digest = CRYPTO_DIGEST_NONE; } } jcr->JobFiles = file_index; } if (fd->is_error()) { berrno be; Jmsg2(jcr, M_FATAL, 0, _("bdird<filed: bad attributes from filed n=%d : %s\n"), n, be.bstrerror()); free_pool_memory(fname); return; } /* Now find all the files that are missing -- i.e. all files in * the database where the MarkId != current JobId */ jcr->fn_printed = false; bsnprintf(buf, sizeof(buf), "SELECT Path.Path,Filename.Name FROM File,Path,Filename " "WHERE File.JobId=%d AND File.FileIndex > 0 " "AND File.MarkId!=%d AND File.PathId=Path.PathId " "AND File.FilenameId=Filename.FilenameId", JobId, jcr->JobId); /* missing_handler is called for each file found */ db_sql_query(jcr->db, buf, missing_handler, (void *)jcr); if (jcr->fn_printed) { jcr->setJobStatus(JS_Differences); } free_pool_memory(fname); }
/* Update the free space on the device */ bool DEVICE::update_freespace() { POOL_MEM ocmd(PM_FNAME); POOLMEM* results; char* icmd; char* p; uint64_t free, total; char ed1[50]; bool ok = false; int status; berrno be; if (!is_file()) { Mmsg(errmsg, ""); return true; } /* The device must be mounted in order for freespace to work */ if (requires_mount()) { mount(1); } if (get_os_device_freespace()) { Dmsg4(20, "get_os_device_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media()); return true; } icmd = device->free_space_command; if (!icmd) { set_freespace(0, 0, 0, false); Dmsg2(20, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", edit_uint64(free_space, ed1), free_space_errno); Mmsg(errmsg, _("No FreeSpace command defined.\n")); return false; } edit_mount_codes(ocmd, icmd); Dmsg1(20, "update_freespace: cmd=%s\n", ocmd.c_str()); results = get_pool_memory(PM_MESSAGE); Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str()); status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results); Dmsg2(20, "Freespace status=%d result=%s\n", status, results); /* Should report "1223232 12323232\n" "free total\n" */ if (status == 0) { free = str_to_int64(results) * 1024; p = results; if (skip_nonspaces(&p)) { total = str_to_int64(p) * 1024; } else { total = 0; } Dmsg1(400, "Free space program run: Freespace=%s\n", results); if (free >= 0) { set_freespace(free, total, 0, true); /* have valid freespace */ Mmsg(errmsg, ""); ok = true; } } else { set_freespace(0, 0, EPIPE, false); /* no valid freespace */ Mmsg2(errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"), results, be.bstrerror(status)); dev_errno = free_space_errno; Dmsg4(20, "Cannot get free space on device %s. free_space=%s, " "free_space_errno=%d ERR=%s\n", print_name(), edit_uint64(free_space, ed1), free_space_errno, errmsg); } free_pool_memory(results); Dmsg4(20, "leave update_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media()); return ok; }
/* * Fill the CList box with files at path */ void FillDirectory(const char *path, Window *restore) { char pathbuf[MAXSTRING]; char modes[20], user[20], group[20], size[20], date[30]; char file[1000]; char marked[10]; gchar *text[NUM_COLUMNS] = {marked, file, modes, user, group, size, date}; GtkCList *list = restore->list; int row = 0; stop_director_reader(NULL); pm_strcpy(&restore->fname, path); gtk_entry_set_text(GTK_ENTRY(restore_dir), restore->fname); gtk_clist_freeze(list); gtk_clist_clear(list); bsnprintf(pathbuf, sizeof(pathbuf), "cd %s", path); Dmsg1(100, "%s\n", pathbuf); write_director(pathbuf); discard_to_prompt(); write_director("dir"); while (bnet_recv(UA_sock) > 0) { char *p = UA_sock->msg; char *l; strip_trailing_junk(UA_sock->msg); if (*p == '$') { break; } Dmsg1(200, "Got: %s\n", p); if (!*p) { continue; } l = p; skip_nonspaces(&p); /* permissions */ *p++ = 0; bstrncpy(modes, l, sizeof(modes)); skip_spaces(&p); skip_nonspaces(&p); /* link count */ *p++ = 0; skip_spaces(&p); l = p; skip_nonspaces(&p); /* user */ *p++ = 0; skip_spaces(&p); bstrncpy(user, l, sizeof(user)); l = p; skip_nonspaces(&p); /* group */ *p++ = 0; bstrncpy(group, l, sizeof(group)); skip_spaces(&p); l = p; skip_nonspaces(&p); /* size */ *p++ = 0; bstrncpy(size, l, sizeof(size)); skip_spaces(&p); l = p; skip_nonspaces(&p); /* date/time */ skip_spaces(&p); skip_nonspaces(&p); *p++ = 0; bstrncpy(date, l, sizeof(date)); skip_spaces(&p); if (*p == '*') { bstrncpy(marked, "x", sizeof(marked)); p++; } else { bstrncpy(marked, " ", sizeof(marked)); } split_path_and_filename(p, &restore->path, &restore->pnl, &restore->file, &restore->fnl); // Dmsg1(000, "restore->fname=%s\n", restore->fname); bstrncpy(file, restore->file, sizeof(file)); // printf("modes=%s user=%s group=%s size=%s date=%s file=%s\n", // modes, user, group, size, date, file); gtk_clist_append(list, text); row++; } /* Fix up length of file column */ gtk_clist_set_column_width(list, FILE_COLUMN, gtk_clist_optimal_column_width(list, FILE_COLUMN)); gtk_clist_set_column_width(list, MODES_COLUMN, gtk_clist_optimal_column_width(list, MODES_COLUMN)); gtk_clist_thaw(list); start_director_reader(NULL); }