/* * Get a list of the Distfile Option Entries for each enabled * value in "opts". */ char * getondistoptlist(opt_t opts) { int i; static char buf[1024]; for (i = 0, buf[0] = CNULL; distoptinfo[i].do_name; ++i) { if (!IS_ON(opts, distoptinfo[i].do_value)) continue; if (buf[0] == CNULL) (void) strlcpy(buf, distoptinfo[i].do_name, sizeof buf); else { (void) strlcat(buf, ",", sizeof buf); (void) strlcat(buf, distoptinfo[i].do_name, sizeof buf); } if (distoptinfo[i].do_arg) { (void) strlcat(buf, "=", sizeof buf); (void) strlcat(buf, distoptinfo[i].do_arg, sizeof buf); } } return(buf); }
int main(void) { byte lamps = 0b00000000; byte opcao; do { printf("\n=======================\n"); printf(" LÂMPADAS! \n"); printf("=======================\n\n"); printf("1 - Estado das lâmpadas\n"); printf("2 - Ligar lâmpada\n"); printf("3 - Apagar lâmpada\n"); printf("4 - Sair do programa\n\n"); printf("Opção: "); scanf("%hu", (short*) &opcao); switch (opcao) { case 1: { byte idx; for (idx = 0; idx < 8; idx++) { printf("Lâmpada #%d: %s\n", idx+1, (IS_ON(lamps, idx+1)) ? "ON" : "OFF"); } } break; case 2: { byte position; printf("Posição: "); scanf("%hu", (short*) &position); TURN_ON(lamps, position); } break; case 3: { byte position; printf("Posição: "); scanf("%hu", (short*) &position); TURN_OFF(lamps, position); } break; case 4: break; default : printf("\n\nOpção incorreta!"); } } while (opcao != 4); return 0; }
/* * Do the commands in cmds (initialized by yyparse). */ void docmds(struct namelist *hostlist, int argc, char **argv) { struct cmd *c; char *cp; int i; (void) signal(SIGHUP, sighandler); (void) signal(SIGINT, sighandler); (void) signal(SIGQUIT, sighandler); (void) signal(SIGTERM, sighandler); if (!nflag) mysetlinebuf(stdout); /* Make output (mostly) clean */ #if defined(USE_STATDB) if (!nflag && (dostatdb || juststatdb)) { extern long reccount; message(MT_INFO, "Making stat database [%s] ... \n", gettimestr()); if (mkstatdb() < 0) error("Warning: Make stat database failed."); message(MT_INFO, "Stat database created: %d files stored [%s].\n", reccount, gettimestr()); if (juststatdb) return; } #endif /* USE_STATDB */ /* * Print errors for any command line targets we didn't find. * If any errors are found, return to main() which will then exit. */ for (i = 0; i < argc; i++) { int found; for (found = FALSE, c = cmds; c != NULL; c = c->c_next) { if (c->c_label && argv[i] && strcmp(c->c_label, argv[i]) == 0) { found = TRUE; break; } } if (!found) error("Label \"%s\" is not defined in the distfile.", argv[i]); } if (nerrs) return; /* * Main command loop. Loop through all the commands. */ for (c = cmds; c != NULL; c = c->c_next) { checkcmd(c); if (do_fork) { /* * Let the children take care of their assigned host */ if (amchild) { if (strcmp(c->c_name, currenthost) != 0) continue; } else if (c->c_flags & CMD_ASSIGNED) { /* This cmd has been previously assigned */ debugmsg(DM_MISC, "prev assigned: %s\n", c->c_name); continue; } } if (hostlist) { /* Do specific hosts as specified on command line */ struct namelist *nlptr; for (nlptr = hostlist; nlptr; nlptr = nlptr->n_next) /* * Try an exact match and then a match * without '@' (if present). */ if ((strcmp(c->c_name, nlptr->n_name) == 0) || ((cp = strchr(c->c_name, '@')) && strcmp(++cp, nlptr->n_name) == 0)) docmd(c, argc, argv); continue; } else /* Do all of the command */ docmd(c, argc, argv); } if (do_fork) { /* * We're multi-threaded, so do appropriate shutdown * actions based on whether we're the parent or a child. */ if (amchild) { if (!IS_ON(options, DO_QUIET)) message(MT_VERBOSE, "updating of %s finished", currenthost); closeconn(); cleanup(0); exit(nerrs); } /* * Wait for all remaining active children to finish */ while (activechildren > 0) { debugmsg(DM_MISC, "Waiting for %d children to finish.\n", activechildren); waitup(); } } else if (!nflag) { /* * We're single-threaded so close down current connection */ closeconn(); cleanup(0); } }
/* * Notify the list of people the changes that were made. * rhost == NULL if we are mailing a list of changes compared to at time * stamp file. */ static void notify(char *rhost, struct namelist *to, time_t lmod) { int fd; ssize_t len; FILE *pf; struct stat stb; static char buf[BUFSIZ]; extern char *locuser; char *file, *user; if (IS_ON(options, DO_VERIFY) || to == NULL) return; if ((file = getnotifyfile()) == NULL) return; if (!IS_ON(options, DO_QUIET)) { message(MT_INFO, "notify %s%s %s", (rhost) ? "@" : "", (rhost) ? rhost : "", getnlstr(to)); } if (nflag) return; debugmsg(DM_MISC, "notify() temp file = '%s'", file); if ((fd = open(file, O_RDONLY)) < 0) { error("%s: open for reading failed: %s", file, SYSERR); return; } if (fstat(fd, &stb) < 0) { error("%s: fstat failed: %s", file, SYSERR); (void) close(fd); return; } if (stb.st_size == 0) { (void) close(fd); return; } /* * Create a pipe to mailing program. * Set IFS to avoid possible security problem with users * setting "IFS=/". */ (void) snprintf(buf, sizeof(buf), "IFS=\" \t\"; export IFS; %s -oi -t", _PATH_SENDMAIL); pf = popen(buf, "w"); if (pf == NULL) { error("notify: \"%s\" failed\n", _PATH_SENDMAIL); (void) unlink(file); (void) close(fd); return; } /* * Output the proper header information. */ (void) fprintf(pf, "Auto-Submitted: auto-generated\n"); (void) fprintf(pf, "From: rdist (Remote distribution program)\n"); (void) fprintf(pf, "To:"); if (!any('@', to->n_name) && rhost != NULL) (void) fprintf(pf, " %s@%s", to->n_name, rhost); else (void) fprintf(pf, " %s", to->n_name); to = to->n_next; while (to != NULL) { if (!any('@', to->n_name) && rhost != NULL) (void) fprintf(pf, ", %s@%s", to->n_name, rhost); else (void) fprintf(pf, ", %s", to->n_name); to = to->n_next; } (void) putc('\n', pf); if ((user = getlogin()) == NULL) user = locuser; if (rhost != NULL) (void) fprintf(pf, "Subject: files updated by %s from %s to %s\n", locuser, host, rhost); else (void) fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod)); (void) putc('\n', pf); (void) putc('\n', pf); (void) fprintf(pf, "Options: %s\n\n", getondistoptlist(options)); while ((len = read(fd, buf, sizeof(buf))) > 0) (void) fwrite(buf, 1, len, pf); (void) pclose(pf); (void) close(fd); (void) unlink(file); }
/* * Process commands for comparing files to time stamp files. */ static void dodcolon(struct cmd *cmd, char **filev) { struct subcmd *sc; struct namelist *f; char *cp, **cpp; struct stat stb; struct namelist *files = cmd->c_files; struct subcmd *sbcmds = cmd->c_cmds; char *env, *stamp = cmd->c_name; debugmsg(DM_CALL, "dodcolon()"); if (files == NULL) { error("No files to be updated for target \"%s\"", cmd->c_label); return; } if (stat(stamp, &stb) < 0) { error("%s: stat failed: %s", stamp, SYSERR); return; } debugmsg(DM_MISC, "%s: mtime %d\n", stamp, stb.st_mtime); env = NULL; for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { if (sc->sc_type == CMDSPECIAL) { env = (char *) xmalloc(sizeof(E_FILES) + 3); (void) snprintf(env, sizeof(E_FILES) + 3, "%s='", E_FILES); break; } } subcmds = sbcmds; filelist = files; lastmod = stb.st_mtime; if (!nflag && !IS_ON(options, DO_VERIFY)) /* * Set atime and mtime to current time */ (void) setfiletime(stamp, (time_t) 0, (time_t) 0); for (f = files; f != NULL; f = f->n_next) { if (filev) { for (cpp = filev; *cpp; cpp++) if (strcmp(f->n_name, *cpp) == 0) goto found; continue; } found: ptarget = NULL; cmptime(f->n_name, sbcmds, &env); } for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { if (sc->sc_type == NOTIFY) notify(NULL, sc->sc_args, (time_t)lastmod); else if (sc->sc_type == CMDSPECIAL && env) { size_t len = strlen(env); if (env[len - 1] == ':') env[--len] = CNULL; len += 2 + strlen(sc->sc_name) + 1; env = xrealloc(env, len); (void) strlcat(env, "';", len); (void) strlcat(env, sc->sc_name, len); message(MT_CHANGE, "cmdspecial \"%s\"", env); if (!nflag && IS_OFF(options, DO_VERIFY)) runcommand(env); (void) free(env); env = NULL; /* so cmdspecial is only called once */ } } if (!nflag && !IS_ON(options, DO_VERIFY) && (cp = getnotifyfile())) (void) unlink(cp); }
/* * Compare the mtime of file to the list of time stamps. */ static void cmptime(char *name, struct subcmd *sbcmds, char **env) { struct subcmd *sc; struct stat stb; debugmsg(DM_CALL, "cmptime(%s)", name); if (except(name)) return; if (nflag) { (void) printf("comparing dates: %s\n", name); return; } /* * first time cmptime() is called? */ if (ptarget == NULL) { if (exptilde(target, name, sizeof(target)) == NULL) return; ptarget = name = target; while (*ptarget) ptarget++; } if (access(name, R_OK) < 0 || stat(name, &stb) < 0) { error("%s: cannot access file: %s", name, SYSERR); return; } if (S_ISDIR(stb.st_mode)) { rcmptime(&stb, sbcmds, env); return; } else if (!S_ISREG(stb.st_mode)) { error("%s: not a plain file", name); return; } if (stb.st_mtime > lastmod) { message(MT_INFO, "%s: file is newer", name); for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { char buf[BUFSIZ]; if (sc->sc_type != SPECIAL) continue; if (sc->sc_args != NULL && !inlist(sc->sc_args, name)) continue; (void) snprintf(buf, sizeof(buf), "%s=%s;%s", E_LOCFILE, name, sc->sc_name); message(MT_CHANGE, "special \"%s\"", buf); if (*env) { size_t len = strlen(*env) + strlen(name) + 2; *env = (char *) xrealloc(*env, len); (void) strlcat(*env, name, len); (void) strlcat(*env, ":", len); } if (IS_ON(options, DO_VERIFY)) continue; runcommand(buf); } } }
/* * Process commands for sending files to other machines. */ static void doarrow(struct cmd *cmd, char **filev) { struct namelist *f; struct subcmd *sc; char **cpp; int n, ddir, destdir; volatile opt_t opts = options; struct namelist *files; struct subcmd *sbcmds; char *rhost; volatile int didupdate = 0; if (setjmp_ok) { error("reentrant call to doarrow"); abort(); } if (!cmd) { debugmsg(DM_MISC, "doarrow() NULL cmd parameter"); return; } files = cmd->c_files; sbcmds = cmd->c_cmds; rhost = cmd->c_name; if (files == NULL) { error("No files to be updated on %s for target \"%s\"", rhost, cmd->c_label); return; } debugmsg(DM_CALL, "doarrow(%x, %s, %x) start", files, A(rhost), sbcmds); if (nflag) (void) printf("updating host %s\n", rhost); else { if (cmd->c_flags & CMD_CONNFAILED) { debugmsg(DM_MISC, "makeconn %s failed before; skipping\n", rhost); return; } if (setjmp(finish_jmpbuf)) { setjmp_ok = FALSE; debugmsg(DM_MISC, "setjmp to finish_jmpbuf"); markfailed(cmd, cmds); return; } setjmp_ok = TRUE; if (!makeconn(rhost)) { setjmp_ok = FALSE; markfailed(cmd, cmds); return; } } subcmds = sbcmds; filelist = files; n = 0; for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { if (sc->sc_type != INSTALL) continue; n++; /* * destination is a directory if one of the following is true: * a) more than one name specified on left side of -> directive * b) basename of destination in "install" directive is "." * (e.g. install /tmp/.;) * c) name on left side of -> directive is a directory on local system. * * We need 2 destdir flags (destdir and ddir) because single directory * source is handled differently. In this case, ddir is 0 (which * tells install() not to send DIRTARGET directive to remote rdistd) * and destdir is 1 (which tells remfilename() how to build the FILE * variables correctly). In every other case, destdir and ddir will * have the same value. */ ddir = files->n_next != NULL; /* destination is a directory */ if (!ddir) { struct stat s; int isadir = 0; if (lstat(files->n_name, &s) == 0) isadir = S_ISDIR(s.st_mode); if (!isadir && sc->sc_name && *sc->sc_name) ddir = !strcmp(xbasename(sc->sc_name),"."); destdir = isadir | ddir; } else destdir = ddir; debugmsg(DM_MISC, "Debug files->n_next= %d, destdir=%d, ddir=%d", files->n_next, destdir, ddir); if (!sc->sc_name || !*sc->sc_name) { destdir = 0; ddir = 0; } debugmsg(DM_MISC, "Debug sc->sc_name=%x, destdir=%d, ddir=%d", sc->sc_name, destdir, ddir); for (f = files; f != NULL; f = f->n_next) { if (filev) { for (cpp = filev; *cpp; cpp++) if (strcmp(f->n_name, *cpp) == 0) goto found; continue; } found: if (install(f->n_name, sc->sc_name, ddir, destdir, sc->sc_options) > 0) ++didupdate; opts = sc->sc_options; } } /* end loop for each INSTALL command */ /* if no INSTALL commands present, do default install */ if (!n) { for (f = files; f != NULL; f = f->n_next) { if (filev) { for (cpp = filev; *cpp; cpp++) if (strcmp(f->n_name, *cpp) == 0) goto found2; continue; } found2: /* ddir & destdir set to zero for default install */ if (install(f->n_name, NULL, 0, 0, options) > 0) ++didupdate; } } /* * Run any commands for the entire cmd */ if (didupdate > 0) { runcmdspecial(cmd, opts); didupdate = 0; } if (!nflag) (void) signal(SIGPIPE, cleanup); for (sc = sbcmds; sc != NULL; sc = sc->sc_next) if (sc->sc_type == NOTIFY) notify(rhost, sc->sc_args, (time_t) 0); if (!nflag) { struct linkbuf *nextl, *l; for (l = ihead; l != NULL; freelinkinfo(l), l = nextl) { nextl = l->nextp; if (contimedout || IS_ON(opts, DO_IGNLNKS) || l->count == 0) continue; message(MT_WARNING, "%s: Warning: %d %s link%s", l->pathname, abs(l->count), (l->count > 0) ? "missing" : "extra", (l->count == 1) ? "" : "s"); } ihead = NULL; } setjmp_ok = FALSE; }
/* * Create a connection to the rdist server on the machine rhost. * Return 0 if the connection fails or 1 if it succeeds. */ static int makeconn(char *rhost) { char *ruser, *cp; static char *cur_host = NULL; extern char *locuser; extern int64_t min_freefiles, min_freespace; extern char *remotemsglist; char tuser[BUFSIZ], buf[BUFSIZ]; u_char respbuff[BUFSIZ]; int n; debugmsg(DM_CALL, "makeconn(%s)", rhost); /* * See if we're already connected to this host */ if (cur_host != NULL && rem_w >= 0) { if (strcmp(cur_host, rhost) == 0) return(1); closeconn(); } /* * Determine remote user and current host names */ cur_host = rhost; cp = strchr(rhost, '@'); if (cp != NULL) { char c = *cp; *cp = CNULL; (void) strlcpy((char *)tuser, rhost, sizeof(tuser)); *cp = c; rhost = cp + 1; ruser = tuser; if (*ruser == CNULL) ruser = locuser; else if (!okname(ruser)) return(0); } else ruser = locuser; if (!IS_ON(options, DO_QUIET)) message(MT_VERBOSE, "updating host %s", rhost); (void) snprintf(buf, sizeof(buf), "%.*s -S", (int)(sizeof(buf)-5), path_rdistd); if ((rem_r = rem_w = remotecmd(rhost, locuser, ruser, buf)) < 0) return(0); /* * First thing received should be S_VERSION */ respbuff[0] = '\0'; n = remline(respbuff, sizeof(respbuff), TRUE); if (n <= 0 || respbuff[0] != S_VERSION) { if (n > 0) error("Unexpected input from server: \"%s\".", respbuff); else error("No input from server."); closeconn(); return(0); } /* * For future compatibility we check to see if the server * sent it's version number to us. If it did, we use it, * otherwise, we send our version number to the server and let * it decide if it can handle our protocol version. */ if (respbuff[1] == CNULL) { /* * The server wants us to send it our version number */ (void) sendcmd(S_VERSION, "%d", VERSION); if (response() < 0) return(0); } else { /* * The server sent it's version number to us */ proto_version = atoi(&respbuff[1]); if (proto_version != VERSION) { fatalerr( "Server version (%d) is not the same as local version (%d).", proto_version, VERSION); return(0); } } /* * Send config commands */ if (host[0]) { (void) sendcmd(C_SETCONFIG, "%c%s", SC_HOSTNAME, host); if (response() < 0) return(0); } if (min_freespace) { (void) sendcmd(C_SETCONFIG, "%c%lld", SC_FREESPACE, min_freespace); if (response() < 0) return(0); } if (min_freefiles) { (void) sendcmd(C_SETCONFIG, "%c%lld", SC_FREEFILES, min_freefiles); if (response() < 0) return(0); } if (remotemsglist) { (void) sendcmd(C_SETCONFIG, "%c%s", SC_LOGGING, remotemsglist); if (response() < 0) return(0); } if (strcmp(defowner, "bin") != 0) { (void) sendcmd(C_SETCONFIG, "%c%s", SC_DEFOWNER, defowner); if (response() < 0) return(0); } if (strcmp(defgroup, "bin") != 0) { (void) sendcmd(C_SETCONFIG, "%c%s", SC_DEFGROUP, defgroup); if (response() < 0) return(0); } return(1); }