int main(int argc, char **argv) { int rc = 0; int errflg = 0; int opt; struct rlimit rlim; if ((command = strrchr(argv[0], '/')) != NULL) command++; else command = argv[0]; /* options */ while ((opt = getopt(argc, argv, "r")) != EOF) { switch (opt) { case 'r': /* show registers */ rflag = 1; break; default: errflg = 1; break; } } argc -= optind; argv += optind; if (errflg || argc <= 0) { (void) fprintf(stderr, "usage:\t%s [-r] { pid | core }[/lwps] ...\n", command); (void) fprintf(stderr, " (report process status flags)\n"); (void) fprintf(stderr, " -r : report registers\n"); return (2); } /* * Make sure we'll have enough file descriptors to handle a target * that has many many mappings. */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rlim); (void) enable_extended_FILE_stdio(-1, -1); } while (argc-- > 0) rc += look(*argv++); return (rc); }
int Setrlimit() { struct rlimit rlim; int fd_limit; if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) Die(gettext("getrlimit failed")); fd_limit = rlim.rlim_cur; rlim.rlim_max = MIN(rlim.rlim_max, RLIMIT_NOFILE_MAX); rlim.rlim_cur = rlim.rlim_max; (void) enable_extended_FILE_stdio(-1, -1); if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) return (fd_limit); else return (rlim.rlim_cur); }
int main(int argc, char **argv) { int rflag = 0, sflag = 0, xflag = 0, Fflag = 0; int errflg = 0, Sflag = 0; int rc = 0; int opt; const char *bar8 = "-------"; const char *bar16 = "----------"; const char *bar; struct rlimit rlim; struct stat64 statbuf; char buf[128]; int mapfd; int prg_gflags = PGRAB_RDONLY; int prr_flags = 0; boolean_t use_agent_lwp = B_FALSE; if ((command = strrchr(argv[0], '/')) != NULL) command++; else command = argv[0]; while ((opt = getopt(argc, argv, "arsxSlLFA:")) != EOF) { switch (opt) { case 'a': /* include shared mappings in -[xS] */ aflag = 1; break; case 'r': /* show reserved mappings */ rflag = 1; break; case 's': /* show hardware page sizes */ sflag = 1; break; case 'S': /* show swap reservations */ Sflag = 1; break; case 'x': /* show extended mappings */ xflag = 1; break; case 'l': /* show unresolved link map names */ lflag = 1; break; case 'L': /* show lgroup information */ Lflag = 1; use_agent_lwp = B_TRUE; break; case 'F': /* force grabbing (no O_EXCL) */ Fflag = PGRAB_FORCE; break; case 'A': if (parse_addr_range(optarg, &start_addr, &end_addr) != 0) errflg++; break; default: errflg = 1; break; } } argc -= optind; argv += optind; if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || (aflag && (!xflag && !Sflag)) || (Lflag && (xflag || Sflag))) { errflg = 1; } if (errflg || argc <= 0) { (void) fprintf(stderr, "usage:\t%s [-rslF] [-A start[,end]] { pid | core } ...\n", command); (void) fprintf(stderr, "\t\t(report process address maps)\n"); (void) fprintf(stderr, "\t%s -L [-rslF] [-A start[,end]] pid ...\n", command); (void) fprintf(stderr, "\t\t(report process address maps lgroups mappings)\n"); (void) fprintf(stderr, "\t%s -x [-aslF] [-A start[,end]] pid ...\n", command); (void) fprintf(stderr, "\t\t(show resident/anon/locked mapping details)\n"); (void) fprintf(stderr, "\t%s -S [-alF] [-A start[,end]] { pid | core } ...\n", command); (void) fprintf(stderr, "\t\t(show swap reservations)\n\n"); (void) fprintf(stderr, "\t-a: include shared mappings in -[xS] summary\n"); (void) fprintf(stderr, "\t-r: show reserved address maps\n"); (void) fprintf(stderr, "\t-s: show hardware page sizes\n"); (void) fprintf(stderr, "\t-l: show unresolved dynamic linker map names\n"); (void) fprintf(stderr, "\t-F: force grabbing of the target process\n"); (void) fprintf(stderr, "\t-L: show lgroup mappings\n"); (void) fprintf(stderr, "\t-A start,end: limit output to the specified range\n"); return (2); } /* * Make sure we'll have enough file descriptors to handle a target * that has many many mappings. */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rlim); (void) enable_extended_FILE_stdio(-1, -1); } /* * The implementation of -L option creates an agent LWP in the target * process address space. The agent LWP issues meminfo(2) system calls * on behalf of the target process. If we are interrupted prematurely, * the target process remains in the stopped state with the agent still * attached to it. To prevent such situation we catch signals from * terminal and terminate gracefully. */ if (use_agent_lwp) { /* * Buffer output to stdout, stderr while process is grabbed. * Prevents infamous deadlocks due to pmap `pgrep xterm` and * other variants. */ (void) proc_initstdio(); prg_gflags = PGRAB_RETAIN | Fflag; prr_flags = PRELEASE_RETAIN; if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) (void) sigset(SIGHUP, intr); if (sigset(SIGINT, SIG_IGN) == SIG_DFL) (void) sigset(SIGINT, intr); if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) (void) sigset(SIGQUIT, intr); (void) sigset(SIGPIPE, intr); (void) sigset(SIGTERM, intr); } while (argc-- > 0) { char *arg; int gcode; psinfo_t psinfo; int tries = 0; if (use_agent_lwp) (void) proc_flushstdio(); if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, prg_gflags, &gcode)) == NULL) { (void) fprintf(stderr, "%s: cannot examine %s: %s\n", command, arg, Pgrab_error(gcode)); rc++; continue; } procname = arg; /* for perr() */ addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; bar = addr_width == 8 ? bar8 : bar16; (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); proc_unctrl_psinfo(&psinfo); if (Pstate(Pr) != PS_DEAD) { (void) snprintf(buf, sizeof (buf), "/proc/%d/map", (int)psinfo.pr_pid); if ((mapfd = open(buf, O_RDONLY)) < 0) { (void) fprintf(stderr, "%s: cannot " "examine %s: lost control of " "process\n", command, arg); rc++; Prelease(Pr, prr_flags); continue; } } else { mapfd = -1; } again: map_count = 0; if (Pstate(Pr) == PS_DEAD) { (void) printf("core '%s' of %d:\t%.70s\n", arg, (int)psinfo.pr_pid, psinfo.pr_psargs); if (rflag || sflag || xflag || Sflag || Lflag) { (void) printf(" -%c option is not compatible " "with core files\n", xflag ? 'x' : sflag ? 's' : rflag ? 'r' : Lflag ? 'L' : 'S'); Prelease(Pr, prr_flags); rc++; continue; } } else { (void) printf("%d:\t%.70s\n", (int)psinfo.pr_pid, psinfo.pr_psargs); } if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { struct totals t; /* * Since we're grabbing the process readonly, we need * to make sure the address space doesn't change during * execution. */ if (Pstate(Pr) != PS_DEAD) { if (tries++ == MAX_TRIES) { Prelease(Pr, prr_flags); (void) close(mapfd); (void) fprintf(stderr, "%s: cannot " "examine %s: address space is " "changing\n", command, arg); continue; } if (fstat64(mapfd, &statbuf) != 0) { Prelease(Pr, prr_flags); (void) close(mapfd); (void) fprintf(stderr, "%s: cannot " "examine %s: lost control of " "process\n", command, arg); continue; } } nstacks = psinfo.pr_nlwp * 2; stacks = calloc(nstacks, sizeof (stacks[0])); if (stacks != NULL) { int n = 0; (void) Plwp_iter(Pr, getstack, &n); qsort(stacks, nstacks, sizeof (stacks[0]), cmpstacks); } (void) memset(&t, 0, sizeof (t)); if (Pgetauxval(Pr, AT_BASE) != -1L && Prd_agent(Pr) == NULL) { (void) fprintf(stderr, "%s: warning: " "librtld_db failed to initialize; " "shared library information will not be " "available\n", command); } /* * Gather data */ if (xflag) rc += xmapping_iter(Pr, gather_xmap, NULL, 0); else if (Sflag) rc += xmapping_iter(Pr, gather_xmap, NULL, 1); else { if (rflag) rc += rmapping_iter(Pr, gather_map, NULL); else if (sflag) rc += xmapping_iter(Pr, gather_xmap, NULL, 0); else if (lflag) rc += Pmapping_iter(Pr, gather_map, NULL); else rc += Pmapping_iter_resolved(Pr, gather_map, NULL); } /* * Ensure mappings are consistent. */ if (Pstate(Pr) != PS_DEAD) { struct stat64 newbuf; if (fstat64(mapfd, &newbuf) != 0 || memcmp(&newbuf.st_mtim, &statbuf.st_mtim, sizeof (newbuf.st_mtim)) != 0) { if (stacks != NULL) { free(stacks); stacks = NULL; } goto again; } } /* * Display data. */ if (xflag) { (void) printf("%*s%*s%*s%*s%*s " "%sMode Mapped File\n", addr_width, "Address", size_width, "Kbytes", size_width, "RSS", size_width, "Anon", size_width, "Locked", sflag ? "Pgsz " : ""); rc += iter_xmap(sflag ? look_xmap : look_xmap_nopgsz, &t); (void) printf("%s%s %s %s %s %s\n", addr_width == 8 ? "-" : "------", bar, bar, bar, bar, bar); (void) printf("%stotal Kb", addr_width == 16 ? " " : ""); printK(t.total_size, size_width); printK(t.total_rss, size_width); printK(t.total_anon, size_width); printK(t.total_locked, size_width); (void) printf("\n"); } else if (Sflag) { (void) printf("%*s%*s%*s Mode" " Mapped File\n", addr_width, "Address", size_width, "Kbytes", size_width, "Swap"); rc += iter_xmap(look_xmap_nopgsz, &t); (void) printf("%s%s %s %s\n", addr_width == 8 ? "-" : "------", bar, bar, bar); (void) printf("%stotal Kb", addr_width == 16 ? " " : ""); printK(t.total_size, size_width); printK(t.total_swap, size_width); (void) printf("\n"); } else { if (rflag) { rc += iter_map(look_map, &t); } else if (sflag) { if (Lflag) { (void) printf("%*s %*s %4s" " %-6s %s %s\n", addr_width, "Address", size_width, "Bytes", "Pgsz", "Mode ", "Lgrp", "Mapped File"); rc += iter_xmap(look_smap, &t); } else { (void) printf("%*s %*s %4s" " %-6s %s\n", addr_width, "Address", size_width, "Bytes", "Pgsz", "Mode ", "Mapped File"); rc += iter_xmap(look_smap, &t); } } else { rc += iter_map(look_map, &t); } (void) printf(" %stotal %*luK\n", addr_width == 16 ? " " : "", size_width, t.total_size); } if (stacks != NULL) { free(stacks); stacks = NULL; } } Prelease(Pr, prr_flags); if (mapfd != -1) (void) close(mapfd); } if (use_agent_lwp) (void) proc_finistdio(); return (rc); }
int main(int argc, char **argv) { int rc = 0; int c; struct rlimit rlim; if ((command = strrchr(argv[0], '/')) != NULL) command++; else command = argv[0]; if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) < 0) return (perr("sysconf(_SC_NGROUPS_MAX)")); opterr = 0; while ((c = getopt(argc, argv, "au:g:l:G:")) != EOF) { switch (c) { case 'a': all = B_TRUE; break; case 'u': user = optarg; doset = B_TRUE; break; case 'g': group = optarg; doset = B_TRUE; break; case 'G': grplst = optarg; doset = B_TRUE; break; case 'l': login = optarg; doset = B_TRUE; break; default: usage(); /*NOTREACHED*/ } } if (login != NULL && (user != NULL || group != NULL || grplst != NULL)) usage(); if (all && doset) usage(); argc -= optind; argv += optind; if (argc == 0) usage(); if (doset) initcred(); /* * Make sure we'll have enough file descriptors to handle a target * that has many many mappings. */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rlim); (void) enable_extended_FILE_stdio(-1, -1); } while (argc-- > 0) rc += look(*argv++); return (rc > 255 ? 255 : rc); }
int main(int ac, char *av[]) { char *dir = "/"; int allflag = 0; int df_allflag = 0; int opt_cnt = 0; int maxservers = 1; /* zero allows inifinte number of threads */ int maxservers_set = 0; int logmaxservers = 0; int pid; int i; char *provider = (char *)NULL; char *df_provider = (char *)NULL; struct protob *protobp0, *protobp; NETSELDECL(proto) = NULL; NETSELDECL(df_proto) = NULL; NETSELPDECL(providerp); char *defval; boolean_t can_do_mlp; uint_t dss_npaths = 0; char **dss_pathnames = NULL; sigset_t sgset; char name[PATH_MAX], value[PATH_MAX]; int ret, bufsz; int pipe_fd = -1; MyName = *av; /* * Initializations that require more privileges than we need to run. */ (void) _create_daemon_lock(NFSD, DAEMON_UID, DAEMON_GID); svcsetprio(); can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP); if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) { (void) fprintf(stderr, "%s should be run with" " sufficient privileges\n", av[0]); exit(1); } (void) enable_extended_FILE_stdio(-1, -1); /* * Read in the values from SMF first before we check * command line options so the options override SMF values. */ bufsz = PATH_MAX; ret = nfs_smf_get_prop("max_connections", value, DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD, &bufsz); if (ret == SA_OK) { errno = 0; max_conns_allowed = strtol(value, (char **)NULL, 10); if (errno != 0) max_conns_allowed = -1; } bufsz = PATH_MAX; ret = nfs_smf_get_prop("listen_backlog", value, DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD, &bufsz); if (ret == SA_OK) { errno = 0; listen_backlog = strtol(value, (char **)NULL, 10); if (errno != 0) { listen_backlog = 32; } } bufsz = PATH_MAX; ret = nfs_smf_get_prop("protocol", value, DEFAULT_INSTANCE, SCF_TYPE_ASTRING, NFSD, &bufsz); if ((ret == SA_OK) && strlen(value) > 0) { df_proto = strdup(value); opt_cnt++; if (strncasecmp("ALL", value, 3) == 0) { free(df_proto); df_proto = NULL; df_allflag = 1; } } bufsz = PATH_MAX; ret = nfs_smf_get_prop("device", value, DEFAULT_INSTANCE, SCF_TYPE_ASTRING, NFSD, &bufsz); if ((ret == SA_OK) && strlen(value) > 0) { df_provider = strdup(value); opt_cnt++; } bufsz = PATH_MAX; ret = nfs_smf_get_prop("servers", value, DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD, &bufsz); if (ret == SA_OK) { errno = 0; maxservers = strtol(value, (char **)NULL, 10); if (errno != 0) maxservers = 1; else maxservers_set = 1; } bufsz = 4; ret = nfs_smf_get_prop("server_versmin", value, DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD, &bufsz); if (ret == SA_OK) nfs_server_vers_min = strtol(value, (char **)NULL, 10); bufsz = 4; ret = nfs_smf_get_prop("server_versmax", value, DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD, &bufsz); if (ret == SA_OK) nfs_server_vers_max = strtol(value, (char **)NULL, 10); bufsz = PATH_MAX; ret = nfs_smf_get_prop("server_delegation", value, DEFAULT_INSTANCE, SCF_TYPE_ASTRING, NFSD, &bufsz); if (ret == SA_OK) if (strncasecmp(value, "off", 3) == 0) nfs_server_delegation = FALSE; /* * Conflict options error messages. */ if (opt_cnt > 1) { (void) fprintf(stderr, "\nConflicting options, only one of " "the following options can be specified\n" "in SMF:\n" "\tprotocol=ALL\n" "\tprotocol=protocol\n" "\tdevice=devicename\n\n"); usage(); } opt_cnt = 0; while ((i = getopt(ac, av, "ac:p:s:t:l:")) != EOF) { switch (i) { case 'a': free(df_proto); df_proto = NULL; free(df_provider); df_provider = NULL; allflag = 1; opt_cnt++; break; case 'c': max_conns_allowed = atoi(optarg); break; case 'p': proto = optarg; df_allflag = 0; opt_cnt++; break; /* * DSS: NFSv4 distributed stable storage. * * This is a Contracted Project Private interface, for * the sole use of Sun Cluster HA-NFS. See PSARC/2006/313. */ case 's': if (strlen(optarg) < MAXPATHLEN) { /* first "-s" option encountered? */ if (dss_pathnames == NULL) { /* * Allocate maximum possible space * required given cmdline arg count; * "-s <path>" consumes two args. */ size_t sz = (ac / 2) * sizeof (char *); dss_pathnames = (char **)malloc(sz); if (dss_pathnames == NULL) { (void) fprintf(stderr, "%s: " "dss paths malloc failed\n", av[0]); exit(1); } (void) memset(dss_pathnames, 0, sz); } dss_pathnames[dss_npaths] = optarg; dss_npaths++; } else { (void) fprintf(stderr, "%s: -s pathname too long.\n", av[0]); } break; case 't': provider = optarg; df_allflag = 0; opt_cnt++; break; case 'l': listen_backlog = atoi(optarg); break; case '?': usage(); /* NOTREACHED */ } } allflag = df_allflag; if (proto == NULL) proto = df_proto; if (provider == NULL) provider = df_provider; /* * Conflict options error messages. */ if (opt_cnt > 1) { (void) fprintf(stderr, "\nConflicting options, only one of " "the following options can be specified\n" "on the command line:\n" "\t-a\n" "\t-p protocol\n" "\t-t transport\n\n"); usage(); } if (proto != NULL && strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0) { if (nfs_server_vers_max == NFS_V4) { if (nfs_server_vers_min == NFS_V4) { fprintf(stderr, "NFS version 4 is not supported " "with the UDP protocol. Exiting\n"); exit(3); } else { fprintf(stderr, "NFS version 4 is not supported " "with the UDP protocol.\n"); } } } /* * If there is exactly one more argument, it is the number of * servers. */ if (optind == ac - 1) { maxservers = atoi(av[optind]); maxservers_set = 1; } /* * If there are two or more arguments, then this is a usage error. */ else if (optind < ac - 1) usage(); /* * Check the ranges for min/max version specified */ else if ((nfs_server_vers_min > nfs_server_vers_max) || (nfs_server_vers_min < NFS_VERSMIN) || (nfs_server_vers_max > NFS_VERSMAX)) usage(); /* * There are no additional arguments, and we haven't set maxservers * explicitly via the config file, we use a default number of * servers. We will log this. */ else if (maxservers_set == 0) logmaxservers = 1; /* * Basic Sanity checks on options * * max_conns_allowed must be positive, except for the special * value of -1 which is used internally to mean unlimited, -1 isn't * documented but we allow it anyway. * * maxservers must be positive * listen_backlog must be positive or zero */ if (((max_conns_allowed != -1) && (max_conns_allowed <= 0)) || (listen_backlog < 0) || (maxservers <= 0)) { usage(); } /* * Set current dir to server root */ if (chdir(dir) < 0) { (void) fprintf(stderr, "%s: ", MyName); perror(dir); exit(1); } #ifndef DEBUG pipe_fd = daemonize_init(); #endif openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON); /* * establish our lock on the lock file and write our pid to it. * exit if some other process holds the lock, or if there's any * error in writing/locking the file. */ pid = _enter_daemon_lock(NFSD); switch (pid) { case 0: break; case -1: fprintf(stderr, "error locking for %s: %s\n", NFSD, strerror(errno)); exit(2); default: /* daemon was already running */ exit(0); } /* * If we've been given a list of paths to be used for distributed * stable storage, and provided we're going to run a version * that supports it, setup the DSS paths. */ if (dss_pathnames != NULL && nfs_server_vers_max >= DSS_VERSMIN) { if (dss_init(dss_npaths, dss_pathnames) != 0) { fprintf(stderr, "%s", "dss_init failed. Exiting.\n"); exit(1); } } /* * Block all signals till we spawn other * threads. */ (void) sigfillset(&sgset); (void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL); if (logmaxservers) { fprintf(stderr, "Number of servers not specified. Using default of %d.\n", maxservers); } /* * Make sure to unregister any previous versions in case the * user is reconfiguring the server in interesting ways. */ svc_unreg(NFS_PROGRAM, NFS_VERSION); svc_unreg(NFS_PROGRAM, NFS_V3); svc_unreg(NFS_PROGRAM, NFS_V4); svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V2); svc_unreg(NFS_ACL_PROGRAM, NFS_ACL_V3); /* * Set up kernel RPC thread pool for the NFS server. */ if (nfssvcpool(maxservers)) { fprintf(stderr, "Can't set up kernel NFS service: %s. " "Exiting.\n", strerror(errno)); exit(1); } /* * Set up blocked thread to do LWP creation on behalf of the kernel. */ if (svcwait(NFS_SVCPOOL_ID)) { fprintf(stderr, "Can't set up NFS pool creator: %s. Exiting.\n", strerror(errno)); exit(1); } /* * RDMA start and stop thread. * Per pool RDMA listener creation and * destructor thread. * * start rdma services and block in the kernel. * (only if proto or provider is not set to TCP or UDP) */ if ((proto == NULL) && (provider == NULL)) { if (svcrdma(NFS_SVCPOOL_ID, nfs_server_vers_min, nfs_server_vers_max, nfs_server_delegation)) { fprintf(stderr, "Can't set up RDMA creator thread : %s\n", strerror(errno)); } } /* * Now open up for signal delivery */ (void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL); sigset(SIGTERM, sigflush); sigset(SIGUSR1, quiesce); /* * Build a protocol block list for registration. */ protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob)); protobp->serv = "NFS"; protobp->versmin = nfs_server_vers_min; protobp->versmax = nfs_server_vers_max; protobp->program = NFS_PROGRAM; protobp->next = (struct protob *)malloc(sizeof (struct protob)); protobp = protobp->next; protobp->serv = "NFS_ACL"; /* not used */ protobp->versmin = nfs_server_vers_min; /* XXX - this needs work to get the version just right */ protobp->versmax = (nfs_server_vers_max > NFS_ACL_V3) ? NFS_ACL_V3 : nfs_server_vers_max; protobp->program = NFS_ACL_PROGRAM; protobp->next = (struct protob *)NULL; if (allflag) { if (do_all(protobp0, nfssvc) == -1) { fprintf(stderr, "setnetconfig failed : %s\n", strerror(errno)); exit(1); } } else if (proto) { /* there's more than one match for the same protocol */ struct netconfig *nconf; NCONF_HANDLE *nc; bool_t protoFound = FALSE; if ((nc = setnetconfig()) == (NCONF_HANDLE *) NULL) { fprintf(stderr, "setnetconfig failed : %s\n", strerror(errno)); goto done; } while (nconf = getnetconfig(nc)) { if (strcmp(nconf->nc_proto, proto) == 0) { protoFound = TRUE; do_one(nconf->nc_device, NULL, protobp0, nfssvc); } } (void) endnetconfig(nc); if (protoFound == FALSE) { fprintf(stderr, "couldn't find netconfig entry for protocol %s\n", proto); } } else if (provider) do_one(provider, proto, protobp0, nfssvc); else { for (providerp = defaultproviders; *providerp != NULL; providerp++) { provider = *providerp; do_one(provider, NULL, protobp0, nfssvc); } } done: free(protobp); free(protobp0); if (num_fds == 0) { fprintf(stderr, "Could not start NFS service for any protocol." " Exiting.\n"); exit(1); } end_listen_fds = num_fds; /* * nfsd is up and running as far as we are concerned. */ daemonize_fini(pipe_fd); /* * Get rid of unneeded privileges. */ __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); /* * Poll for non-data control events on the transport descriptors. */ poll_for_action(); /* * If we get here, something failed in poll_for_action(). */ return (1); }
int main(int argc, char **argv) { boolean_t is_daemon = B_TRUE; boolean_t is_verbose = B_FALSE; int ipc_fd; int c; struct rlimit rl; /* * -l is ignored for compatibility with old agent. */ while ((c = getopt(argc, argv, "vd:l:fa")) != EOF) { switch (c) { case 'a': do_adopt = B_TRUE; grandparent = getpid(); break; case 'd': debug_level = strtoul(optarg, NULL, 0); break; case 'f': is_daemon = B_FALSE; break; case 'v': is_verbose = B_TRUE; break; case '?': (void) fprintf(stderr, "usage: %s [-a] [-d n] [-f] [-v]" "\n", argv[0]); return (EXIT_FAILURE); default: break; } } (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if (geteuid() != 0) { dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level); dhcpmsg(MSG_ERROR, "must be super-user"); dhcpmsg_fini(); return (EXIT_FAILURE); } if (is_daemon && daemonize() == 0) { dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level); dhcpmsg(MSG_ERR, "cannot become daemon, exiting"); dhcpmsg_fini(); return (EXIT_FAILURE); } dhcpmsg_init(argv[0], is_daemon, is_verbose, debug_level); (void) atexit(dhcpmsg_fini); tq = iu_tq_create(); eh = iu_eh_create(); if (eh == NULL || tq == NULL) { errno = ENOMEM; dhcpmsg(MSG_ERR, "cannot create timer queue or event handler"); return (EXIT_FAILURE); } /* * ignore most signals that could be reasonably generated. */ (void) signal(SIGTERM, graceful_shutdown); (void) signal(SIGQUIT, graceful_shutdown); (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGUSR1, SIG_IGN); (void) signal(SIGUSR2, SIG_IGN); (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGCHLD, SIG_IGN); /* * upon SIGTHAW we need to refresh any non-infinite leases. */ (void) iu_eh_register_signal(eh, SIGTHAW, refresh_ifslist, NULL); class_id = get_class_id(); if (class_id != NULL) class_id_len = strlen(class_id); else dhcpmsg(MSG_WARNING, "get_class_id failed, continuing " "with no vendor class id"); /* * the inactivity timer is enabled any time there are no * interfaces under DHCP control. if DHCP_INACTIVITY_WAIT * seconds transpire without an interface under DHCP control, * the agent shuts down. */ inactivity_id = iu_schedule_timer(tq, DHCP_INACTIVITY_WAIT, inactivity_shutdown, NULL); /* * max out the number available descriptors, just in case.. */ rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) dhcpmsg(MSG_ERR, "setrlimit failed"); (void) enable_extended_FILE_stdio(-1, -1); /* * create the ipc channel that the agent will listen for * requests on, and register it with the event handler so that * `accept_event' will be called back. */ switch (dhcp_ipc_init(&ipc_fd)) { case 0: break; case DHCP_IPC_E_BIND: dhcpmsg(MSG_ERROR, "dhcp_ipc_init: cannot bind to port " "%i (agent already running?)", IPPORT_DHCPAGENT); return (EXIT_FAILURE); default: dhcpmsg(MSG_ERROR, "dhcp_ipc_init failed"); return (EXIT_FAILURE); } if (iu_register_event(eh, ipc_fd, POLLIN, accept_event, 0) == -1) { dhcpmsg(MSG_ERR, "cannot register ipc fd for messages"); return (EXIT_FAILURE); } /* * Create the global routing socket. This is used for monitoring * interface transitions, so that we learn about the kernel's Duplicate * Address Detection status, and for inserting and removing default * routes as learned from DHCP servers. */ rtsock_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET); if (rtsock_fd == -1) { dhcpmsg(MSG_ERR, "cannot open routing socket"); return (EXIT_FAILURE); } if (iu_register_event(eh, rtsock_fd, POLLIN, rtsock_event, 0) == -1) { dhcpmsg(MSG_ERR, "cannot register routing socket for messages"); return (EXIT_FAILURE); } /* * if the -a (adopt) option was specified, try to adopt the * kernel-managed interface before we start. */ if (do_adopt && dhcp_adopt() == 0) return (EXIT_FAILURE); /* * enter the main event loop; this is where all the real work * takes place (through registering events and scheduling timers). * this function only returns when the agent is shutting down. */ switch (iu_handle_events(eh, tq)) { case -1: dhcpmsg(MSG_WARNING, "iu_handle_events exited abnormally"); break; case DHCP_REASON_INACTIVITY: dhcpmsg(MSG_INFO, "no interfaces to manage, shutting down..."); break; case DHCP_REASON_TERMINATE: dhcpmsg(MSG_INFO, "received SIGTERM, shutting down..."); break; case DHCP_REASON_SIGNAL: dhcpmsg(MSG_WARNING, "received unexpected signal, shutting " "down..."); break; } (void) iu_eh_unregister_signal(eh, SIGTHAW, NULL); iu_eh_destroy(eh); iu_tq_destroy(tq); return (EXIT_SUCCESS); }
int parmount(char **mntlist, int count, char *fstype) { int maxfd = OPEN_MAX; struct rlimit rl; vfsent_t **vl, *vp; /* * Process scaling. After running a series * of tests based on the number of simultaneous processes and * processors available, optimum performance was achieved near or * at (PROCN * 2). */ if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1) maxrun = 4; else maxrun = maxrun * 2 + 1; if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_NOFILE, &rl) == 0) maxfd = (int)rl.rlim_cur; } (void) enable_extended_FILE_stdio(-1, -1); /* * The parent needs to maintain 3 of its own fd's, plus 2 for * each child (the stdout and stderr pipes). */ maxfd = (maxfd / 2) - 6; /* 6 takes care of temporary */ /* periods of open fds */ if (maxfd < maxrun) maxrun = maxfd; if (maxrun < 4) maxrun = 4; /* sanity check */ if (count == 0) mntlist = NULL; /* used as a flag later */ else fstype = NULL; /* mount points supplied: */ /* ignore fstype */ /* * Read the whole vfstab into a linked list for quick processing. * On average, this is the most efficient way to collect and * manipulate the vfstab data. */ vfsll = getvfsall(fstype, mntlist == NULL); /* * Make an array out of the vfs linked list for sorting purposes. */ if (vfsll == NULL || (vfsarray = make_vfsarray(mntlist, count)) == NULL) { if (mntlist == NULL) /* not an error - just none found */ return (0); fprintf(stderr, gettext("%s: No valid entries found in %s\n"), myname, vfstab); return (1); } /* * Sort the entries based on their resolved path names * * If an lofs is encountered, then the original order of the vfstab * file needs to be maintained until we are done mounting lofs's. */ if (!lofscnt) qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *), mlevelcmp); /* * Shrink the vfsll linked list down to the new list. This will * speed up the pid search in cleanupkid() later. */ vfsll = vfsarray[0]; for (vl = vfsarray; vp = *vl; ) vp->next = *++vl; /* * Try to handle interrupts in a reasonable way. */ sigset(SIGHUP, cleanup); sigset(SIGQUIT, cleanup); sigset(SIGINT, cleanup); do_mounts(); /* do the mounts */ if (failcnt > 0 && failcnt == lofsfail) return (ALL_LOFS_FAILURES); return (exitcode); }
int main(int argc, char **argv) { struct ps_prochandle *P; int gerr; char *prefix = NULL; int opt; int opt_p = 0, opt_g = 0, opt_c = 0; int oflags = 0; int i; char fname[MAXPATHLEN]; char path[MAXPATHLEN]; int err = 0; core_content_t content = CC_CONTENT_DEFAULT; struct rlimit rlim; if ((pname = strrchr(argv[0], '/')) == NULL) pname = argv[0]; else argv[0] = ++pname; /* for getopt() */ while ((opt = getopt(argc, argv, "o:Fgpc:")) != EOF) { switch (opt) { case 'o': prefix = optarg; break; case 'c': if (proc_str2content(optarg, &content) != 0) { (void) fprintf(stderr, "%s: invalid " "content string '%s'\n", pname, optarg); goto usage; } opt_c = 1; break; case 'F': oflags |= PGRAB_FORCE; break; case 'p': opt_p = 1; break; case 'g': opt_g = 1; break; default: goto usage; } } if ((opt_p | opt_g) == 0) { if (prefix == NULL) prefix = "core"; } else { int options; if ((options = core_get_options()) == -1) { perror("core_get_options()"); return (1); } if (opt_p && !(options & CC_PROCESS_PATH)) { (void) fprintf(stderr, "%s: per-process core dumps " "are disabled (ignoring -p)\n", pname); opt_p = 0; } if (opt_g && !(options & CC_GLOBAL_PATH)) { (void) fprintf(stderr, "%s: global core dumps " "are disabled (ignoring -g)\n", pname); opt_g = 0; } if ((opt_p | opt_g) == 0 && prefix == NULL) return (1); } argc -= optind; argv += optind; if (argc == 0) goto usage; /* * Make sure we'll have enough file descriptors to handle a target * that has many many mappings. */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rlim); (void) enable_extended_FILE_stdio(-1, -1); } for (i = 0; i < argc; i++) { P = proc_arg_grab(argv[i], PR_ARG_PIDS, oflags, &gerr); if (P == NULL) { (void) fprintf(stderr, "%s: cannot grab %s: %s\n", pname, argv[i], Pgrab_error(gerr)); err++; continue; } if (prefix != NULL) { (void) snprintf(path, sizeof (path), "%s.%%p", prefix); convert_path(path, fname, sizeof (fname), P); gcore(P, fname, content, &err); } if (opt_p) { pid_t pid = Pstatus(P)->pr_pid; (void) core_get_process_path(path, sizeof (path), pid); convert_path(path, fname, sizeof (fname), P); if (!opt_c) (void) core_get_process_content(&content, pid); gcore(P, fname, content, &err); } if (opt_g) { /* * Global core files are always just readable and * writable by their owner so we temporarily change * the umask. */ mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO); (void) core_get_global_path(path, sizeof (path)); convert_path(path, fname, sizeof (fname), P); if (!opt_c) (void) core_get_global_content(&content); gcore(P, fname, content, &err); (void) umask(oldmode); } Prelease(P, 0); } return (err != 0); usage: (void) fprintf(stderr, "usage: %s " "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname); return (2); }
int main(int argc, char *argv[]) { int sflag = 0, s1flag = 0, s2flag = 0, nflag = 0, dflag = 0, eflag = 0; char *options, *value; extern char *optarg; extern int optind; int c, d; struct rlimit rl; int mode = RPC_SVC_MT_AUTO; int maxrecsz = RPC_MAXDATASIZE; void detachfromtty(void); int setmodulus(); int pk_nodefaultkeys(); int svc_create_local_service(); char domainname[MAXNETNAMELEN + 1]; /* * Set our allowed number of file descriptors to the max * of what the system will allow, limited by FD_SETSIZE. */ if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { rlim_t limit; if ((limit = rl.rlim_max) > FD_SETSIZE) limit = FD_SETSIZE; rl.rlim_cur = limit; (void) setrlimit(RLIMIT_NOFILE, &rl); (void) enable_extended_FILE_stdio(-1, -1); } __key_encryptsession_pk_LOCAL = &__key_encrypt_pk_2_svc; __key_decryptsession_pk_LOCAL = &__key_decrypt_pk_2_svc; __key_gendes_LOCAL = &__key_gen_1_svc; /* * Pre-option initialisation */ (void) umask(066); /* paranoia */ if (geteuid() != 0) { (void) fprintf(stderr, "%s must be run as root\n", argv[0]); exit(1); } setmodulus(HEXMODULUS); openlog("keyserv", LOG_PID, LOG_DAEMON); /* * keyserv will not work with a null domainname. */ if (getdomainname(domainname, MAXNETNAMELEN+1) || (domainname[0] == '\0')) { syslog(LOG_ERR, "could not get a valid domainname.\n"); exit(SMF_EXIT_ERR_CONFIG); } /* * Initialise security mechanisms */ cache_size = NULL; cache_options = NULL; if (init_mechs() == -1) { disk_caching = 0; } defaults(); while ((c = getopt(argc, argv, "ndDet:cs:")) != -1) switch (c) { case 'n': nflag++; break; case 'd': dflag++; use_nobody_keys = FALSE; break; case 'e': eflag++; use_nobody_keys = TRUE; break; case 'D': debugging = 1; break; case 't': nthreads = atoi(optarg); break; case 'c': disk_caching = 0; break; case 's': if (!disk_caching) { fprintf(stderr, "missing configuration file"); fprintf(stderr, " or -c option specified\n"); usage(); } sflag++; /* * Which version of [-s] do we have...? */ if (strchr((const char *) optarg, '=') == NULL) { /* * -s <size> */ if (s1flag) { fprintf(stderr, "duplicate" " [-s <size>]\n"); usage(); } s1flag++; default_cache = get_cache_size(optarg); break; } /* * -s <mechtype>=<size>[,...] */ s2flag++; options = optarg; while (*options != '\0') { d = getsubopt(&options, cache_options, &value); if (d == -1) { /* Ignore unknown mechtype */ continue; } if (value == NULL) { fprintf(stderr, "missing cache size for " "mechtype %s\n", cache_options[d]); usage(); } cache_size[d] = get_cache_size(value); } break; default: usage(); break; } if (dflag && eflag) { (void) fprintf(stderr, "specify only one of -d and -e\n"); usage(); } if (use_nobody_keys == FALSE) { pk_nodefaultkeys(); } if (optind != argc) { usage(); } if (!disk_caching && sflag) { fprintf(stderr, "missing configuration file"); fprintf(stderr, " or -c option specified\n"); usage(); } if (debugging) { if (disk_caching) { char **cpp = cache_options; int *ip = cache_size; (void) fprintf(stderr, "default disk cache size: "); if (default_cache < 0) { (void) fprintf(stderr, "%d entries\n", abs(default_cache)); } else { (void) fprintf(stderr, "%dMB\n", default_cache); } (void) fprintf(stderr, "supported mechanisms:\n"); (void) fprintf(stderr, "\talias\t\tdisk cache size\n"); (void) fprintf(stderr, "\t=====\t\t===============\n"); while (*cpp != NULL) { (void) fprintf(stderr, "\t%s\t\t", *cpp++); if (*ip < 0) { (void) fprintf(stderr, "%d entries\n", abs(*ip)); } else { (void) fprintf(stderr, "%dMB\n", *ip); } ip++; } } else { (void) fprintf(stderr, "common key disk caching disabled\n"); } } /* * Post-option initialisation */ if (disk_caching) { int i; for (i = 0; mechs[i]; i++) { if ((AUTH_DES_COMPAT_CHK(mechs[i])) || (mechs[i]->keylen < 0) || (mechs[i]->algtype < 0)) continue; create_cache_file(mechs[i]->keylen, mechs[i]->algtype, cache_size[i] ? cache_size[i] : default_cache); } } getrootkey(&masterkey, nflag); /* * Set MT mode */ if (nthreads > 0) { (void) rpc_control(RPC_SVC_MTMODE_SET, &mode); (void) rpc_control(RPC_SVC_THRMAX_SET, &nthreads); } /* * Enable non-blocking mode and maximum record size checks for * connection oriented transports. */ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { syslog(LOG_INFO, "unable to set max RPC record size"); } if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS, "netpath", "keyserv") == 0) { syslog(LOG_ERR, "%s: unable to create service for version %d\n", argv[0], KEY_VERS); exit(1); } if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS2, "netpath", "keyserv") == 0) { syslog(LOG_ERR, "%s: unable to create service for version %d\n", argv[0], KEY_VERS2); exit(1); } if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS3, "netpath", "keyserv") == 0) { syslog(LOG_ERR, "%s: unable to create service for version %d\n", argv[0], KEY_VERS3); exit(1); } if (!debugging) { detachfromtty(); } if (svc_create(keyprogram, KEY_PROG, KEY_VERS, "door") == 0) { syslog(LOG_ERR, "%s: unable to create service over doors for version %d\n", argv[0], KEY_VERS); exit(1); } if (svc_create(keyprogram, KEY_PROG, KEY_VERS2, "door") == 0) { syslog(LOG_ERR, "%s: unable to create service over doors for version %d\n", argv[0], KEY_VERS2); exit(1); } if (svc_create(keyprogram, KEY_PROG, KEY_VERS3, "door") == 0) { syslog(LOG_ERR, "%s: unable to create service over doors for version %d\n", argv[0], KEY_VERS3); exit(1); } svc_run(); abort(); /* NOTREACHED */ return (0); }
int main(int argc, char **argv) { dsvcd_datastore_t **ds_table; dsvc_datastore_t dd; dsvc_synchtype_t synchtype; char **modules; unsigned int i, j; int debug_level = 0; boolean_t is_daemon = B_TRUE; boolean_t is_verbose = B_FALSE; int sig, nmodules, nsynchmods, c; sigset_t sigset; char signame[SIG2STR_MAX]; char *progname; void *stackbase; unsigned int stacksize = 16 * 1024; struct rlimit rl; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* * Mask all signals except SIGABRT; doing this here ensures that * all threads created through door_create() have them masked too. */ (void) sigfillset(&sigset); (void) sigdelset(&sigset, SIGABRT); (void) thr_sigsetmask(SIG_BLOCK, &sigset, NULL); /* * Figure out our program name; just keep the final piece so that * our dhcpmsg() messages don't get too long. */ progname = strrchr(argv[0], '/'); if (progname != NULL) progname++; else progname = argv[0]; /* * Set the door thread creation procedure so that all of our * threads are created with thread stacks with backing store. */ (void) door_server_create(doorserv_create); while ((c = getopt(argc, argv, "d:fv")) != EOF) { switch (c) { case 'd': debug_level = atoi(optarg); break; case 'f': is_daemon = B_FALSE; break; case 'v': is_verbose = B_TRUE; break; case '?': (void) fprintf(stderr, gettext("usage: %s [-dn] [-f] [-v]\n"), progname); return (EXIT_FAILURE); default: break; } } if (geteuid() != 0) { dhcpmsg_init(progname, B_FALSE, is_verbose, debug_level); dhcpmsg(MSG_ERROR, "must be super-user"); dhcpmsg_fini(); return (EXIT_FAILURE); } if (is_daemon && daemonize() == 0) { dhcpmsg_init(progname, B_FALSE, is_verbose, debug_level); dhcpmsg(MSG_ERROR, "cannot become daemon, exiting"); dhcpmsg_fini(); return (EXIT_FAILURE); } dhcpmsg_init(progname, is_daemon, is_verbose, debug_level); (void) atexit(dhcpmsg_fini); /* * Max out the number available descriptors since we need to * allocate two per held lock. */ rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) dhcpmsg(MSG_ERR, "setrlimit failed"); (void) enable_extended_FILE_stdio(-1, -1); if (enumerate_dd(&modules, &nmodules) != DSVC_SUCCESS) { dhcpmsg(MSG_ERROR, "cannot enumerate public modules, exiting"); return (EXIT_FAILURE); } /* * NOTE: this code assumes that a module that needs dsvclockd will * always need it (even as the container version is ramped). If * this becomes bogus in a future release, we'll have to make this * logic more sophisticated. */ nsynchmods = nmodules; for (i = 0; i < nmodules; i++) { dd.d_resource = modules[i]; dd.d_conver = DSVC_CUR_CONVER; dd.d_location = ""; if (module_synchtype(&dd, &synchtype) != DSVC_SUCCESS) { dhcpmsg(MSG_WARNING, "cannot determine synchronization " "type for `%s', skipping", modules[i]); free(modules[i]); modules[i] = NULL; nsynchmods--; continue; } if ((synchtype & DSVC_SYNCH_STRATMASK) != DSVC_SYNCH_DSVCD) { free(modules[i]); modules[i] = NULL; nsynchmods--; } } if (nsynchmods == 0) { dhcpmsg(MSG_INFO, "no public modules need synchronization"); return (EXIT_SUCCESS); } /* * Allocate the datastore table; include one extra entry so that * the table is NULL-terminated. */ ds_table = calloc(nsynchmods + 1, sizeof (dsvcd_datastore_t *)); if (ds_table == NULL) { dhcpmsg(MSG_ERR, "cannot allocate datastore table, exiting"); return (EXIT_FAILURE); } ds_table[nsynchmods] = NULL; /* * Create the datastores (which implicitly creates the doors). * then sit around and wait for requests to come in on the doors. */ for (i = 0, j = 0; i < nmodules; i++) { if (modules[i] != NULL) { ds_table[j] = ds_create(modules[i], svc_lock); if (ds_table[j] == NULL) { while (j-- > 0) ds_destroy(ds_table[j]); return (EXIT_FAILURE); } free(modules[i]); j++; } } free(modules); stackbase = stack_create(&stacksize); if (stackbase == NULL) dhcpmsg(MSG_ERR, "cannot create reaper stack; containers " "will not be reaped"); else { errno = thr_create(stackbase, stacksize, reaper, ds_table, THR_DAEMON, NULL); if (errno != 0) { dhcpmsg(MSG_ERR, "cannot create reaper thread; " "containers will not be reaped"); stack_destroy(stackbase, stacksize); } } /* * Synchronously wait for a QUIT, TERM, or INT, then shutdown. */ (void) sigemptyset(&sigset); (void) sigaddset(&sigset, SIGQUIT); (void) sigaddset(&sigset, SIGTERM); (void) sigaddset(&sigset, SIGINT); (void) sigwait(&sigset, &sig); if (sig != SIGTERM && sig != SIGQUIT && sig != SIGINT) dhcpmsg(MSG_WARNING, "received unexpected signal"); if (sig2str(sig, signame) == -1) (void) strlcpy(signame, "???", sizeof (signame)); dhcpmsg(MSG_INFO, "shutting down via SIG%s", signame); for (i = 0; i < nsynchmods; i++) ds_destroy(ds_table[i]); return (EXIT_SUCCESS); }
int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts) { int max_threads, max_queue, readtimeout, ret = 0; unsigned int options = 0; char timestr[32]; #ifndef _WIN32 struct sigaction sigact; sigset_t sigset; struct rlimit rlim; #endif mode_t old_umask; const struct optstruct *opt; char buff[BUFFSIZE + 1]; pid_t mainpid; int idletimeout; unsigned long long val; size_t i, j, rr_last = 0; pthread_t accept_th; pthread_mutex_t fds_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t recvfds_mutex = PTHREAD_MUTEX_INITIALIZER; struct acceptdata acceptdata = ACCEPTDATA_INIT(&fds_mutex, &recvfds_mutex); struct fd_data *fds = &acceptdata.recv_fds; time_t start_time, current_time; unsigned int selfchk; threadpool_t *thr_pool; #if defined(FANOTIFY) || defined(CLAMAUTH) pthread_t fan_pid; pthread_attr_t fan_attr; struct thrarg *tharg = NULL; /* shut up gcc */ #endif #ifndef _WIN32 memset(&sigact, 0, sizeof(struct sigaction)); #endif /* set up limits */ if((opt = optget(opts, "MaxScanSize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, opt->numarg))) { logg("!cl_engine_set_num(CL_ENGINE_MAX_SCANSIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_SCANSIZE, NULL); if(val) logg("Limits: Global size limit set to %llu bytes.\n", val); else logg("^Limits: Global size limit protection disabled.\n"); if((opt = optget(opts, "MaxFileSize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, opt->numarg))) { logg("!cl_engine_set_num(CL_ENGINE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_FILESIZE, NULL); if(val) logg("Limits: File size limit set to %llu bytes.\n", val); else logg("^Limits: File size limit protection disabled.\n"); #ifndef _WIN32 if(getrlimit(RLIMIT_FSIZE, &rlim) == 0) { if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_FILESIZE, NULL)) logg("^System limit for file size is lower than engine->maxfilesize\n"); if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_SCANSIZE, NULL)) logg("^System limit for file size is lower than engine->maxscansize\n"); } else { logg("^Cannot obtain resource limits for file size\n"); } #endif if((opt = optget(opts, "MaxRecursion"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_RECURSION, opt->numarg))) { logg("!cl_engine_set_num(CL_ENGINE_MAX_RECURSION) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_RECURSION, NULL); if(val) logg("Limits: Recursion level limit set to %u.\n", (unsigned int) val); else logg("^Limits: Recursion level limit protection disabled.\n"); if((opt = optget(opts, "MaxFiles"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILES, opt->numarg))) { logg("!cl_engine_set_num(CL_ENGINE_MAX_FILES) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_FILES, NULL); if(val) logg("Limits: Files limit set to %u.\n", (unsigned int) val); else logg("^Limits: Files limit protection disabled.\n"); #ifndef _WIN32 if (getrlimit(RLIMIT_CORE, &rlim) == 0) { logg("*Limits: Core-dump limit is %lu.\n", (unsigned long)rlim.rlim_cur); } #endif /* Engine max sizes */ if((opt = optget(opts, "MaxEmbeddedPE"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_EMBEDDEDPE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_EMBEDDEDPE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_EMBEDDEDPE, NULL); logg("Limits: MaxEmbeddedPE limit set to %llu bytes.\n", val); if((opt = optget(opts, "MaxHTMLNormalize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_HTMLNORMALIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_HTMLNORMALIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_HTMLNORMALIZE, NULL); logg("Limits: MaxHTMLNormalize limit set to %llu bytes.\n", val); if((opt = optget(opts, "MaxHTMLNoTags"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_HTMLNOTAGS, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_HTMLNOTAGS) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_HTMLNOTAGS, NULL); logg("Limits: MaxHTMLNoTags limit set to %llu bytes.\n", val); if((opt = optget(opts, "MaxScriptNormalize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCRIPTNORMALIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_SCRIPTNORMALIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_SCRIPTNORMALIZE, NULL); logg("Limits: MaxScriptNormalize limit set to %llu bytes.\n", val); if((opt = optget(opts, "MaxZipTypeRcg"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_ZIPTYPERCG, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_ZIPTYPERCG) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_ZIPTYPERCG, NULL); logg("Limits: MaxZipTypeRcg limit set to %llu bytes.\n", val); if((opt = optget(opts, "MaxPartitions"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_PARTITIONS, opt->numarg))) { logg("!cli_engine_set_num(MaxPartitions) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_PARTITIONS, NULL); logg("Limits: MaxPartitions limit set to %llu.\n", val); if((opt = optget(opts, "MaxIconsPE"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_ICONSPE, opt->numarg))) { logg("!cli_engine_set_num(MaxIconsPE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MAX_ICONSPE, NULL); logg("Limits: MaxIconsPE limit set to %llu.\n", val); if((opt = optget(opts, "PCREMatchLimit"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_MATCH_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(PCREMatchLimit) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_PCRE_MATCH_LIMIT, NULL); logg("Limits: PCREMatchLimit limit set to %llu.\n", val); if((opt = optget(opts, "PCRERecMatchLimit"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_RECMATCH_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(PCRERecMatchLimit) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_PCRE_RECMATCH_LIMIT, NULL); logg("Limits: PCRERecMatchLimit limit set to %llu.\n", val); if((opt = optget(opts, "PCREMaxFileSize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_MAX_FILESIZE, opt->numarg))) { logg("!cli_engine_set_num(PCREMaxFileSize) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_PCRE_MAX_FILESIZE, NULL); logg("Limits: PCREMaxFileSize limit set to %llu.\n", val); if(optget(opts, "ScanArchive")->enabled) { logg("Archive support enabled.\n"); options |= CL_SCAN_ARCHIVE; if(optget(opts, "ArchiveBlockEncrypted")->enabled) { logg("Archive: Blocking encrypted archives.\n"); options |= CL_SCAN_BLOCKENCRYPTED; } } else { logg("Archive support disabled.\n"); } if(optget(opts, "AlgorithmicDetection")->enabled) { logg("Algorithmic detection enabled.\n"); options |= CL_SCAN_ALGORITHMIC; } else { logg("Algorithmic detection disabled.\n"); } if(optget(opts, "ScanPE")->enabled) { logg("Portable Executable support enabled.\n"); options |= CL_SCAN_PE; } else { logg("Portable Executable support disabled.\n"); } if(optget(opts, "ScanELF")->enabled) { logg("ELF support enabled.\n"); options |= CL_SCAN_ELF; } else { logg("ELF support disabled.\n"); } if(optget(opts, "ScanPE")->enabled || optget(opts, "ScanELF")->enabled) { if(optget(opts, "DetectBrokenExecutables")->enabled) { logg("Detection of broken executables enabled.\n"); options |= CL_SCAN_BLOCKBROKEN; } } if(optget(opts, "ScanMail")->enabled) { logg("Mail files support enabled.\n"); options |= CL_SCAN_MAIL; if(optget(opts, "ScanPartialMessages")->enabled) { logg("Mail: RFC1341 handling enabled.\n"); options |= CL_SCAN_PARTIAL_MESSAGE; } } else { logg("Mail files support disabled.\n"); } if(optget(opts, "ScanOLE2")->enabled) { logg("OLE2 support enabled.\n"); options |= CL_SCAN_OLE2; if(optget(opts, "OLE2BlockMacros")->enabled) { logg("OLE2: Blocking all VBA macros.\n"); options |= CL_SCAN_BLOCKMACROS; } } else { logg("OLE2 support disabled.\n"); } if(optget(opts, "ScanPDF")->enabled) { logg("PDF support enabled.\n"); options |= CL_SCAN_PDF; } else { logg("PDF support disabled.\n"); } if(optget(opts, "ScanSWF")->enabled) { logg("SWF support enabled.\n"); options |= CL_SCAN_SWF; } else { logg("SWF support disabled.\n"); } if(optget(opts, "ScanHTML")->enabled) { logg("HTML support enabled.\n"); options |= CL_SCAN_HTML; } else { logg("HTML support disabled.\n"); } if(optget(opts,"PhishingScanURLs")->enabled) { if(optget(opts,"PhishingAlwaysBlockCloak")->enabled) { options |= CL_SCAN_PHISHING_BLOCKCLOAK; logg("Phishing: Always checking for cloaked urls\n"); } if(optget(opts,"PhishingAlwaysBlockSSLMismatch")->enabled) { options |= CL_SCAN_PHISHING_BLOCKSSL; logg("Phishing: Always checking for ssl mismatches\n"); } } if(optget(opts,"PartitionIntersection")->enabled) { options |= CL_SCAN_PARTITION_INTXN; logg("Raw DMG: Always checking for partitons intersections\n"); } if(optget(opts,"HeuristicScanPrecedence")->enabled) { options |= CL_SCAN_HEURISTIC_PRECEDENCE; logg("Heuristic: precedence enabled\n"); } if(optget(opts, "StructuredDataDetection")->enabled) { options |= CL_SCAN_STRUCTURED; if((opt = optget(opts, "StructuredMinCreditCardCount"))->enabled) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_CC_COUNT, opt->numarg))) { logg("!cl_engine_set_num(CL_ENGINE_MIN_CC_COUNT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MIN_CC_COUNT, NULL); logg("Structured: Minimum Credit Card Number Count set to %u\n", (unsigned int) val); if((opt = optget(opts, "StructuredMinSSNCount"))->enabled) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_SSN_COUNT, opt->numarg))) { logg("!cl_engine_set_num(CL_ENGINE_MIN_SSN_COUNT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 1; } } val = cl_engine_get_num(engine, CL_ENGINE_MIN_SSN_COUNT, NULL); logg("Structured: Minimum Social Security Number Count set to %u\n", (unsigned int) val); if(optget(opts, "StructuredSSNFormatNormal")->enabled) options |= CL_SCAN_STRUCTURED_SSN_NORMAL; if(optget(opts, "StructuredSSNFormatStripped")->enabled) options |= CL_SCAN_STRUCTURED_SSN_STRIPPED; } #ifdef HAVE__INTERNAL__SHA_COLLECT if(optget(opts, "DevCollectHashes")->enabled) options |= CL_SCAN_INTERNAL_COLLECT_SHA; #endif selfchk = optget(opts, "SelfCheck")->numarg; if(!selfchk) { logg("Self checking disabled.\n"); } else { logg("Self checking every %u seconds.\n", selfchk); } /* save the PID */ mainpid = getpid(); if((opt = optget(opts, "PidFile"))->enabled) { FILE *fd; old_umask = umask(0002); if((fd = fopen(opt->strarg, "w")) == NULL) { logg("!Can't save PID in file %s\n", opt->strarg); } else { if (fprintf(fd, "%u\n", (unsigned int) mainpid)<0) { logg("!Can't save PID in file %s\n", opt->strarg); } fclose(fd); } umask(old_umask); } logg("*Listening daemon: PID: %u\n", (unsigned int) mainpid); max_threads = optget(opts, "MaxThreads")->numarg; max_queue = optget(opts, "MaxQueue")->numarg; acceptdata.commandtimeout = optget(opts, "CommandReadTimeout")->numarg; readtimeout = optget(opts, "ReadTimeout")->numarg; #if !defined(_WIN32) && defined(RLIMIT_NOFILE) if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { /* don't warn if default value is too high, silently fix it */ unsigned maxrec; int max_max_queue; unsigned warn = optget(opts, "MaxQueue")->active; const unsigned clamdfiles = 6; /* Condition to not run out of file descriptors: * MaxThreads * MaxRecursion + (MaxQueue - MaxThreads) + CLAMDFILES < RLIMIT_NOFILE * CLAMDFILES is 6: 3 standard FD + logfile + 2 FD for reloading the DB * */ #ifdef C_SOLARIS #ifdef HAVE_ENABLE_EXTENDED_FILE_STDIO if (enable_extended_FILE_stdio(-1, -1) == -1) { logg("^Unable to set extended FILE stdio, clamd will be limited to max 256 open files\n"); rlim.rlim_cur = rlim.rlim_cur > 255 ? 255 : rlim.rlim_cur; } #elif !defined(_LP64) if (rlim.rlim_cur > 255) { rlim.rlim_cur = 255; logg("^Solaris only supports 256 open files for 32-bit processes, you need at least Solaris 10u4, or compile as 64-bit to support more!\n"); } #endif #endif opt = optget(opts,"MaxRecursion"); maxrec = opt->numarg; max_max_queue = rlim.rlim_cur - maxrec * max_threads - clamdfiles + max_threads; if (max_queue < max_threads) { max_queue = max_threads; if (warn) logg("^MaxQueue value too low, increasing to: %d\n", max_queue); } if (max_max_queue < max_threads) { logg("^MaxThreads * MaxRecursion is too high: %d, open file descriptor limit is: %lu\n", maxrec*max_threads, (unsigned long)rlim.rlim_cur); max_max_queue = max_threads; } if (max_queue > max_max_queue) { max_queue = max_max_queue; if (warn) logg("^MaxQueue value too high, lowering to: %d\n", max_queue); } else if (max_queue < 2*max_threads && max_queue < max_max_queue) { max_queue = 2*max_threads; if (max_queue > max_max_queue) max_queue = max_max_queue; /* always warn here */ logg("^MaxQueue is lower than twice MaxThreads, increasing to: %d\n", max_queue); } } #endif logg("*MaxQueue set to: %d\n", max_queue); acceptdata.max_queue = max_queue; if(optget(opts, "ScanOnAccess")->enabled) #if defined(FANOTIFY) || defined(CLAMAUTH) { do { if(pthread_attr_init(&fan_attr)) break; pthread_attr_setdetachstate(&fan_attr, PTHREAD_CREATE_JOINABLE); if(!(tharg = (struct thrarg *) malloc(sizeof(struct thrarg)))) break; tharg->opts = opts; tharg->engine = engine; tharg->options = options; if(!pthread_create(&fan_pid, &fan_attr, onas_fan_th, tharg)) break; free(tharg); tharg=NULL; } while(0); if (!tharg) logg("!Unable to start on-access scan\n"); } #else logg("!On-access scan is not available\n"); #endif #ifndef _WIN32 /* set up signal handling */ sigfillset(&sigset); sigdelset(&sigset, SIGINT); sigdelset(&sigset, SIGTERM); sigdelset(&sigset, SIGSEGV); sigdelset(&sigset, SIGHUP); sigdelset(&sigset, SIGPIPE); sigdelset(&sigset, SIGUSR2); /* The behavior of a process is undefined after it ignores a * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ sigdelset(&sigset, SIGFPE); sigdelset(&sigset, SIGILL); sigdelset(&sigset, SIGSEGV); #ifdef SIGBUS sigdelset(&sigset, SIGBUS); #endif sigdelset(&sigset, SIGTSTP); sigdelset(&sigset, SIGCONT); sigprocmask(SIG_SETMASK, &sigset, NULL); /* SIGINT, SIGTERM, SIGSEGV */ sigact.sa_handler = sighandler_th; sigemptyset(&sigact.sa_mask); sigaddset(&sigact.sa_mask, SIGINT); sigaddset(&sigact.sa_mask, SIGTERM); sigaddset(&sigact.sa_mask, SIGHUP); sigaddset(&sigact.sa_mask, SIGPIPE); sigaddset(&sigact.sa_mask, SIGUSR2); sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGHUP, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); sigaction(SIGUSR2, &sigact, NULL); #endif idletimeout = optget(opts, "IdleTimeout")->numarg; for (i=0;i < nsockets;i++) if (fds_add(&acceptdata.fds, socketds[i], 1, 0) == -1) { logg("!fds_add failed\n"); cl_engine_free(engine); return 1; } #ifdef _WIN32 event_wake_accept = CreateEvent(NULL, TRUE, FALSE, NULL); event_wake_recv = CreateEvent(NULL, TRUE, FALSE, NULL); #else if (pipe(acceptdata.syncpipe_wake_recv) == -1 || (pipe(acceptdata.syncpipe_wake_accept) == -1)) { logg("!pipe failed\n"); exit(-1); } syncpipe_wake_recv_w = acceptdata.syncpipe_wake_recv[1]; if (fds_add(fds, acceptdata.syncpipe_wake_recv[0], 1, 0) == -1 || fds_add(&acceptdata.fds, acceptdata.syncpipe_wake_accept[0], 1, 0)) { logg("!failed to add pipe fd\n"); exit(-1); } #endif if ((thr_pool = thrmgr_new(max_threads, idletimeout, max_queue, scanner_thread)) == NULL) { logg("!thrmgr_new failed\n"); exit(-1); } if (pthread_create(&accept_th, NULL, acceptloop_th, &acceptdata)) { logg("!pthread_create failed\n"); exit(-1); } time(&start_time); for(;;) { int new_sd; /* Block waiting for connection on any of the sockets */ pthread_mutex_lock(fds->buf_mutex); fds_cleanup(fds); /* signal that we can accept more connections */ if (fds->nfds <= (unsigned)max_queue) pthread_cond_signal(&acceptdata.cond_nfds); new_sd = fds_poll_recv(fds, selfchk ? (int)selfchk : -1, 1, event_wake_recv); #ifdef _WIN32 ResetEvent(event_wake_recv); #else if (!fds->nfds) { /* at least the dummy/sync pipe should have remained */ logg("!All recv() descriptors gone: fatal\n"); pthread_mutex_lock(&exit_mutex); progexit = 1; pthread_mutex_unlock(&exit_mutex); pthread_mutex_unlock(fds->buf_mutex); break; } #endif if (new_sd == -1 && errno != EINTR) { logg("!Failed to poll sockets, fatal\n"); pthread_mutex_lock(&exit_mutex); progexit = 1; pthread_mutex_unlock(&exit_mutex); } if(fds->nfds) i = (rr_last + 1) % fds->nfds; for (j = 0; j < fds->nfds && new_sd >= 0; j++, i = (i+1) % fds->nfds) { size_t pos = 0; int error = 0; struct fd_buf *buf = &fds->buf[i]; if (!buf->got_newdata) continue; #ifndef _WIN32 if (buf->fd == acceptdata.syncpipe_wake_recv[0]) { /* dummy sync pipe, just to wake us */ if (read(buf->fd, buff, sizeof(buff)) < 0) { logg("^Syncpipe read failed\n"); } continue; } #endif if (buf->got_newdata == -1) { if (buf->mode == MODE_WAITREPLY) { logg("$mode WAIT_REPLY -> closed\n"); buf->fd = -1; thrmgr_group_terminate(buf->group); thrmgr_group_finished(buf->group, EXIT_ERROR); continue; } else { logg("$client read error or EOF on read\n"); error = 1; } } if (buf->fd != -1 && buf->got_newdata == -2) { logg("$Client read timed out\n"); mdprintf(buf->fd, "COMMAND READ TIMED OUT\n"); error = 1; } rr_last = i; if (buf->mode == MODE_WAITANCILL) { buf->mode = MODE_COMMAND; logg("$mode -> MODE_COMMAND\n"); } while (!error && buf->fd != -1 && buf->buffer && pos < buf->off && buf->mode != MODE_WAITANCILL) { client_conn_t conn; const char *cmd = NULL; int rc; /* New data available to read on socket. */ memset(&conn, 0, sizeof(conn)); conn.scanfd = buf->recvfd; buf->recvfd = -1; conn.sd = buf->fd; conn.options = options; conn.opts = opts; conn.thrpool = thr_pool; conn.engine = engine; conn.group = buf->group; conn.id = buf->id; conn.quota = buf->quota; conn.filename = buf->dumpname; conn.mode = buf->mode; conn.term = buf->term; /* Parse & dispatch command */ cmd = parse_dispatch_cmd(&conn, buf, &pos, &error, opts, readtimeout); if (conn.mode == MODE_COMMAND && !cmd) break; if (!error) { if (buf->mode == MODE_WAITREPLY && buf->off) { /* Client is not supposed to send anything more */ logg("^Client sent garbage after last command: %lu bytes\n", (unsigned long)buf->off); buf->buffer[buf->off] = '\0'; logg("$Garbage: %s\n", buf->buffer); error = 1; } else if (buf->mode == MODE_STREAM) { rc = handle_stream(&conn, buf, opts, &error, &pos, readtimeout); if (rc == -1) break; else continue; } } if (error && error != CL_ETIMEOUT) { conn_reply_error(&conn, "Error processing command."); } } if (error) { if (buf->dumpfd != -1) { close(buf->dumpfd); if (buf->dumpname) { cli_unlink(buf->dumpname); free(buf->dumpname); } buf->dumpfd = -1; } thrmgr_group_terminate(buf->group); if (thrmgr_group_finished(buf->group, EXIT_ERROR)) { if (buf->fd < 0) { logg("$Skipping shutdown of bad socket after error (FD %d)\n", buf->fd); } else { logg("$Shutting down socket after error (FD %d)\n", buf->fd); shutdown(buf->fd, 2); closesocket(buf->fd); } } else logg("$Socket not shut down due to active tasks\n"); buf->fd = -1; } } pthread_mutex_unlock(fds->buf_mutex); /* handle progexit */ pthread_mutex_lock(&exit_mutex); if (progexit) { pthread_mutex_unlock(&exit_mutex); pthread_mutex_lock(fds->buf_mutex); for (i=0;i < fds->nfds; i++) { if (fds->buf[i].fd == -1) continue; thrmgr_group_terminate(fds->buf[i].group); if (thrmgr_group_finished(fds->buf[i].group, EXIT_ERROR)) { logg("$Shutdown closed fd %d\n", fds->buf[i].fd); shutdown(fds->buf[i].fd, 2); closesocket(fds->buf[i].fd); fds->buf[i].fd = -1; } } pthread_mutex_unlock(fds->buf_mutex); break; } pthread_mutex_unlock(&exit_mutex); /* SIGHUP */ if (sighup) { logg("SIGHUP caught: re-opening log file.\n"); logg_close(); sighup = 0; if(!logg_file && (opt = optget(opts, "LogFile"))->enabled) logg_file = opt->strarg; } /* SelfCheck */ if(selfchk) { time(¤t_time); if((current_time - start_time) >= (time_t)selfchk) { if(reload_db(engine, dboptions, opts, TRUE, &ret)) { pthread_mutex_lock(&reload_mutex); reload = 1; pthread_mutex_unlock(&reload_mutex); } time(&start_time); } } /* DB reload */ pthread_mutex_lock(&reload_mutex); if(reload) { pthread_mutex_unlock(&reload_mutex); engine = reload_db(engine, dboptions, opts, FALSE, &ret); if(ret) { logg("Terminating because of a fatal error.\n"); if(new_sd >= 0) closesocket(new_sd); break; } pthread_mutex_lock(&reload_mutex); reload = 0; time(&reloaded_time); pthread_mutex_unlock(&reload_mutex); #if defined(FANOTIFY) || defined(CLAMAUTH) if(optget(opts, "ScanOnAccess")->enabled && tharg) { tharg->engine = engine; } #endif time(&start_time); } else { pthread_mutex_unlock(&reload_mutex); } } pthread_mutex_lock(&exit_mutex); progexit = 1; pthread_mutex_unlock(&exit_mutex); #ifdef _WIN32 SetEvent(event_wake_accept); #else if (write(acceptdata.syncpipe_wake_accept[1], "", 1) < 0) { logg("^Write to syncpipe failed\n"); } #endif /* Destroy the thread manager. * This waits for all current tasks to end */ logg("*Waiting for all threads to finish\n"); thrmgr_destroy(thr_pool); #if defined(FANOTIFY) || defined(CLAMAUTH) if(optget(opts, "ScanOnAccess")->enabled && tharg) { logg("Stopping on-access scan\n"); pthread_mutex_lock(&logg_mutex); pthread_kill(fan_pid, SIGUSR1); pthread_mutex_unlock(&logg_mutex); pthread_join(fan_pid, NULL); free(tharg); } #endif if(engine) { thrmgr_setactiveengine(NULL); cl_engine_free(engine); } pthread_join(accept_th, NULL); fds_free(fds); pthread_mutex_destroy(fds->buf_mutex); pthread_cond_destroy(&acceptdata.cond_nfds); #ifdef _WIN32 CloseHandle(event_wake_accept); CloseHandle(event_wake_recv); #else close(acceptdata.syncpipe_wake_accept[1]); close(acceptdata.syncpipe_wake_recv[1]); #endif if(dbstat.entries) cl_statfree(&dbstat); logg("*Shutting down the main socket%s.\n", (nsockets > 1) ? "s" : ""); for (i = 0; i < nsockets; i++) shutdown(socketds[i], 2); if((opt = optget(opts, "PidFile"))->enabled) { if(unlink(opt->strarg) == -1) logg("!Can't unlink the pid file %s\n", opt->strarg); else logg("Pid file removed.\n"); } time(¤t_time); logg("--- Stopped at %s", cli_ctime(¤t_time, timestr, sizeof(timestr))); return ret; }
int main(int argc, char *argv[]) { int msize; char buf[BUFSIZ+1]; int i; char hostname[256]; int hflag; struct rlimit rl; if (argc < 2) usage(); if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { rl.rlim_cur = (rl.rlim_max < MAX_THREADS ? rl.rlim_max : MAX_THREADS); (void) setrlimit(RLIMIT_NOFILE, &rl); (void) enable_extended_FILE_stdio(-1, -1); } (void) gethostname(hostname, sizeof (hostname)); init_who(); msize = snprintf(buf, sizeof (buf), "From %s@%s: ", who, hostname); while ((i = getchar()) != EOF) { if (msize >= (sizeof (buf) - 1)) { (void) fprintf(stderr, "Message too long\n"); exit(1); } buf[msize++] = i; } buf[msize] = '\0'; path = buf; hflag = 1; while (argc > 1) { if (argv[1][0] == '-') { switch (argv[1][1]) { case 'h': hflag = 1; break; case 'n': hflag = 0; break; case 'q': qflag = 1; break; default: usage(); break; } argc--; argv++; continue; } if (hflag) { doit(argv[1]); } else { char *machine, *user, *domain; (void) setnetgrent(argv[1]); while (getnetgrent(&machine, &user, &domain)) { if (machine) doit(machine); else doall(); } (void) endnetgrent(); } argc--; argv++; } thr_exit(NULL); return (0); }
int main(int argc, char **argv) { int c; pid_t pid; extern char *optarg; sigset_t mask; struct sigaction act; (void) setlocale(LC_ALL, ""); #ifndef TEXT_DOMAIN #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); if ((prog = strrchr(argv[0], '/')) == NULL) { prog = argv[0]; } else { prog++; } (void) enable_extended_FILE_stdio(-1, -1); /* * process arguments */ if (argc > 3) { usage(); } while ((c = getopt(argc, argv, "d:t:")) != EOF) { switch (c) { case 'd': debug_level = atoi(optarg); break; case 't': idle_timeout = atoi(optarg); break; case '?': default: usage(); /*NOTREACHED*/ } } /* * Check permission */ if (getuid() != 0) { (void) fprintf(stderr, gettext("Must be root to run %s\n"), prog); exit(EPERM); } /* * When rcm_daemon is started by a call to librcm, it inherits file * descriptors from the DR initiator making a call. The file * descriptors may correspond to devices that can be removed by DR. * Since keeping them remain opened is problematic, close everything * but stdin/stdout/stderr. */ closefrom(3); /* * When rcm_daemon is started by the caller, it will inherit the * signal block mask. We unblock all signals to make sure the * signal handling will work normally. */ (void) sigfillset(&mask); (void) thr_sigsetmask(SIG_UNBLOCK, &mask, NULL); /* * block SIGUSR1, use it for killing specific threads */ (void) sigemptyset(&mask); (void) sigaddset(&mask, SIGUSR1); (void) thr_sigsetmask(SIG_BLOCK, &mask, NULL); /* * Setup signal handlers for SIGHUP and SIGUSR1 * SIGHUP - causes a "delayed" daemon exit, effectively the same * as a daemon restart. * SIGUSR1 - causes a thr_exit(). Unblocked in selected threads. */ act.sa_flags = 0; act.sa_handler = catch_sighup; (void) sigaction(SIGHUP, &act, NULL); act.sa_handler = catch_sigusr1; (void) sigaction(SIGUSR1, &act, NULL); /* * ignore SIGPIPE so that the rcm daemon does not exit when it * attempts to read or write from a pipe whose corresponding * rcm script process exited. */ act.sa_handler = SIG_IGN; (void) sigaction(SIGPIPE, &act, NULL); /* * run in daemon mode */ if (debug_level < DEBUG_LEVEL_FORK) { if (fork()) { exit(0); } detachfromtty(); } /* only one daemon can run at a time */ if ((pid = enter_daemon_lock()) != getpid()) { rcm_log_message(RCM_DEBUG, "%s pid %d already running\n", prog, pid); exit(EDEADLK); } rcm_log_message(RCM_TRACE1, "%s started, debug level = %d\n", prog, debug_level); /* * Set daemon state to block RCM requests before rcm_daemon is * fully initialized. See rcmd_thr_incr(). */ rcmd_set_state(RCMD_INIT); /* * create rcm_daemon door and set permission to 0400 */ if (create_event_service(RCM_SERVICE_DOOR, event_service) == -1) { rcm_log_message(RCM_ERROR, gettext("cannot create door service: %s\n"), strerror(errno)); rcmd_exit(errno); } (void) chmod(RCM_SERVICE_DOOR, S_IRUSR); init_poll_thread(); /* initialize poll thread related data */ /* * Initialize database by asking modules to register. */ rcmd_db_init(); /* * Initialize locking, including lock recovery in the event of * unexpected daemon failure. */ rcmd_lock_init(); /* * Start accepting normal requests */ rcmd_set_state(RCMD_NORMAL); /* * Start cleanup thread */ rcmd_db_clean(); /* * Loop within daemon and return after a period of inactivity. */ rcmd_start_timer(idle_timeout); rcmd_cleanup(0); return (0); }
int main(int argc, char *argv[]) { pid_t pid; int c, error; struct rlimit rlset; char *defval; /* * There is no check for non-global zone and Trusted Extensions. * Reparsed works in both of these environments as long as the * services that use reparsed are supported. */ MyName = argv[0]; if (geteuid() != 0) { syslog(LOG_ERR, "%s must be run as root", MyName); exit(1); } while ((c = getopt(argc, argv, REPARSED_CMD_OPTS)) != EOF) { switch (c) { case 'v': verbose++; break; default: usage(); } } daemonize(); openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON); (void) _create_daemon_lock(REPARSED, DAEMON_UID, DAEMON_GID); (void) enable_extended_FILE_stdio(-1, -1); switch (_enter_daemon_lock(REPARSED)) { case 0: break; case -1: syslog(LOG_ERR, "Error locking for %s", REPARSED); exit(2); default: /* daemon was already running */ exit(0); } (void) signal(SIGHUP, warn_hup); /* * Make the process a privilege aware daemon. * Only "basic" privileges are required. * */ if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0, (char *)NULL) == -1) { syslog(LOG_ERR, "should be run with sufficient privileges"); exit(3); } /* * Clear basic privileges not required by reparsed. */ __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); return (start_reparsed_svcs()); }
int main(int argc, char **argv) { int rc = 0; int opt; struct rlimit rlim; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if ((command = strrchr(argv[0], '/')) != NULL) command++; else command = argv[0]; while ((opt = getopt(argc, argv, "lDMNPevs:xS")) != EOF) { switch (opt) { case 'l': list = B_TRUE; break; case 'D': set = B_TRUE; Don = B_TRUE; break; case 'M': mac_aware = B_TRUE; break; case 'N': set = B_TRUE; Doff = B_TRUE; break; case 'P': set = B_TRUE; pfexec = B_TRUE; break; case 'e': exec = B_TRUE; break; case 'S': mode = PRIV_STR_SHORT; break; case 'v': verb = B_TRUE; mode = PRIV_STR_LIT; break; case 's': set = B_TRUE; if ((rc = parsespec(optarg)) != 0) return (rc); break; case 'x': set = B_TRUE; xpol = B_TRUE; break; default: usage(); /*NOTREACHED*/ } } argc -= optind; argv += optind; if ((argc < 1 && !list) || Doff && Don || list && (set || exec) || (mac_aware && !exec)) usage(); /* * Make sure we'll have enough file descriptors to handle a target * that has many many mappings. */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rlim); (void) enable_extended_FILE_stdio(-1, -1); } if (exec) { privupdate_self(); rc = execvp(argv[0], &argv[0]); (void) fprintf(stderr, "%s: %s: %s\n", command, argv[0], strerror(errno)); } else if (list) { rc = dumppriv(argv); } else { while (argc-- > 0) rc += look(*argv++); } return (rc); }