cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

sysinfo.c
Go to the documentation of this file.
1 /*
2  Copyright 2019 Northern.tech AS
3 
4  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the
8  Free Software Foundation; version 3.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 
19  To the extent this program is licensed as part of the Enterprise
20  versions of CFEngine, the applicable Commercial Open Source License
21  (COSL) may apply to this file if you as a licensee so wish it. See
22  included file COSL.txt.
23 */
24 
25 #include <platform.h>
26 
27 #include <sysinfo.h>
28 #include <sysinfo_priv.h>
29 #include <cf3.extern.h>
30 #include <eval_context.h>
31 #include <files_names.h>
32 #include <files_interfaces.h>
33 #include <hash.h>
34 #include <scope.h>
35 #include <item_lib.h>
36 #include <matching.h>
37 #include <systype.h>
38 #include <unix.h>
39 #include <string_lib.h>
40 #include <regex.h> /* StringMatchFull */
41 #include <misc_lib.h>
42 #include <file_lib.h>
43 #include <rlist.h>
44 #include <audit.h>
45 #include <pipes.h>
46 #include <known_dirs.h>
47 #include <files_lib.h>
48 #include <printsize.h>
49 #include <cf-windows-functions.h>
50 #include <ornaments.h>
51 #include <feature.h>
52 #include <evalfunction.h>
53 #include <json-utils.h>
54 
55 #ifdef HAVE_ZONE_H
56 # include <zone.h>
57 #endif
58 
59 // HP-UX mpctl() for $(sys.cpus) on HP-UX - Mantis #1069
60 #ifdef HAVE_SYS_MPCTL_H
61 # include <sys/mpctl.h>
62 #endif
63 
64 /* Linux.
65  WARNING keep this before the #include <sys/sysctl.h> because of glibc bug:
66  https://sourceware.org/bugzilla/show_bug.cgi?id=140 */
67 #ifdef HAVE_STRUCT_SYSINFO_UPTIME
68 # include <sys/sysinfo.h>
69 #endif
70 
71 /* BSD, MAC OS X uptime calculation use KERN_BOOTTIME sysctl. */
72 #ifdef HAVE_SYS_SYSCTL_H
73 # ifdef HAVE_SYS_PARAM_H
74 # include <sys/param.h>
75 # endif
76 # include <sys/sysctl.h>
77 #endif
78 
79 
80 /*****************************************************/
81 // Uptime calculation settings for GetUptimeSeconds() - Mantis #1134
82 
83 /* Listed here in priority order, i.e. first come the platform-specific
84  * ways. If nothing works, one of the last, most generic ways should. */
85 
86 #ifndef __MINGW32__ /* Windows is implemented in Enterprise */
87 
88 // HP-UX: pstat_getproc(2) on init (pid 1)
89 #if defined(__hpux)
90 # include <sys/param.h>
91 # include <sys/pstat.h>
92 # define BOOT_TIME_WITH_PSTAT_GETPROC
93 
94 // Solaris: kstat() for kernel statistics
95 // See http://dsc.sun.com/solaris/articles/kstatc.html
96 // BSD also has a kstat.h (albeit in sys), so check __sun just to be paranoid
97 
98 /**
99  * @WARNING: Commented out because inside a Solaris 10 zone this gives the
100  * uptime of the host machine (the hypervisor). We thus choose to
101  * use UTMP for Solaris.
102  */
103 /*
104 #elif defined(__sun) && defined(HAVE_KSTAT_H)
105 # include <kstat.h>
106 # define BOOT_TIME_WITH_KSTAT
107 */
108 
109 // BSD: sysctl(3) to get kern.boottime, CPU count, etc.
110 // See http://www.unix.com/man-page/FreeBSD/3/sysctl/
111 // Linux also has sys/sysctl.h, so we check KERN_BOOTTIME to make sure it's BSD
112 #elif defined(HAVE_SYS_SYSCTL_H) && defined(KERN_BOOTTIME)
113 # define BOOT_TIME_WITH_SYSCTL
114 
115 // GNU/Linux: struct sysinfo.uptime
116 #elif defined(HAVE_STRUCT_SYSINFO_UPTIME)
117 # define BOOT_TIME_WITH_SYSINFO
118 
119 /* Generic System V way, available in most platforms. */
120 #elif defined(HAVE_UTMP_H)
121 # include <utmp.h>
122 # define BOOT_TIME_WITH_UTMP
123 
124 /* POSIX alternative (utmp.h does not exist on BSDs). */
125 #elif defined(HAVE_UTMPX_H)
126 # include <utmpx.h>
127 # define BOOT_TIME_WITH_UTMPX
128 
129 #else
130 // Most generic way: {stat("/proc/1")}.st_ctime
131 // TODO in Solaris zones init is not guaranteed to be PID 1!
132 #define BOOT_TIME_WITH_PROCFS
133 
134 #endif
135 
136 /* Fallback uptime calculation: Parse the "uptime" command in case the
137  * platform-specific way fails or returns absurd number. */
138 static time_t GetBootTimeFromUptimeCommand(time_t now);
139 
140 #endif /* ifndef __MINGW32__ */
141 
142 #define LSB_RELEASE_FILENAME "/etc/lsb-release"
143 #define DEBIAN_VERSION_FILENAME "/etc/debian_version"
144 #define DEBIAN_ISSUE_FILENAME "/etc/issue"
145 
146 
147 /*****************************************************/
148 
149 void CalculateDomainName(const char *nodename, const char *dnsname,
150  char *fqname, size_t fqname_size,
151  char *uqname, size_t uqname_size,
152  char *domain, size_t domain_size);
153 
154 #ifdef __linux__
155 static int Linux_Fedora_Version(EvalContext *ctx);
156 static int Linux_Redhat_Version(EvalContext *ctx);
157 static void Linux_Amazon_Version(EvalContext *ctx);
158 static void Linux_Alpine_Version(EvalContext *ctx);
159 static void Linux_Oracle_VM_Server_Version(EvalContext *ctx);
160 static void Linux_Oracle_Version(EvalContext *ctx);
161 static int Linux_Suse_Version(EvalContext *ctx);
162 static int Linux_Slackware_Version(EvalContext *ctx, char *filename);
163 static int Linux_Debian_Version(EvalContext *ctx);
164 static int Linux_Misc_Version(EvalContext *ctx);
165 static int Linux_Mandrake_Version(EvalContext *ctx);
166 static int Linux_Mandriva_Version(EvalContext *ctx);
167 static int Linux_Mandriva_Version_Real(EvalContext *ctx, char *filename, char *relstring, char *vendor);
168 static int VM_Version(EvalContext *ctx);
169 static int Xen_Domain(EvalContext *ctx);
170 static int EOS_Version(EvalContext *ctx);
171 static int MiscOS(EvalContext *ctx);
172 static void OpenVZ_Detect(EvalContext *ctx);
173 
174 static bool ReadLine(const char *filename, char *buf, int bufsize);
175 static FILE *ReadFirstLine(const char *filename, char *buf, int bufsize);
176 #endif
177 
178 #ifdef XEN_CPUID_SUPPORT
179 static void Xen_Cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
180 static bool Xen_Hv_Check(void);
181 #endif
182 
183 static void GetCPUInfo(EvalContext *ctx);
184 
185 static const char *const CLASSATTRIBUTES[][3] =
186 {
187  [PLATFORM_CONTEXT_UNKNOWN] = {"-", "-", "-"}, /* as appear here are matched. The fields are sysname and machine */
188  [PLATFORM_CONTEXT_OPENVZ] = {"virt_host_vz_vzps", ".*", ".*"}, /* VZ with vzps */
189  [PLATFORM_CONTEXT_HP] = {"hp-ux", ".*", ".*"}, /* hpux */
190  [PLATFORM_CONTEXT_AIX] = {"aix", ".*", ".*"}, /* aix */
191  [PLATFORM_CONTEXT_LINUX] = {"linux", ".*", ".*"}, /* linux */
192  [PLATFORM_CONTEXT_BUSYBOX] = {"busybox", ".*", ".*"}, /* linux w/ busybox - warning uname returns linux */
193  [PLATFORM_CONTEXT_SOLARIS] = {"sunos", ".*",
194  "5\\.1[1-9].*"}, /* new solaris, SunOS >= 5.11 */
195  [PLATFORM_CONTEXT_SUN_SOLARIS] = {"sunos", ".*",
196  "5\\.([2-9]|10)(\\..*)?"}, /* old solaris, SunOS < 5.11 */
197  [PLATFORM_CONTEXT_FREEBSD] = {"freebsd", ".*", ".*"}, /* freebsd */
198  [PLATFORM_CONTEXT_NETBSD] = {"netbsd", ".*", ".*"}, /* NetBSD */
199  [PLATFORM_CONTEXT_CRAYOS] = {"sn.*", "cray*", ".*"}, /* cray */
200  [PLATFORM_CONTEXT_WINDOWS_NT] = {"cygwin_nt.*", ".*", ".*"}, /* NT (cygwin) */
201  [PLATFORM_CONTEXT_SYSTEMV] = {"unix_sv", ".*", ".*"}, /* Unixware */
202  [PLATFORM_CONTEXT_OPENBSD] = {"openbsd", ".*", ".*"}, /* OpenBSD */
203  [PLATFORM_CONTEXT_CFSCO] = {"sco_sv", ".*", ".*"}, /* SCO */
204  [PLATFORM_CONTEXT_DARWIN] = {"darwin", ".*", ".*"}, /* Darwin, aka MacOS X */
205  [PLATFORM_CONTEXT_QNX] = {"qnx", ".*", ".*"}, /* qnx */
206  [PLATFORM_CONTEXT_DRAGONFLY] = {"dragonfly", ".*", ".*"}, /* dragonfly */
207  [PLATFORM_CONTEXT_MINGW] = {"windows_nt.*", ".*", ".*"}, /* NT (native) */
208  [PLATFORM_CONTEXT_VMWARE] = {"vmkernel", ".*", ".*"}, /* VMWARE / ESX */
209  [PLATFORM_CONTEXT_ANDROID] = {"android", ".*", ".*"}, /* android: Warning uname returns linux */
210 };
211 
212 static const char *const VRESOLVCONF[] =
213 {
214  [PLATFORM_CONTEXT_UNKNOWN] = "-",
215  [PLATFORM_CONTEXT_OPENVZ] = "/etc/resolv.conf", /* virt_host_vz_vzps */
216  [PLATFORM_CONTEXT_HP] = "/etc/resolv.conf", /* hpux */
217  [PLATFORM_CONTEXT_AIX] = "/etc/resolv.conf", /* aix */
218  [PLATFORM_CONTEXT_LINUX] = "/etc/resolv.conf", /* linux */
219  [PLATFORM_CONTEXT_BUSYBOX] = "/etc/resolv.conf", /* linux */
220  [PLATFORM_CONTEXT_SOLARIS] = "/etc/resolv.conf", /* new solaris */
221  [PLATFORM_CONTEXT_SUN_SOLARIS] = "/etc/resolv.conf", /* old solaris */
222  [PLATFORM_CONTEXT_FREEBSD] = "/etc/resolv.conf", /* freebsd */
223  [PLATFORM_CONTEXT_NETBSD] = "/etc/resolv.conf", /* netbsd */
224  [PLATFORM_CONTEXT_CRAYOS] = "/etc/resolv.conf", /* cray */
225  [PLATFORM_CONTEXT_WINDOWS_NT] = "/etc/resolv.conf", /* NT */
226  [PLATFORM_CONTEXT_SYSTEMV] = "/etc/resolv.conf", /* Unixware */
227  [PLATFORM_CONTEXT_OPENBSD] = "/etc/resolv.conf", /* openbsd */
228  [PLATFORM_CONTEXT_CFSCO] = "/etc/resolv.conf", /* sco */
229  [PLATFORM_CONTEXT_DARWIN] = "/etc/resolv.conf", /* darwin */
230  [PLATFORM_CONTEXT_QNX] = "/etc/resolv.conf", /* qnx */
231  [PLATFORM_CONTEXT_DRAGONFLY] = "/etc/resolv.conf", /* dragonfly */
232  [PLATFORM_CONTEXT_MINGW] = "", /* mingw */
233  [PLATFORM_CONTEXT_VMWARE] = "/etc/resolv.conf", /* vmware */
234  [PLATFORM_CONTEXT_ANDROID] = "", /* android */
235 };
236 
237 static const char *const VMAILDIR[] =
238 {
239  [PLATFORM_CONTEXT_UNKNOWN] = "-",
240  [PLATFORM_CONTEXT_OPENVZ] = "/var/spool/mail", /* virt_host_vz_vzps */
241  [PLATFORM_CONTEXT_HP] = "/var/mail", /* hpux */
242  [PLATFORM_CONTEXT_AIX] = "/var/spool/mail", /* aix */
243  [PLATFORM_CONTEXT_LINUX] = "/var/spool/mail", /* linux */
244  [PLATFORM_CONTEXT_BUSYBOX] = "", /* linux */
245  [PLATFORM_CONTEXT_SOLARIS] = "/var/mail", /* new solaris */
246  [PLATFORM_CONTEXT_SUN_SOLARIS] = "/var/mail", /* old solaris */
247  [PLATFORM_CONTEXT_FREEBSD] = "/var/mail", /* freebsd */
248  [PLATFORM_CONTEXT_NETBSD] = "/var/mail", /* netbsd */
249  [PLATFORM_CONTEXT_CRAYOS] = "/usr/mail", /* cray */
250  [PLATFORM_CONTEXT_WINDOWS_NT] = "N/A", /* NT */
251  [PLATFORM_CONTEXT_SYSTEMV] = "/var/mail", /* Unixware */
252  [PLATFORM_CONTEXT_OPENBSD] = "/var/mail", /* openbsd */
253  [PLATFORM_CONTEXT_CFSCO] = "/var/spool/mail", /* sco */
254  [PLATFORM_CONTEXT_DARWIN] = "/var/mail", /* darwin */
255  [PLATFORM_CONTEXT_QNX] = "/var/spool/mail", /* qnx */
256  [PLATFORM_CONTEXT_DRAGONFLY] = "/var/mail", /* dragonfly */
257  [PLATFORM_CONTEXT_MINGW] = "", /* mingw */
258  [PLATFORM_CONTEXT_VMWARE] = "/var/spool/mail", /* vmware */
259  [PLATFORM_CONTEXT_ANDROID] = "", /* android */
260 };
261 
262 static const char *const VEXPORTS[] =
263 {
264  [PLATFORM_CONTEXT_UNKNOWN] = "-",
265  [PLATFORM_CONTEXT_OPENVZ] = "/etc/exports", /* virt_host_vz_vzps */
266  [PLATFORM_CONTEXT_HP] = "/etc/exports", /* hpux */
267  [PLATFORM_CONTEXT_AIX] = "/etc/exports", /* aix */
268  [PLATFORM_CONTEXT_LINUX] = "/etc/exports", /* linux */
269  [PLATFORM_CONTEXT_BUSYBOX] = "", /* linux */
270  [PLATFORM_CONTEXT_SOLARIS] = "/etc/dfs/dfstab", /* new solaris */
271  [PLATFORM_CONTEXT_SUN_SOLARIS] = "/etc/dfs/dfstab", /* old solaris */
272  [PLATFORM_CONTEXT_FREEBSD] = "/etc/exports", /* freebsd */
273  [PLATFORM_CONTEXT_NETBSD] = "/etc/exports", /* netbsd */
274  [PLATFORM_CONTEXT_CRAYOS] = "/etc/exports", /* cray */
275  [PLATFORM_CONTEXT_WINDOWS_NT] = "/etc/exports", /* NT */
276  [PLATFORM_CONTEXT_SYSTEMV] = "/etc/dfs/dfstab", /* Unixware */
277  [PLATFORM_CONTEXT_OPENBSD] = "/etc/exports", /* openbsd */
278  [PLATFORM_CONTEXT_CFSCO] = "/etc/dfs/dfstab", /* sco */
279  [PLATFORM_CONTEXT_DARWIN] = "/etc/exports", /* darwin */
280  [PLATFORM_CONTEXT_QNX] = "/etc/exports", /* qnx */
281  [PLATFORM_CONTEXT_DRAGONFLY] = "/etc/exports", /* dragonfly */
282  [PLATFORM_CONTEXT_MINGW] = "", /* mingw */
283  [PLATFORM_CONTEXT_VMWARE] = "none", /* vmware */
284  [PLATFORM_CONTEXT_ANDROID] = "" , /* android */
285 };
286 
287 
288 /*******************************************************************/
289 
290 void CalculateDomainName(const char *nodename, const char *dnsname,
291  char *fqname, size_t fqname_size,
292  char *uqname, size_t uqname_size,
293  char *domain, size_t domain_size)
294 {
295  if (strstr(dnsname, "."))
296  {
297  strlcpy(fqname, dnsname, fqname_size);
298  }
299  else
300  {
301  strlcpy(fqname, nodename, fqname_size);
302  }
303 
304  if ((strncmp(nodename, fqname, strlen(nodename)) == 0) && (fqname[strlen(nodename)] == '.'))
305  {
306  /* If hostname is not qualified */
307  strlcpy(domain, fqname + strlen(nodename) + 1, domain_size);
308  strlcpy(uqname, nodename, uqname_size);
309  }
310  else
311  {
312  /* If hostname is qualified */
313 
314  char *p = strchr(nodename, '.');
315 
316  if (p != NULL)
317  {
318  strlcpy(uqname, nodename, MIN(uqname_size, p - nodename + 1));
319  strlcpy(domain, p + 1, domain_size);
320  }
321  else
322  {
323  strlcpy(uqname, nodename, uqname_size);
324  strlcpy(domain, "", domain_size);
325  }
326  }
327 }
328 
329 /*******************************************************************/
330 
331 void DetectDomainName(EvalContext *ctx, const char *orig_nodename)
332 {
333  char nodename[CF_BUFSIZE];
334 
335  strlcpy(nodename, orig_nodename, sizeof(nodename));
336  ToLowerStrInplace(nodename);
337 
338  char dnsname[CF_BUFSIZE] = "";
339  char fqn[CF_BUFSIZE];
340 
341  if (gethostname(fqn, sizeof(fqn)) != -1)
342  {
343  struct hostent *hp;
344 
345  if ((hp = gethostbyname(fqn)))
346  {
347  strlcpy(dnsname, hp->h_name, sizeof(dnsname));
348  ToLowerStrInplace(dnsname);
349  }
350  }
351 
352  CalculateDomainName(nodename, dnsname, VFQNAME, CF_MAXVARSIZE,
354 
355 /*
356  * VFQNAME = a.b.c.d ->
357  * NewClass("a.b.c.d")
358  * NewClass("b.c.d")
359  * NewClass("c.d")
360  * NewClass("d")
361  */
362  char *ptr = VFQNAME;
363 
364  do
365  {
366  EvalContextClassPutHard(ctx, ptr, "inventory,attribute_name=none,source=agent,derived-from=sys.fqhost");
367 
368  ptr = strchr(ptr, '.');
369  if (ptr != NULL)
370  {
371  ptr++;
372  }
373  } while (ptr != NULL);
374 
375  EvalContextClassPutHard(ctx, VUQNAME, "source=agent,derived-from=sys.uqhost");
376  EvalContextClassPutHard(ctx, VDOMAIN, "source=agent,derived-from=sys.domain");
377 
378  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "host", nodename, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=none");
379  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "uqhost", VUQNAME, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=none");
380  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost", VFQNAME, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=Host name");
382 }
383 
384 /*******************************************************************/
385 
387 {
388  int major = 0;
389  int minor = 0;
390  int patch = 0;
391  char workbuf[CF_BUFSIZE];
392  if (sscanf(Version(), "%d.%d.%d", &major, &minor, &patch) == 3)
393  {
394  snprintf(workbuf, CF_MAXVARSIZE, "%d", major);
395  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_major", workbuf, CF_DATA_TYPE_STRING, "source=agent");
396  snprintf(workbuf, CF_MAXVARSIZE, "%d", minor);
397  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_minor", workbuf, CF_DATA_TYPE_STRING, "source=agent");
398  snprintf(workbuf, CF_MAXVARSIZE, "%d", patch);
399  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_patch", workbuf, CF_DATA_TYPE_STRING, "source=agent");
400  }
401  else
402  {
403  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_major", "BAD VERSION " VERSION, CF_DATA_TYPE_STRING, "source=agent");
404  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_minor", "BAD VERSION " VERSION, CF_DATA_TYPE_STRING, "source=agent");
405  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_patch", "BAD VERSION " VERSION, CF_DATA_TYPE_STRING, "source=agent");
406  }
407 
408  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_release", RELEASE, CF_DATA_TYPE_STRING, "source=agent");
409 
410  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "local_libdir", "lib", CF_DATA_TYPE_STRING, "source=agent");
411 
412  snprintf(workbuf, CF_BUFSIZE, "%s%cinputs%clib", GetWorkDir(), FILE_SEPARATOR, FILE_SEPARATOR);
413  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "libdir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
414 }
415 
416 static void GetNameInfo3(EvalContext *ctx)
417 {
418  int i, found = false;
419  char *sp, workbuf[CF_BUFSIZE];
420  time_t tloc;
421  struct hostent *hp;
422  struct sockaddr_in cin;
423  unsigned char digest[EVP_MAX_MD_SIZE + 1];
424  const char* const workdir = GetWorkDir();
425  const char* const bindir = GetBinDir();
426 
427 #ifdef _AIX
428  char real_version[_SYS_NMLN];
429 #endif
430 #if defined(HAVE_SYSINFO) && (defined(SI_ARCHITECTURE) || defined(SI_PLATFORM))
431  long sz;
432 #endif
433 
434 #define COMPONENTS_SIZE 16
435  // This is used for $(sys.cf_agent), $(sys.cf_serverd) ... :
436  char *components[COMPONENTS_SIZE] = { "cf-twin", "cf-agent", "cf-serverd", "cf-monitord", "cf-know",
437  "cf-report", "cf-key", "cf-runagent", "cf-execd", "cf-hub",
438  "cf-promises", "cf-upgrade", "cf-net", "cf-check", "cf-secret",
439  NULL
440  };
441  int have_component[COMPONENTS_SIZE];
442  struct stat sb;
443  char name[CF_MAXVARSIZE], quoteName[CF_MAXVARSIZE], shortname[CF_MAXVARSIZE];
444 
445  if (uname(&VSYSNAME) == -1)
446  {
447  Log(LOG_LEVEL_ERR, "Couldn't get kernel name info!. (uname: %s)", GetErrorStr());
448  memset(&VSYSNAME, 0, sizeof(VSYSNAME));
449  }
450 
451 #ifdef _AIX
452  snprintf(real_version, _SYS_NMLN, "%.80s.%.80s", VSYSNAME.version, VSYSNAME.release);
453  strlcpy(VSYSNAME.release, real_version, _SYS_NMLN);
454 #endif
455 #ifdef __ANDROID__
456  /*
457  * uname cannot differentiate android from linux
458  */
459  strcpy(VSYSNAME.sysname, "android");
460 #endif
461 #ifdef __BUSYBOX__
462  /*
463  * uname cannot differentiate a busybox toolset from a normal GNU linux toolset
464  */
465  strcpy(VSYSNAME.sysname, "busybox");
466 #endif
467 
470 
471 #ifdef _AIX
472  switch (_system_configuration.architecture)
473  {
474  case POWER_RS:
475  strlcpy(VSYSNAME.machine, "power", _SYS_NMLN);
476  break;
477  case POWER_PC:
478  strlcpy(VSYSNAME.machine, "powerpc", _SYS_NMLN);
479  break;
480  case IA64:
481  strlcpy(VSYSNAME.machine, "ia64", _SYS_NMLN);
482  break;
483  }
484 #endif
485 
486 /*
487  * solarisx86 is a historically defined class for Solaris on x86. We have to
488  * define it manually now.
489  */
490 #ifdef __sun
491  if (strcmp(VSYSNAME.machine, "i86pc") == 0)
492  {
493  EvalContextClassPutHard(ctx, "solarisx86", "inventory,attribute_name=none,source=agent");
494  }
495 #endif
496 
498 
499  if ((tloc = time((time_t *) NULL)) == -1)
500  {
501  Log(LOG_LEVEL_ERR, "Couldn't read system clock");
502  }
503  else
504  {
505  snprintf(workbuf, CF_BUFSIZE, "%jd", (intmax_t) tloc);
506  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "systime", workbuf, CF_DATA_TYPE_INT, "time_based,source=agent");
507  snprintf(workbuf, CF_BUFSIZE, "%jd", (intmax_t) tloc / SECONDS_PER_DAY);
508  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "sysday", workbuf, CF_DATA_TYPE_INT, "time_based,source=agent");
509  i = GetUptimeMinutes(tloc);
510  if (i != -1)
511  {
512  snprintf(workbuf, CF_BUFSIZE, "%d", i);
513  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "uptime", workbuf, CF_DATA_TYPE_INT, "inventory,time_based,source=agent,attribute_name=Uptime minutes");
514  }
515  }
516 
517  for (i = 0; i < PLATFORM_CONTEXT_MAX; i++)
518  {
519  char sysname[CF_BUFSIZE];
520  strlcpy(sysname, VSYSNAME.sysname, CF_BUFSIZE);
521  ToLowerStrInplace(sysname);
522 
523  /* FIXME: review those strcmps. Moved out from StringMatch */
524  if (!strcmp(CLASSATTRIBUTES[i][0], sysname)
525  || StringMatchFull(CLASSATTRIBUTES[i][0], sysname))
526  {
527  if (!strcmp(CLASSATTRIBUTES[i][1], VSYSNAME.machine)
529  {
530  if (!strcmp(CLASSATTRIBUTES[i][2], VSYSNAME.release)
532  {
533  EvalContextClassPutHard(ctx, CLASSTEXT[i], "inventory,attribute_name=none,source=agent,derived-from=sys.class");
534 
535  found = true;
536 
538  VPSHARDCLASS = (PlatformContext) i; /* this one can be overriden at vz detection */
539  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "class", CLASSTEXT[i], CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=OS type");
540  break;
541  }
542  }
543  else
544  {
545  Log(LOG_LEVEL_DEBUG, "I recognize '%s' but not '%s'", VSYSNAME.sysname, VSYSNAME.machine);
546  continue;
547  }
548  }
549  }
550 
551  if (!found)
552  {
553  i = 0;
554  }
555 
556  Log(LOG_LEVEL_VERBOSE, "%s - ready", NameVersion());
557  Banner("Environment discovery");
558 
559  snprintf(workbuf, CF_BUFSIZE, "%s", CLASSTEXT[i]);
560 
561 
562  Log(LOG_LEVEL_VERBOSE, "Host name is: %s", VSYSNAME.nodename);
563  Log(LOG_LEVEL_VERBOSE, "Operating System Type is %s", VSYSNAME.sysname);
564  Log(LOG_LEVEL_VERBOSE, "Operating System Release is %s", VSYSNAME.release);
565  Log(LOG_LEVEL_VERBOSE, "Architecture = %s", VSYSNAME.machine);
566  Log(LOG_LEVEL_VERBOSE, "CFEngine detected operating system description is %s", workbuf);
567  Log(LOG_LEVEL_VERBOSE, "The time is now %s", ctime(&tloc));
568 
569  snprintf(workbuf, CF_MAXVARSIZE, "%s", ctime(&tloc));
570  Chop(workbuf, CF_EXPANDSIZE);
571 
572  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "date", workbuf, CF_DATA_TYPE_STRING, "time_based,source=agent");
573  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cdate", CanonifyName(workbuf), CF_DATA_TYPE_STRING, "time_based,source=agent");
575  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "release", VSYSNAME.release, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=OS kernel");
577  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "arch", VSYSNAME.machine, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=Architecture");
578  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "workdir", workdir, CF_DATA_TYPE_STRING, "source=agent");
588 
589  snprintf(workbuf, CF_BUFSIZE, "%s", bindir);
590  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "bindir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
591 
592  snprintf(workbuf, CF_BUFSIZE, "%s%cpromises.cf", GetInputDir(), FILE_SEPARATOR);
593  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "default_policy_path", workbuf, CF_DATA_TYPE_STRING, "source=agent");
594 
595  snprintf(workbuf, CF_BUFSIZE, "%s%cfailsafe.cf", GetInputDir(), FILE_SEPARATOR);
596  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "failsafe_policy_path", workbuf, CF_DATA_TYPE_STRING, "source=agent");
597 
598  snprintf(workbuf, CF_BUFSIZE, "%s%cupdate.cf", GetInputDir(), FILE_SEPARATOR);
599  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "update_policy_path", workbuf, CF_DATA_TYPE_STRING, "source=agent");
600 
601 /* FIXME: type conversion */
602  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version", (char *) Version(), CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CFEngine version");
603 
604  DiscoverVersion(ctx);
605 
606  if (PUBKEY)
607  {
608  char pubkey_digest[CF_HOSTKEY_STRING_SIZE] = { 0 };
609 
611  HashPrintSafe(pubkey_digest, sizeof(pubkey_digest), digest,
612  CF_DEFAULT_DIGEST, true);
613 
614  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "key_digest", pubkey_digest, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CFEngine ID");
615 
616  snprintf(workbuf, CF_MAXVARSIZE - 1, "PK_%s", pubkey_digest);
617  CanonifyNameInPlace(workbuf);
618  EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent,derived-from=sys.key_digest");
619  }
620 
621  for (i = 0; components[i] != NULL; i++)
622  {
623  snprintf(shortname, CF_MAXVARSIZE - 1, "%s", CanonifyName(components[i]));
624 
625 #if defined(_WIN32)
626  // twin has own dir, and is named agent
627  if (i == 0)
628  {
629  snprintf(name, CF_MAXVARSIZE - 1, "%s-twin%ccf-agent.exe", bindir, FILE_SEPARATOR);
630  }
631  else
632  {
633  snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s.exe", bindir, FILE_SEPARATOR, components[i]);
634  }
635 #else
636  snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s", bindir, FILE_SEPARATOR, components[i]);
637 #endif
638 
639  have_component[i] = false;
640 
641  if (stat(name, &sb) != -1)
642  {
643  snprintf(quoteName, sizeof(quoteName), "\"%s\"", name);
644  // Sets $(sys.cf_agent), $(sys.cf_serverd) $(sys.cf_execd) etc.
645  // to their respective /bin paths
646  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, shortname, quoteName, CF_DATA_TYPE_STRING, "cfe_internal,source=agent");
647  have_component[i] = true;
648  }
649  }
650 
651 // If no twin, fail over the agent
652 
653  if (!have_component[0])
654  {
655  snprintf(shortname, CF_MAXVARSIZE - 1, "%s", CanonifyName(components[0]));
656 
657 #if defined(_WIN32)
658  snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s.exe", bindir, FILE_SEPARATOR,
659  components[1]);
660 #else
661  snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s", bindir, FILE_SEPARATOR, components[1]);
662 #endif
663 
664  if (stat(name, &sb) != -1)
665  {
666  snprintf(quoteName, sizeof(quoteName), "\"%s\"", name);
667  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, shortname, quoteName, CF_DATA_TYPE_STRING, "cfe_internal,source=agent");
668  }
669  }
670 
671 /* Windows special directories and tools */
672 
673 #ifdef __MINGW32__
674  if (NovaWin_GetWinDir(workbuf, sizeof(workbuf)))
675  {
676  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "windir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
677  }
678 
679  if (NovaWin_GetSysDir(workbuf, sizeof(workbuf)))
680  {
681  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winsysdir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
682 
683  char filename[CF_BUFSIZE];
684  if (snprintf(filename, sizeof(filename), "%s%s", workbuf, "\\WindowsPowerShell\\v1.0\\powershell.exe") < sizeof(filename))
685  {
686  if (NovaWin_FileExists(filename))
687  {
688  EvalContextClassPutHard(ctx, "powershell", "inventory,attribute_name=none,source=agent");
689  Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", "powershell");
690  }
691  }
692  }
693 
694  if (NovaWin_GetProgDir(workbuf, sizeof(workbuf)))
695  {
696  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winprogdir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
697  }
698 
699 # ifdef _WIN64
700 // only available on 64 bit windows systems
701  if (NovaWin_GetEnv("PROGRAMFILES(x86)", workbuf, sizeof(workbuf)))
702  {
703  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winprogdir86", workbuf, CF_DATA_TYPE_STRING, "source=agent");
704  }
705 
706 # else/* NOT _WIN64 */
707 
708  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winprogdir86", "", CF_DATA_TYPE_STRING, "source=agent");
709 
710 # endif
711 #endif /* !__MINGW32__ */
712 
713  EnterpriseContext(ctx);
714 
715  snprintf(workbuf, sizeof(workbuf), "%u_bit", (unsigned) sizeof(void*) * 8);
716  EvalContextClassPutHard(ctx, workbuf, "source=agent");
717  Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
718 
719  snprintf(workbuf, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, VSYSNAME.release);
720  EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent,derived-from=sys.sysname,derived-from=sys.release");
721 
722  EvalContextClassPutHard(ctx, VSYSNAME.machine, "source=agent,derived-from=sys.machine");
723  Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
724 
725  snprintf(workbuf, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, VSYSNAME.machine);
726  EvalContextClassPutHard(ctx, workbuf, "source=agent,derived-from=sys.sysname,derived-from=sys.machine");
727  Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
728 
729  snprintf(workbuf, CF_BUFSIZE, "%s_%s_%s", VSYSNAME.sysname, VSYSNAME.machine, VSYSNAME.release);
730  EvalContextClassPutHard(ctx, workbuf, "source=agent,derived-from=sys.sysname,derived-from=sys.machine,derived-from=sys.release");
731  Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
732 
733 #ifdef HAVE_SYSINFO
734 # ifdef SI_ARCHITECTURE
735  sz = sysinfo(SI_ARCHITECTURE, workbuf, CF_BUFSIZE);
736  if (sz == -1)
737  {
738  Log(LOG_LEVEL_VERBOSE, "cfengine internal: sysinfo returned -1");
739  }
740  else
741  {
742  EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent");
743  Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", workbuf);
744  }
745 # endif
746 # ifdef SI_PLATFORM
747  sz = sysinfo(SI_PLATFORM, workbuf, CF_BUFSIZE);
748  if (sz == -1)
749  {
750  Log(LOG_LEVEL_VERBOSE, "cfengine internal: sysinfo returned -1");
751  }
752  else
753  {
754  EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent");
755  Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", workbuf);
756  }
757 # endif
758 #endif
759 
760  snprintf(workbuf, CF_BUFSIZE, "%s_%s_%s_%s", VSYSNAME.sysname, VSYSNAME.machine, VSYSNAME.release,
761  VSYSNAME.version);
762 
763  if (strlen(workbuf) > CF_MAXVARSIZE - 2)
764  {
765  Log(LOG_LEVEL_VERBOSE, "cfengine internal: $(arch) overflows CF_MAXVARSIZE! Truncating");
766  }
767 
768  sp = xstrdup(CanonifyName(workbuf));
769  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "long_arch", sp, CF_DATA_TYPE_STRING, "source=agent");
770  EvalContextClassPutHard(ctx, sp, "source=agent,derived-from=sys.long_arch");
771  free(sp);
772 
773  snprintf(workbuf, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, VSYSNAME.machine);
774  sp = xstrdup(CanonifyName(workbuf));
775  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "ostype", sp, CF_DATA_TYPE_STRING, "source=agent");
776  EvalContextClassPutHard(ctx, sp, "inventory,attribute_name=none,source=agent,derived-from=sys.ostype");
777  free(sp);
778 
779  if (!found)
780  {
781  Log(LOG_LEVEL_ERR, "I don't understand what architecture this is");
782  }
783 
784  char compile_str[] = "compiled_on_";
785  size_t compile_str_len = sizeof(compile_str);
786  strcpy(workbuf, compile_str);
787 
788  strlcat(workbuf, CanonifyName(AUTOCONF_SYSNAME),
789  CF_BUFSIZE - compile_str_len);
790  EvalContextClassPutHard(ctx, workbuf, "source=agent");
791  Log(LOG_LEVEL_VERBOSE, "GNU autoconf class from compile time: %s", workbuf);
792 
793 /* Get IP address from nameserver */
794 
795  if ((hp = gethostbyname(VFQNAME)) == NULL)
796  {
797  Log(LOG_LEVEL_VERBOSE, "Hostname lookup failed on node name '%s'", VSYSNAME.nodename);
798  return;
799  }
800  else
801  {
802  memset(&cin, 0, sizeof(cin));
803  cin.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr))->s_addr;
804  Log(LOG_LEVEL_VERBOSE, "Address given by nameserver: %s", inet_ntoa(cin.sin_addr));
805  strcpy(VIPADDRESS, inet_ntoa(cin.sin_addr));
806 
807  for (i = 0; hp->h_aliases[i] != NULL; i++)
808  {
809  Log(LOG_LEVEL_DEBUG, "Adding alias '%s'", hp->h_aliases[i]);
810  EvalContextClassPutHard(ctx, hp->h_aliases[i], "inventory,attribute_name=none,source=agent,based-on=sys.fqhost");
811  }
812  }
813 
814 #ifdef HAVE_GETZONEID
815  zoneid_t zid;
816  char zone[ZONENAME_MAX];
817  char vbuff[CF_BUFSIZE];
818 
819  zid = getzoneid();
820  getzonenamebyid(zid, zone, ZONENAME_MAX);
821 
822  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "zone", zone, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=Solaris zone");
823  snprintf(vbuff, CF_BUFSIZE - 1, "zone_%s", zone);
824  EvalContextClassPutHard(ctx, vbuff, "source=agent,derived-from=sys.zone");
825 
826  if (strcmp(zone, "global") == 0)
827  {
828  Log(LOG_LEVEL_VERBOSE, "CFEngine seems to be running inside a global solaris zone of name '%s'", zone);
829  }
830  else
831  {
832  Log(LOG_LEVEL_VERBOSE, "CFEngine seems to be running inside a local solaris zone of name '%s'", zone);
833  }
834 #endif
835 }
836 
837 /*******************************************************************/
838 
840 {
841  CF_DB *dbp;
842  CF_DBC *dbcp;
843  char *key;
844  void *stored;
845  int ksize, vsize;
846 
847  if (!OpenDB(&dbp, dbid_static))
848  {
849  return;
850  }
851 
852  /* Acquire a cursor for the database. */
853  if (!NewDBCursor(dbp, &dbcp))
854  {
855  Log(LOG_LEVEL_INFO, "Unable to scan class db");
856  CloseDB(dbp);
857  return;
858  }
859 
860  while (NextDB(dbcp, &key, &ksize, &stored, &vsize))
861  {
862  if (key == NULL || stored == NULL)
863  {
864  continue;
865  }
866 
867  char lval[1024];
868  int type_i;
869  int ret = sscanf(key, "%1023[^:]:%d", lval, &type_i);
870  if (ret == 2)
871  {
872  DataType type = type_i;
873  switch (type)
874  {
875  case CF_DATA_TYPE_STRING:
876  case CF_DATA_TYPE_INT:
877  case CF_DATA_TYPE_REAL:
879  lval, stored, type,
880  "monitoring,source=observation");
881  break;
882 
884  {
885  Rlist *list = RlistFromSplitString(stored, ',');
887  lval, list, CF_DATA_TYPE_STRING_LIST,
888  "monitoring,source=observation");
889  RlistDestroy(list);
890  break;
891  }
894  lval, stored, CF_DATA_TYPE_STRING,
895  "monitoring,source=observation");
896  break;
897 
898  default:
900  "Unexpected monitoring type %d found in dbid_static database",
901  (int) type);
902  }
903  }
904  }
905 
906  DeleteDBCursor(dbcp);
907  CloseDB(dbp);
908 }
909 
910 static void Get3Environment(EvalContext *ctx)
911 {
912  char env[CF_BUFSIZE], context[CF_BUFSIZE], name[CF_MAXVARSIZE], value[CF_BUFSIZE];
913  struct stat statbuf;
914  time_t now = time(NULL);
915 
916  Log(LOG_LEVEL_VERBOSE, "Looking for environment from cf-monitord...");
917 
918  snprintf(env, CF_BUFSIZE, "%s/%s", GetStateDir(), CF_ENV_FILE);
919  MapName(env);
920 
921  FILE *fp = safe_fopen(env, "r");
922  if (fp == NULL)
923  {
924  Log(LOG_LEVEL_VERBOSE, "Unable to detect environment from cf-monitord");
925  return;
926  }
927 
928  int fd = fileno(fp);
929  if (fstat(fd, &statbuf) == -1)
930  {
931  Log(LOG_LEVEL_VERBOSE, "Unable to detect environment from cf-monitord");
932  fclose(fp);
933  return;
934  }
935 
936  if (statbuf.st_mtime < (now - 60 * 60))
937  {
938  Log(LOG_LEVEL_VERBOSE, "Environment data are too old - discarding");
939  unlink(env);
940  fclose(fp);
941  return;
942  }
943 
944  snprintf(value, CF_MAXVARSIZE - 1, "%s", ctime(&statbuf.st_mtime));
945  if (Chop(value, CF_EXPANDSIZE) == -1)
946  {
947  Log(LOG_LEVEL_ERR, "Chop was called on a string that seemed to have no terminator");
948  }
949 
950  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_MON, "env_time", value, CF_DATA_TYPE_STRING, "time_based,source=agent");
951 
952  Log(LOG_LEVEL_VERBOSE, "Loading environment...");
953 
954  for(;;)
955  {
956  name[0] = '\0';
957  value[0] = '\0';
958 
959  if (fgets(context, sizeof(context), fp) == NULL)
960  {
961  if (ferror(fp))
962  {
963  UnexpectedError("Failed to read line from stream");
964  break;
965  }
966  else /* feof */
967  {
968  break;
969  }
970  }
971 
972 
973  if (*context == '@')
974  {
975  if (sscanf(context + 1, "%[^=]=%[^\n]", name, value) == 2)
976  {
978  "Setting new monitoring list '%s' => '%s'",
979  name, value);
980  Rlist *list = RlistParseShown(value);
982  name, list,
984  "monitoring,source=environment");
985 
986  RlistDestroy(list);
987  }
988  else
989  {
991  "Failed to parse '%s' as '@variable=list' monitoring list",
992  context);
993  }
994  }
995  else if (strchr(context, '='))
996  {
997  if (sscanf(context, "%255[^=]=%255[^\n]", name, value) == 2)
998  {
1000  name, value,
1002  "monitoring,source=environment");
1004  "Setting new monitoring scalar '%s' => '%s'",
1005  name, value);
1006  }
1007  else
1008  {
1010  "Failed to parse '%s' as 'variable=value' monitoring scalar",
1011  context);
1012  }
1013  }
1014  else
1015  {
1016  StripTrailingNewline(context, CF_BUFSIZE);
1017  EvalContextClassPutHard(ctx, context, "monitoring,source=environment");
1018  }
1019  }
1020 
1021  fclose(fp);
1022  Log(LOG_LEVEL_VERBOSE, "Environment data loaded");
1023 
1025 }
1026 
1027 static void BuiltinClasses(EvalContext *ctx)
1028 {
1029  char vbuff[CF_BUFSIZE];
1030 
1031  EvalContextClassPutHard(ctx, "any", "source=agent"); /* This is a reserved word / wildcard */
1032 
1033  snprintf(vbuff, CF_BUFSIZE, "cfengine_%s", CanonifyName(Version()));
1034  CreateHardClassesFromCanonification(ctx, vbuff, "inventory,attribute_name=none,source=agent");
1035 
1036  CreateHardClassesFromFeatures(ctx, "source=agent");
1037 }
1038 
1039 /*******************************************************************/
1040 
1041 void CreateHardClassesFromCanonification(EvalContext *ctx, const char *canonified, char *tags)
1042 {
1043  char buf[CF_MAXVARSIZE];
1044 
1045  strlcpy(buf, canonified, sizeof(buf));
1046 
1047  EvalContextClassPutHard(ctx, buf, tags);
1048 
1049  char *sp;
1050 
1051  while ((sp = strrchr(buf, '_')))
1052  {
1053  *sp = 0;
1054  EvalContextClassPutHard(ctx, buf, tags);
1055  }
1056 }
1057 
1058 static void SetFlavor(EvalContext *ctx, const char *flavor)
1059 {
1060  EvalContextClassPutHard(ctx, flavor, "inventory,attribute_name=none,source=agent,derived-from=sys.flavor");
1061  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "flavour", flavor, CF_DATA_TYPE_STRING, "source=agent");
1062  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "flavor", flavor, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=none");
1063 }
1064 
1065 #ifdef __linux__
1066 
1067 /**
1068  * @brief Combines OS and version string to define flavor variable and class
1069  *
1070  * @note Input strings should be canonified before calling
1071  */
1072 static void SetFlavor2(
1073  EvalContext *const ctx,
1074  const char *const id,
1075  const char *const major_version)
1076 {
1077  assert(ctx != NULL);
1078  assert(id != NULL);
1079  assert(major_version != NULL);
1080 
1081  char *flavor;
1082  xasprintf(&flavor, "%s_%s", id, major_version);
1083  SetFlavor(ctx, flavor);
1084  free(flavor);
1085 }
1086 
1087 /**
1088  * @brief Combines OS and version string to define multiple hard classes
1089  *
1090  * @note Input strings should be canonified before calling
1091  */
1092 static void DefineVersionedHardClasses(
1093  EvalContext *const ctx,
1094  const char *const tags,
1095  const char *const id,
1096  const char *const version)
1097 {
1098  assert(ctx != NULL);
1099  assert(id != NULL);
1100  assert(version != NULL);
1101 
1102  char *class;
1103  xasprintf(&class, "%s_%s", id, version);
1104 
1105  // Strip away version number to define multiple hard classes
1106  // Example: coreos_1185_3_0 -> coreos_1185_3 -> coreos_1185 -> coreos
1107  char *last_underscore = strrchr(class, '_');
1108  while ( last_underscore != NULL )
1109  {
1110  EvalContextClassPutHard(ctx, class, tags);
1111  *last_underscore = '\0';
1112  last_underscore = strrchr(class, '_');
1113  }
1114  EvalContextClassPutHard(ctx, class, tags);
1115  free(class);
1116 }
1117 
1118 static void OSReleaseParse(EvalContext *ctx, const char *file_path)
1119 {
1120  JsonElement *os_release_json = JsonReadDataFile("system info discovery",
1121  file_path, DATAFILETYPE_ENV,
1122  100 * 1024);
1123  if (os_release_json != NULL)
1124  {
1125  char *tags;
1126  xasprintf(&tags,
1127  "inventory,attribute_name=none,source=agent,derived-from-file=%s",
1128  file_path);
1130  os_release_json, CF_DATA_TYPE_CONTAINER,
1131  tags);
1132  const char *const_os_release_id = JsonObjectGetAsString(os_release_json, "ID");
1133  const char *const_os_release_version_id = JsonObjectGetAsString(os_release_json, "VERSION_ID");
1134  char *os_release_id = SafeStringDuplicate(const_os_release_id);
1135  char *os_release_version_id = SafeStringDuplicate(const_os_release_version_id);
1136 
1137  if (os_release_id != NULL)
1138  {
1139  CanonifyNameInPlace(os_release_id);
1140 
1141  const char *alias = NULL;
1142  if (StringEqual(os_release_id, "rhel"))
1143  {
1144  alias = "redhat";
1145  }
1146  else if (StringEqual(os_release_id, "opensuse") ||
1147  StringEqual(os_release_id, "sles"))
1148  {
1149  alias = "suse";
1150  }
1151 
1152  if (os_release_version_id == NULL)
1153  {
1154  // if VERSION_ID doesn't exist, define only one hard class:
1155  EvalContextClassPutHard(ctx, os_release_id, tags);
1156  if (alias != NULL)
1157  {
1158  EvalContextClassPutHard(ctx, alias, tags);
1159  }
1160  }
1161  else // if VERSION_ID exists set flavor and multiple hard classes:
1162  {
1163  CanonifyNameInPlace(os_release_version_id);
1164 
1165  // Set the flavor to be ID + major version (derived from VERSION_ID)
1166  char *first_underscore = strchr(os_release_version_id, '_');
1167  if (first_underscore != NULL)
1168  {
1169  // Temporarily modify os_release_version_id to be major version
1170  *first_underscore = '\0';
1171  SetFlavor2(ctx, os_release_id, os_release_version_id);
1172  *first_underscore = '_';
1173  }
1174  else
1175  {
1176  SetFlavor2(ctx, os_release_id, os_release_version_id);
1177  }
1178 
1179  // One of the hard classes is already set by SetFlavor
1180  // but it seems excessive to try to skip this:
1181  DefineVersionedHardClasses(ctx, tags, os_release_id, os_release_version_id);
1182  if (alias != NULL)
1183  {
1184  DefineVersionedHardClasses(ctx, tags, alias, os_release_version_id);
1185  }
1186  }
1187  }
1188  free(os_release_version_id);
1189  free(os_release_id);
1190  free(tags);
1191  JsonDestroy(os_release_json);
1192  }
1193 }
1194 #endif
1195 
1196 static void OSClasses(EvalContext *ctx)
1197 {
1198 #ifdef __linux__
1199 
1200 /* First we check if init process is systemd, and set "systemd" hard class. */
1201 
1202  {
1203  char init_path[CF_BUFSIZE];
1204  if (ReadLine("/proc/1/cmdline", init_path, sizeof(init_path)))
1205  {
1206  /* Follow possible symlinks. */
1207 
1208  char resolved_path[PATH_MAX]; /* realpath() needs PATH_MAX */
1209  if (realpath(init_path, resolved_path) != NULL &&
1210  strlen(resolved_path) < sizeof(init_path))
1211  {
1212  strcpy(init_path, resolved_path);
1213  }
1214 
1215  /* Check if string ends with "/systemd". */
1216  char *p;
1217  char *next_p = NULL;
1218  const char *term = "/systemd";
1219  do
1220  {
1221  p = next_p;
1222  next_p = strstr(next_p ? next_p+strlen(term) : init_path, term);
1223  }
1224  while (next_p);
1225 
1226  if (p != NULL &&
1227  p[strlen("/systemd")] == '\0')
1228  {
1229  EvalContextClassPutHard(ctx, "systemd",
1230  "inventory,attribute_name=none,source=agent");
1231  }
1232  }
1233  }
1234 
1235 
1236  struct stat statbuf;
1237 
1238  // os-release is used to set sys.os_release, sys.flavor and hard classes
1239  if (access("/etc/os-release", R_OK) != -1)
1240  {
1241  OSReleaseParse(ctx, "/etc/os-release");
1242  }
1243  else if (access("/usr/lib/os-release", R_OK) != -1)
1244  {
1245  OSReleaseParse(ctx, "/usr/lib/os-release");
1246  }
1247 
1248 /* Mandrake/Mandriva, Fedora and Oracle VM Server supply /etc/redhat-release, so
1249  we test for those distributions first */
1250 
1251  if (stat("/etc/mandriva-release", &statbuf) != -1)
1252  {
1253  Linux_Mandriva_Version(ctx);
1254  }
1255  else if (stat("/etc/mandrake-release", &statbuf) != -1)
1256  {
1257  Linux_Mandrake_Version(ctx);
1258  }
1259  else if (stat("/etc/fedora-release", &statbuf) != -1)
1260  {
1261  Linux_Fedora_Version(ctx);
1262  }
1263  else if (stat("/etc/ovs-release", &statbuf) != -1)
1264  {
1265  Linux_Oracle_VM_Server_Version(ctx);
1266  }
1267  else if (stat("/etc/redhat-release", &statbuf) != -1)
1268  {
1269  Linux_Redhat_Version(ctx);
1270  }
1271 
1272 /* Oracle Linux >= 6 supplies separate /etc/oracle-release alongside
1273  /etc/redhat-release, use it to precisely identify version */
1274 
1275  if (stat("/etc/oracle-release", &statbuf) != -1)
1276  {
1277  Linux_Oracle_Version(ctx);
1278  }
1279 
1280  if (stat("/etc/generic-release", &statbuf) != -1)
1281  {
1282  Log(LOG_LEVEL_VERBOSE, "This appears to be a sun cobalt system.");
1283  SetFlavor(ctx, "SunCobalt");
1284  }
1285 
1286  if (stat("/etc/SuSE-release", &statbuf) != -1)
1287  {
1288  Linux_Suse_Version(ctx);
1289  }
1290 
1291  if (stat("/etc/system-release", &statbuf) != -1)
1292  {
1293  Linux_Amazon_Version(ctx);
1294  }
1295 
1296 # define SLACKWARE_ANCIENT_VERSION_FILENAME "/etc/slackware-release"
1297 # define SLACKWARE_VERSION_FILENAME "/etc/slackware-version"
1298  if (stat(SLACKWARE_VERSION_FILENAME, &statbuf) != -1)
1299  {
1300  Linux_Slackware_Version(ctx, SLACKWARE_VERSION_FILENAME);
1301  }
1302  else if (stat(SLACKWARE_ANCIENT_VERSION_FILENAME, &statbuf) != -1)
1303  {
1304  Linux_Slackware_Version(ctx, SLACKWARE_ANCIENT_VERSION_FILENAME);
1305  }
1306 
1307  if (stat(DEBIAN_VERSION_FILENAME, &statbuf) != -1)
1308  {
1309  Linux_Debian_Version(ctx);
1310  }
1311 
1312  if (stat(LSB_RELEASE_FILENAME, &statbuf) != -1)
1313  {
1314  Linux_Misc_Version(ctx);
1315  }
1316 
1317  if (stat("/usr/bin/aptitude", &statbuf) != -1)
1318  {
1319  Log(LOG_LEVEL_VERBOSE, "This system seems to have the aptitude package system");
1320  EvalContextClassPutHard(ctx, "have_aptitude", "inventory,attribute_name=none,source=agent");
1321  }
1322 
1323  if (stat("/etc/UnitedLinux-release", &statbuf) != -1)
1324  {
1325  Log(LOG_LEVEL_VERBOSE, "This appears to be a UnitedLinux system.");
1326  SetFlavor(ctx, "UnitedLinux");
1327  }
1328 
1329  if (stat("/etc/alpine-release", &statbuf) != -1)
1330  {
1331  Linux_Alpine_Version(ctx);
1332  }
1333 
1334  if (stat("/etc/gentoo-release", &statbuf) != -1)
1335  {
1336  Log(LOG_LEVEL_VERBOSE, "This appears to be a gentoo system.");
1337  SetFlavor(ctx, "gentoo");
1338  }
1339 
1340  if (stat("/etc/arch-release", &statbuf) != -1)
1341  {
1342  Log(LOG_LEVEL_VERBOSE, "This appears to be an Arch Linux system.");
1343  SetFlavor(ctx, "archlinux");
1344  }
1345 
1346  if (stat("/proc/vmware/version", &statbuf) != -1 || stat("/etc/vmware-release", &statbuf) != -1)
1347  {
1348  VM_Version(ctx);
1349  }
1350  else if (stat("/etc/vmware", &statbuf) != -1 && S_ISDIR(statbuf.st_mode))
1351  {
1352  VM_Version(ctx);
1353  }
1354 
1355  if (stat("/proc/xen/capabilities", &statbuf) != -1)
1356  {
1357  Xen_Domain(ctx);
1358  }
1359  if (stat("/etc/Eos-release", &statbuf) != -1)
1360  {
1361  EOS_Version(ctx);
1362  SetFlavor(ctx, "Eos");
1363  }
1364 
1365  if (stat("/etc/issue", &statbuf) != -1)
1366  {
1367  MiscOS(ctx);
1368  }
1369 
1370  if (stat("/proc/self/status", &statbuf) != -1)
1371  {
1372  OpenVZ_Detect(ctx);
1373  }
1374 
1375 #else
1376 
1377  char vbuff[CF_MAXVARSIZE];
1378 
1379 #ifdef _AIX
1381 #else
1383 #endif
1384 
1385 
1386  for (char *sp = vbuff; *sp != '\0'; sp++)
1387  {
1388  if (*sp == '-')
1389  {
1390  *sp = '\0';
1391  break;
1392  }
1393  }
1394 
1395  char context[CF_BUFSIZE];
1396  snprintf(context, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, vbuff);
1397  SetFlavor(ctx, context);
1398 
1399 
1400 #ifdef __hpux
1401  /*
1402  * Define a hard class with just the version major number of HP-UX
1403  *
1404  * For example, when being run on HP-UX B.11.23 the following class will
1405  * be defined: hpux_11
1406  */
1407 
1408  // Extract major version number
1409  char *major = NULL;
1410  for (char *sp = vbuff; *sp != '\0'; sp++)
1411  {
1412  if (major == NULL && isdigit(*sp))
1413  {
1414  major = sp;
1415  }
1416  else if (!isdigit(*sp))
1417  {
1418  *sp = '\0';
1419  }
1420  }
1421 
1422  if (major != NULL)
1423  {
1424  snprintf(context, CF_BUFSIZE, "hpux_%s", major);
1425  EvalContextClassPutHard(ctx, context, "source=agent,derived-from=sys.flavor");
1426  }
1427 #endif
1428 
1429 #ifdef __FreeBSD__
1430  /*
1431  * Define a hard class with just the version major number on FreeBSD
1432  *
1433  * For example, when being run on either FreeBSD 10.0 or 10.1 a class
1434  * called freebsd_10 will be defined
1435  */
1436  for (char *sp = vbuff; *sp != '\0'; sp++)
1437  {
1438  if (*sp == '.')
1439  {
1440  *sp = '\0';
1441  break;
1442  }
1443  }
1444 
1445  snprintf(context, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, vbuff);
1446  EvalContextClassPutHard(ctx, context, "source=agent,derived-from=sys.flavor");
1447 #endif
1448 
1449 #endif
1450 
1451 #ifdef XEN_CPUID_SUPPORT
1452  if (Xen_Hv_Check())
1453  {
1454  Log(LOG_LEVEL_VERBOSE, "This appears to be a xen hv system.");
1455  EvalContextClassPutHard(ctx, "xen", "inventory,attribute_name=Virtual host,source=agent");
1456  EvalContextClassPutHard(ctx, "xen_domu_hv", "source=agent");
1457  }
1458 #endif /* XEN_CPUID_SUPPORT */
1459 
1460  GetCPUInfo(ctx);
1461 
1462 #ifdef __CYGWIN__
1463 
1464  for (char *sp = VSYSNAME.sysname; *sp != '\0'; sp++)
1465  {
1466  if (*sp == '-')
1467  {
1468  sp++;
1469  if (strncmp(sp, "5.0", 3) == 0)
1470  {
1471  Log(LOG_LEVEL_VERBOSE, "This appears to be Windows 2000");
1472  EvalContextClassPutHard(ctx, "Win2000", "inventory,attribute_name=none,source=agent");
1473  }
1474 
1475  if (strncmp(sp, "5.1", 3) == 0)
1476  {
1477  Log(LOG_LEVEL_VERBOSE, "This appears to be Windows XP");
1478  EvalContextClassPutHard(ctx, "WinXP", "inventory,attribute_name=none,source=agent");
1479  }
1480 
1481  if (strncmp(sp, "5.2", 3) == 0)
1482  {
1483  Log(LOG_LEVEL_VERBOSE, "This appears to be Windows Server 2003");
1484  EvalContextClassPutHard(ctx, "WinServer2003", "inventory,attribute_name=none,source=agent");
1485  }
1486 
1487  if (strncmp(sp, "6.1", 3) == 0)
1488  {
1489  Log(LOG_LEVEL_VERBOSE, "This appears to be Windows Vista");
1490  EvalContextClassPutHard(ctx, "WinVista", "inventory,attribute_name=none,source=agent");
1491  }
1492 
1493  if (strncmp(sp, "6.3", 3) == 0)
1494  {
1495  Log(LOG_LEVEL_VERBOSE, "This appears to be Windows Server 2008");
1496  EvalContextClassPutHard(ctx, "WinServer2008", "inventory,attribute_name=none,source=agent");
1497  }
1498  }
1499  }
1500 
1501  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "crontab", "", CF_DATA_TYPE_STRING, "source=agent");
1502 
1503 #endif /* __CYGWIN__ */
1504 
1505 #ifdef __MINGW32__
1506  EvalContextClassPutHard(ctx, VSYSNAME.release, "inventory,attribute_name=none,source=agent,derived-from=sys.release"); // code name - e.g. Windows Vista
1507  EvalContextClassPutHard(ctx, VSYSNAME.version, "inventory,attribute_name=none,source=agent,derived-from=sys.version"); // service pack number - e.g. Service Pack 3
1508 
1509  if (strstr(VSYSNAME.sysname, "workstation"))
1510  {
1511  EvalContextClassPutHard(ctx, "WinWorkstation", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1512  }
1513  else if (strstr(VSYSNAME.sysname, "server"))
1514  {
1515  EvalContextClassPutHard(ctx, "WinServer", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1516  }
1517  else if (strstr(VSYSNAME.sysname, "domain controller"))
1518  {
1519  EvalContextClassPutHard(ctx, "DomainController", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1520  EvalContextClassPutHard(ctx, "WinServer", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1521  }
1522  else
1523  {
1524  EvalContextClassPutHard(ctx, "unknown_ostype", "source=agent,derived-from=sys.sysname");
1525  }
1526 
1527  SetFlavor(ctx, "windows");
1528 
1529 #endif /* __MINGW32__ */
1530 
1531 #ifndef _WIN32
1532  struct passwd *pw;
1533  if ((pw = getpwuid(getuid())) == NULL)
1534  {
1535  Log(LOG_LEVEL_ERR, "Unable to get username for uid '%ju'. (getpwuid: %s)", (uintmax_t)getuid(), GetErrorStr());
1536  }
1537  else
1538  {
1539  char vbuff[CF_BUFSIZE];
1540 
1541  if (EvalContextClassGet(ctx, NULL, "SUSE"))
1542  {
1543  snprintf(vbuff, CF_BUFSIZE, "/var/spool/cron/tabs/%s", pw->pw_name);
1544  }
1545  else if (EvalContextClassGet(ctx, NULL, "redhat"))
1546  {
1547  snprintf(vbuff, CF_BUFSIZE, "/var/spool/cron/%s", pw->pw_name);
1548  }
1549  else if (EvalContextClassGet(ctx, NULL, "freebsd"))
1550  {
1551  snprintf(vbuff, CF_BUFSIZE, "/var/cron/tabs/%s", pw->pw_name);
1552  }
1553  else
1554  {
1555  snprintf(vbuff, CF_BUFSIZE, "/var/spool/cron/crontabs/%s", pw->pw_name);
1556  }
1557 
1558  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "crontab", vbuff, CF_DATA_TYPE_STRING, "source=agent");
1559  }
1560 
1561 #endif
1562 
1563 #if defined(__ANDROID__)
1564  SetFlavor(ctx, "android");
1565 #endif
1566 
1567 #ifdef __sun
1568  if (StringMatchFull("joyent.*", VSYSNAME.version))
1569  {
1570  EvalContextClassPutHard(ctx, "smartos", "inventory,attribute_name=none,source=agent,derived-from=sys.version");
1571  EvalContextClassPutHard(ctx, "smartmachine", "source=agent,derived-from=sys.version");
1572  }
1573 #endif
1574 
1575  /* FIXME: this variable needs redhat/SUSE/debian classes to be defined and
1576  * hence can't be initialized earlier */
1577 
1578  if (EvalContextClassGet(ctx, NULL, "redhat"))
1579  {
1580  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "doc_root", "/var/www/html", CF_DATA_TYPE_STRING, "source=agent");
1581  }
1582 
1583  if (EvalContextClassGet(ctx, NULL, "SUSE"))
1584  {
1585  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "doc_root", "/srv/www/htdocs", CF_DATA_TYPE_STRING, "source=agent");
1586  }
1587 
1588  if (EvalContextClassGet(ctx, NULL, "debian"))
1589  {
1590  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "doc_root", "/var/www", CF_DATA_TYPE_STRING, "source=agent");
1591  }
1592 }
1593 
1594 /*********************************************************************************/
1595 
1596 #ifdef __linux__
1597 static void Linux_Oracle_VM_Server_Version(EvalContext *ctx)
1598 {
1599  char relstring[CF_MAXVARSIZE];
1600  char *r;
1601  int major, minor, patch;
1602  int revcomps;
1603 
1604 #define ORACLE_VM_SERVER_REL_FILENAME "/etc/ovs-release"
1605 #define ORACLE_VM_SERVER_ID "Oracle VM server"
1606 
1607  Log(LOG_LEVEL_VERBOSE, "This appears to be Oracle VM Server");
1608  EvalContextClassPutHard(ctx, "redhat", "inventory,attribute_name=none,source=agent");
1609  EvalContextClassPutHard(ctx, "oraclevmserver", "inventory,attribute_name=Virtual host,source=agent");
1610 
1611  if (!ReadLine(ORACLE_VM_SERVER_REL_FILENAME, relstring, sizeof(relstring)))
1612  {
1613  return;
1614  }
1615 
1616  if (strncmp(relstring, ORACLE_VM_SERVER_ID, strlen(ORACLE_VM_SERVER_ID)))
1617  {
1618  Log(LOG_LEVEL_VERBOSE, "Could not identify distribution from %s", ORACLE_VM_SERVER_REL_FILENAME);
1619  return;
1620  }
1621 
1622  if ((r = strstr(relstring, "release ")) == NULL)
1623  {
1624  Log(LOG_LEVEL_VERBOSE, "Could not find distribution version in %s", ORACLE_VM_SERVER_REL_FILENAME);
1625  return;
1626  }
1627 
1628  revcomps = sscanf(r + strlen("release "), "%d.%d.%d", &major, &minor, &patch);
1629 
1630  if (revcomps > 0)
1631  {
1632  char buf[CF_BUFSIZE];
1633 
1634  snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d", major);
1635  SetFlavor(ctx, buf);
1636  }
1637 
1638  if (revcomps > 1)
1639  {
1640  char buf[CF_BUFSIZE];
1641 
1642  snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d_%d", major, minor);
1643  EvalContextClassPutHard(ctx, buf, "inventory,attribute_name=none,source=agent");
1644  }
1645 
1646  if (revcomps > 2)
1647  {
1648  char buf[CF_BUFSIZE];
1649 
1650  snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d_%d_%d", major, minor, patch);
1651  EvalContextClassPutHard(ctx, buf, "inventory,attribute_name=none,source=agent");
1652  }
1653 }
1654 
1655 /*********************************************************************************/
1656 
1657 static void Linux_Oracle_Version(EvalContext *ctx)
1658 {
1659  char relstring[CF_MAXVARSIZE];
1660  char *r;
1661  int major, minor;
1662 
1663 #define ORACLE_REL_FILENAME "/etc/oracle-release"
1664 #define ORACLE_ID "Oracle Linux Server"
1665 
1666  Log(LOG_LEVEL_VERBOSE, "This appears to be Oracle Linux");
1667  EvalContextClassPutHard(ctx, "oracle", "inventory,attribute_name=none,source=agent");
1668 
1669  if (!ReadLine(ORACLE_REL_FILENAME, relstring, sizeof(relstring)))
1670  {
1671  return;
1672  }
1673 
1674  if (strncmp(relstring, ORACLE_ID, strlen(ORACLE_ID)))
1675  {
1676  Log(LOG_LEVEL_VERBOSE, "Could not identify distribution from %s", ORACLE_REL_FILENAME);
1677  return;
1678  }
1679 
1680  if ((r = strstr(relstring, "release ")) == NULL)
1681  {
1682  Log(LOG_LEVEL_VERBOSE, "Could not find distribution version in %s", ORACLE_REL_FILENAME);
1683  return;
1684  }
1685 
1686  if (sscanf(r + strlen("release "), "%d.%d", &major, &minor) == 2)
1687  {
1688  char buf[CF_BUFSIZE];
1689 
1690  snprintf(buf, CF_BUFSIZE, "oracle_%d", major);
1691  SetFlavor(ctx, buf);
1692 
1693  snprintf(buf, CF_BUFSIZE, "oracle_%d_%d", major, minor);
1694  EvalContextClassPutHard(ctx, buf, "inventory,attribute_name=none,source=agent");
1695  }
1696 }
1697 
1698 /*********************************************************************************/
1699 
1700 static int Linux_Fedora_Version(EvalContext *ctx)
1701 {
1702 #define FEDORA_ID "Fedora"
1703 #define RELEASE_FLAG "release "
1704 
1705 /* We are looking for one of the following strings...
1706  *
1707  * Fedora Core release 1 (Yarrow)
1708  * Fedora release 7 (Zodfoobar)
1709  */
1710 
1711 #define FEDORA_REL_FILENAME "/etc/fedora-release"
1712 
1713 /* The full string read in from fedora-release */
1714  char relstring[CF_MAXVARSIZE];
1715 
1716  Log(LOG_LEVEL_VERBOSE, "This appears to be a fedora system.");
1717  EvalContextClassPutHard(ctx, "redhat", "inventory,attribute_name=none,source=agent");
1718  EvalContextClassPutHard(ctx, "fedora", "inventory,attribute_name=none,source=agent");
1719 
1720 /* Grab the first line from the file and then close it. */
1721 
1722  if (!ReadLine(FEDORA_REL_FILENAME, relstring, sizeof(relstring)))
1723  {
1724  return 1;
1725  }
1726 
1727  Log(LOG_LEVEL_VERBOSE, "Looking for fedora core linux info...");
1728 
1729  char *vendor = "";
1730  if (!strncmp(relstring, FEDORA_ID, strlen(FEDORA_ID)))
1731  {
1732  vendor = "fedora";
1733  }
1734  else
1735  {
1736  Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from %s", FEDORA_REL_FILENAME);
1737  return 2;
1738  }
1739 
1740 /* Now, grok the release. We assume that all the strings will
1741  * have the word 'release' before the numerical release.
1742  */
1743  int major = -1;
1744  char strmajor[PRINTSIZE(major)];
1745  char *release = strstr(relstring, RELEASE_FLAG);
1746 
1747  if (release == NULL)
1748  {
1749  Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", FEDORA_REL_FILENAME);
1750  return 2;
1751  }
1752  else
1753  {
1754  release += strlen(RELEASE_FLAG);
1755 
1756  strmajor[0] = '\0';
1757  if (sscanf(release, "%d", &major) != 0)
1758  {
1759  xsnprintf(strmajor, sizeof(strmajor), "%d", major);
1760  }
1761  }
1762 
1763  if (major != -1 && vendor[0] != '\0')
1764  {
1765  char classbuf[CF_MAXVARSIZE];
1766  classbuf[0] = '\0';
1767  strcat(classbuf, vendor);
1768  EvalContextClassPutHard(ctx,classbuf, "inventory,attribute_name=none,source=agent");
1769  strcat(classbuf, "_");
1770  strcat(classbuf, strmajor);
1771  SetFlavor(ctx, classbuf);
1772  }
1773 
1774  return 0;
1775 }
1776 
1777 /*********************************************************************************/
1778 
1779 static int Linux_Redhat_Version(EvalContext *ctx)
1780 {
1781 #define REDHAT_ID "Red Hat Linux"
1782 #define REDHAT_ENT_ID "Red Hat Enterprise Linux"
1783 #define REDHAT_AS_ID "Red Hat Enterprise Linux AS"
1784 #define REDHAT_AS21_ID "Red Hat Linux Advanced Server"
1785 #define REDHAT_ES_ID "Red Hat Enterprise Linux ES"
1786 #define REDHAT_WS_ID "Red Hat Enterprise Linux WS"
1787 #define REDHAT_C_ID "Red Hat Enterprise Linux Client"
1788 #define REDHAT_S_ID "Red Hat Enterprise Linux Server"
1789 #define REDHAT_W_ID "Red Hat Enterprise Linux Workstation"
1790 #define REDHAT_CN_ID "Red Hat Enterprise Linux ComputeNode"
1791 #define MANDRAKE_ID "Linux Mandrake"
1792 #define MANDRAKE_10_1_ID "Mandrakelinux"
1793 #define WHITEBOX_ID "White Box Enterprise Linux"
1794 #define CENTOS_ID "CentOS"
1795 #define SCIENTIFIC_SL_ID "Scientific Linux SL"
1796 #define SCIENTIFIC_SL6_ID "Scientific Linux"
1797 #define SCIENTIFIC_CERN_ID "Scientific Linux CERN"
1798 #define RELEASE_FLAG "release "
1799 #define ORACLE_4_5_ID "Enterprise Linux Enterprise Linux Server"
1800 
1801 /* We are looking for one of the following strings...
1802  *
1803  * Red Hat Linux release 6.2 (Zoot)
1804  * Red Hat Enterprise Linux release 8.0 (Ootpa)
1805  * Red Hat Linux Advanced Server release 2.1AS (Pensacola)
1806  * Red Hat Enterprise Linux AS release 3 (Taroon)
1807  * Red Hat Enterprise Linux WS release 3 (Taroon)
1808  * Red Hat Enterprise Linux Client release 5 (Tikanga)
1809  * Red Hat Enterprise Linux Server release 5 (Tikanga)
1810  * Linux Mandrake release 7.1 (helium)
1811  * Red Hat Enterprise Linux ES release 2.1 (Panama)
1812  * White Box Enterprise linux release 3.0 (Liberation)
1813  * Scientific Linux SL Release 4.0 (Beryllium)
1814  * CentOS release 4.0 (Final)
1815  */
1816 
1817 #define RH_REL_FILENAME "/etc/redhat-release"
1818 
1819  Log(LOG_LEVEL_VERBOSE, "This appears to be a redhat (or redhat-based) system.");
1820  EvalContextClassPutHard(ctx, "redhat", "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1821 
1822  /* Grab the first line from the file and then close it. */
1823  char relstring[CF_MAXVARSIZE];
1824  if (!ReadLine(RH_REL_FILENAME, relstring, sizeof(relstring)))
1825  {
1826  return 1;
1827  }
1828 
1829  Log(LOG_LEVEL_VERBOSE, "Looking for redhat linux info in '%s'", relstring);
1830 
1831  /* First, try to grok the vendor and edition (if any) */
1832  char *edition = ""; /* as (Advanced Server, Enterprise) */
1833  char *vendor = ""; /* Red Hat, Mandrake */
1834  if (!strncmp(relstring, REDHAT_ES_ID, strlen(REDHAT_ES_ID)))
1835  {
1836  vendor = "redhat";
1837  edition = "es";
1838  }
1839  else if (!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
1840  {
1841  vendor = "redhat";
1842  edition = "ws";
1843  }
1844  else if (!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
1845  {
1846  vendor = "redhat";
1847  edition = "ws";
1848  }
1849  else if (!strncmp(relstring, REDHAT_AS_ID, strlen(REDHAT_AS_ID)) ||
1850  !strncmp(relstring, REDHAT_AS21_ID, strlen(REDHAT_AS21_ID)))
1851  {
1852  vendor = "redhat";
1853  edition = "as";
1854  }
1855  else if (!strncmp(relstring, REDHAT_S_ID, strlen(REDHAT_S_ID)))
1856  {
1857  vendor = "redhat";
1858  edition = "s";
1859  }
1860  else if (!strncmp(relstring, REDHAT_C_ID, strlen(REDHAT_C_ID))
1861  || !strncmp(relstring, REDHAT_W_ID, strlen(REDHAT_W_ID)))
1862  {
1863  vendor = "redhat";
1864  edition = "c";
1865  }
1866  else if (!strncmp(relstring, REDHAT_CN_ID, strlen(REDHAT_CN_ID)))
1867  {
1868  vendor = "redhat";
1869  edition = "cn";
1870  }
1871  else if (!strncmp(relstring, REDHAT_ID, strlen(REDHAT_ID)))
1872  {
1873  vendor = "redhat";
1874  }
1875  else if (!strncmp(relstring, REDHAT_ENT_ID, strlen(REDHAT_ENT_ID)))
1876  {
1877  vendor = "redhat";
1878  }
1879  else if (!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
1880  {
1881  vendor = "mandrake";
1882  }
1883  else if (!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
1884  {
1885  vendor = "mandrake";
1886  }
1887  else if (!strncmp(relstring, WHITEBOX_ID, strlen(WHITEBOX_ID)))
1888  {
1889  vendor = "whitebox";
1890  }
1891  else if (!strncmp(relstring, SCIENTIFIC_SL_ID, strlen(SCIENTIFIC_SL_ID)))
1892  {
1893  vendor = "scientific";
1894  edition = "sl";
1895  }
1896  else if (!strncmp(relstring, SCIENTIFIC_CERN_ID, strlen(SCIENTIFIC_CERN_ID)))
1897  {
1898  vendor = "scientific";
1899  edition = "cern";
1900  }
1901  else if (!strncmp(relstring, SCIENTIFIC_SL6_ID, strlen(SCIENTIFIC_SL6_ID)))
1902  {
1903  vendor = "scientific";
1904  edition = "sl";
1905  }
1906  else if (!strncmp(relstring, CENTOS_ID, strlen(CENTOS_ID)))
1907  {
1908  vendor = "centos";
1909  }
1910  else if (!strncmp(relstring, ORACLE_4_5_ID, strlen(ORACLE_4_5_ID)))
1911  {
1912  vendor = "oracle";
1913  edition = "s";
1914  }
1915  else
1916  {
1917  Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from %s", RH_REL_FILENAME);
1918  return 2;
1919  }
1920 
1921 /* Now, grok the release. For AS, we neglect the AS at the end of the
1922  * numerical release because we already figured out that it *is* AS
1923  * from the information above. We assume that all the strings will
1924  * have the word 'release' before the numerical release.
1925  */
1926 
1927 /* Convert relstring to lowercase so that vendors like
1928  Scientific Linux don't fall through the cracks.
1929  */
1930 
1931  for (int i = 0; i < strlen(relstring); i++)
1932  {
1933  relstring[i] = tolower(relstring[i]);
1934  }
1935 
1936  /* Where the numerical release will be found */
1937  int major = -1, minor = -1;
1938  char strmajor[PRINTSIZE(major)], strminor[PRINTSIZE(minor)];
1939 
1940  char *release = strstr(relstring, RELEASE_FLAG);
1941  if (release == NULL)
1942  {
1943  Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", RH_REL_FILENAME);
1944  return 2;
1945  }
1946  else
1947  {
1948  release += strlen(RELEASE_FLAG);
1949  if (sscanf(release, "%d.%d", &major, &minor) == 2)
1950  {
1951  xsnprintf(strmajor, sizeof(strmajor), "%d", major);
1952  xsnprintf(strminor, sizeof(strminor), "%d", minor);
1953  }
1954  /* red hat 9 is *not* red hat 9.0.
1955  * and same thing with RHEL AS 3
1956  */
1957  else if (sscanf(release, "%d", &major) == 1)
1958  {
1959  xsnprintf(strmajor, sizeof(strmajor), "%d", major);
1960  minor = -2;
1961  }
1962  }
1963 
1964  char classbuf[CF_MAXVARSIZE];
1965  if (major != -1 && minor != -1 && (strcmp(vendor, "") != 0))
1966  {
1967  classbuf[0] = '\0';
1968  strcat(classbuf, vendor);
1969  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1970  strcat(classbuf, "_");
1971 
1972  if (strcmp(edition, "") != 0)
1973  {
1974  strcat(classbuf, edition);
1975  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1976  strcat(classbuf, "_");
1977  }
1978 
1979  strcat(classbuf, strmajor);
1980  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1981 
1982  if (minor != -2)
1983  {
1984  strcat(classbuf, "_");
1985  strcat(classbuf, strminor);
1986  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1987  }
1988  }
1989 
1990  // Now a version without the edition
1991  if (major != -1 && minor != -1 && vendor[0] != '\0')
1992  {
1993  classbuf[0] = '\0';
1994  strcat(classbuf, vendor);
1995  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1996  strcat(classbuf, "_");
1997 
1998  strcat(classbuf, strmajor);
1999 
2000  SetFlavor(ctx, classbuf);
2001 
2002  if (minor != -2)
2003  {
2004  strcat(classbuf, "_");
2005  strcat(classbuf, strminor);
2006  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
2007  }
2008  }
2009 
2010  return 0;
2011 }
2012 
2013 /******************************************************************/
2014 
2015 static int Linux_Suse_Version(EvalContext *ctx)
2016 {
2017 #define SUSE_REL_FILENAME "/etc/SuSE-release"
2018 /* Check if it's a SUSE Enterprise version (all in lowercase) */
2019 #define SUSE_SLES8_ID "suse sles-8"
2020 #define SUSE_SLES_ID "suse linux enterprise server"
2021 #define SUSE_SLED_ID "suse linux enterprise desktop"
2022 #define SUSE_RELEASE_FLAG "linux "
2023 
2024  char classbuf[CF_MAXVARSIZE];
2025 
2026  Log(LOG_LEVEL_VERBOSE, "This appears to be a SUSE system.");
2027  EvalContextClassPutHard(ctx, "SUSE", "inventory,attribute_name=none,source=agent");
2028  EvalContextClassPutHard(ctx, "suse", "inventory,attribute_name=none,source=agent");
2029 
2030  /* The correct spelling for SUSE is "SUSE" but CFEngine used to use "SuSE".
2031  * Keep this for backwards compatibility until CFEngine 3.7
2032  */
2033  EvalContextClassPutHard(ctx, "SuSE", "inventory,attribute_name=none,source=agent");
2034 
2035  /* Grab the first line from the SuSE-release file and then close it. */
2036  char relstring[CF_MAXVARSIZE];
2037 
2038  FILE *fp = ReadFirstLine(SUSE_REL_FILENAME, relstring, sizeof(relstring));
2039  if (fp == NULL)
2040  {
2041  return 1;
2042  }
2043 
2044  char vbuf[CF_BUFSIZE], strversion[CF_MAXVARSIZE], strpatch[CF_MAXVARSIZE];
2045  strversion[0] = '\0';
2046  strpatch[0] = '\0';
2047 
2048  int major = -1, minor = -1;
2049  while (fgets(vbuf, sizeof(vbuf), fp) != NULL)
2050  {
2051  if (strncmp(vbuf, "VERSION", strlen("version")) == 0)
2052  {
2053  strlcpy(strversion, vbuf, sizeof(strversion));
2054  sscanf(vbuf, "VERSION = %d", &major);
2055  }
2056 
2057  if (strncmp(vbuf, "PATCH", strlen("PATCH")) == 0)
2058  {
2059  strlcpy(strpatch, vbuf, sizeof(strpatch));
2060  sscanf(vbuf, "PATCHLEVEL = %d", &minor);
2061  }
2062  }
2063  if (ferror(fp))
2064  {
2065  UnexpectedError("Failed to read line from stream");
2066  }
2067  else
2068  {
2069  assert(feof(fp));
2070  }
2071 
2072  fclose(fp);
2073 
2074  /* Check if it's a SUSE Enterprise version */
2075 
2076  Log(LOG_LEVEL_VERBOSE, "Looking for SUSE enterprise info in '%s'", relstring);
2077 
2078  /* Convert relstring to lowercase to handle rename of SuSE to
2079  * SUSE with SUSE 10.0.
2080  */
2081 
2082  for (int i = 0; i < strlen(relstring); i++)
2083  {
2084  relstring[i] = tolower(relstring[i]);
2085  }
2086 
2087  /* Check if it's a SUSE Enterprise version (all in lowercase) */
2088 
2089  if (!strncmp(relstring, SUSE_SLES8_ID, strlen(SUSE_SLES8_ID)))
2090  {
2091  classbuf[0] = '\0';
2092  strcat(classbuf, "SLES8");
2093  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2094  }
2095  else if (strncmp(relstring, "sles", 4) == 0)
2096  {
2097  Item *list, *ip;
2098 
2099  sscanf(relstring, "%[-_a-zA-Z0-9]", vbuf);
2100  EvalContextClassPutHard(ctx, vbuf, "inventory,attribute_name=none,source=agent");
2101 
2102  list = SplitString(vbuf, '-');
2103 
2104  for (ip = list; ip != NULL; ip = ip->next)
2105  {
2106  EvalContextClassPutHard(ctx, ip->name, "inventory,attribute_name=none,source=agent");
2107  }
2108 
2109  DeleteItemList(list);
2110  }
2111  else
2112  {
2113  for (int version = 9; version < 13; version++)
2114  {
2115  snprintf(vbuf, CF_BUFSIZE, "%s %d ", SUSE_SLES_ID, version);
2116  Log(LOG_LEVEL_DEBUG, "Checking for SUSE [%s]", vbuf);
2117 
2118  if (!strncmp(relstring, vbuf, strlen(vbuf)))
2119  {
2120  snprintf(classbuf, CF_MAXVARSIZE, "SLES%d", version);
2121  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2122  }
2123  else
2124  {
2125  snprintf(vbuf, CF_BUFSIZE, "%s %d ", SUSE_SLED_ID, version);
2126  Log(LOG_LEVEL_DEBUG, "Checking for SUSE [%s]", vbuf);
2127 
2128  if (!strncmp(relstring, vbuf, strlen(vbuf)))
2129  {
2130  snprintf(classbuf, CF_MAXVARSIZE, "SLED%d", version);
2131  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2132  }
2133  }
2134  }
2135  }
2136 
2137  /* Determine release version. We assume that the version follows
2138  * the string "SuSE Linux" or "SUSE LINUX".
2139  */
2140 
2141  char *release = strstr(relstring, SUSE_RELEASE_FLAG);
2142  if (release == NULL)
2143  {
2144  release = strstr(relstring, "opensuse");
2145  if (release == NULL)
2146  {
2147  release = strversion;
2148  }
2149  }
2150 
2151  if (release == NULL)
2152  {
2154  "Could not find a numeric OS release in %s",
2155  SUSE_REL_FILENAME);
2156  return 2;
2157  }
2158  else
2159  {
2160  char strmajor[PRINTSIZE(major)], strminor[PRINTSIZE(minor)];
2161  if (strchr(release, '.'))
2162  {
2163  sscanf(release, "%*s %d.%d", &major, &minor);
2164  xsnprintf(strmajor, sizeof(strmajor), "%d", major);
2165  xsnprintf(strminor, sizeof(strminor), "%d", minor);
2166 
2167  if (major != -1 && minor != -1)
2168  {
2169  strcpy(classbuf, "SUSE");
2170  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2171  strcat(classbuf, "_");
2172  strcat(classbuf, strmajor);
2173  SetFlavor(ctx, classbuf);
2174  strcat(classbuf, "_");
2175  strcat(classbuf, strminor);
2176  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2177 
2178  /* The correct spelling for SUSE is "SUSE" but CFEngine used to use "SuSE".
2179  * Keep this for backwards compatibility until CFEngine 3.7
2180  */
2181  strcpy(classbuf, "SuSE");
2182  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2183  strcat(classbuf, "_");
2184  strcat(classbuf, strmajor);
2185  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2186  strcat(classbuf, "_");
2187  strcat(classbuf, strminor);
2188  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2189 
2190  Log(LOG_LEVEL_VERBOSE, "Discovered SUSE version %s", classbuf);
2191  return 0;
2192  }
2193  }
2194  else
2195  {
2196  sscanf(strversion, "VERSION = %s", strmajor);
2197  sscanf(strpatch, "PATCHLEVEL = %s", strminor);
2198 
2199  if (major != -1 && minor != -1)
2200  {
2201  strcpy(classbuf, "SLES");
2202  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2203  strcat(classbuf, "_");
2204  strcat(classbuf, strmajor);
2205  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2206  strcat(classbuf, "_");
2207  strcat(classbuf, strminor);
2208  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2209 
2210  snprintf(classbuf, CF_MAXVARSIZE, "SUSE_%d", major);
2211  SetFlavor(ctx, classbuf);
2212 
2213  /* The correct spelling for SUSE is "SUSE" but CFEngine used to use "SuSE".
2214  * Keep this for backwards compatibility until CFEngine 3.7
2215  */
2216  snprintf(classbuf, CF_MAXVARSIZE, "SuSE_%d", major);
2217  EvalContextClassPutHard(ctx, classbuf, "source=agent");
2218 
2219  Log(LOG_LEVEL_VERBOSE, "Discovered SUSE version %s", classbuf);
2220  return 0;
2221  }
2222  }
2223  }
2224 
2225  Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", SUSE_REL_FILENAME);
2226 
2227  return 0;
2228 }
2229 
2230 /******************************************************************/
2231 
2232 static int Linux_Slackware_Version(EvalContext *ctx, char *filename)
2233 {
2234  int major = -1;
2235  int minor = -1;
2236  int release = -1;
2237  char classname[CF_MAXVARSIZE] = "";
2238  char buffer[CF_MAXVARSIZE];
2239 
2240  Log(LOG_LEVEL_VERBOSE, "This appears to be a slackware system.");
2241  EvalContextClassPutHard(ctx, "slackware", "inventory,attribute_name=none,source=agent");
2242 
2243  if (!ReadLine(filename, buffer, sizeof(buffer)))
2244  {
2245  return 1;
2246  }
2247 
2248  Log(LOG_LEVEL_VERBOSE, "Looking for Slackware version...");
2249  switch (sscanf(buffer, "Slackware %d.%d.%d", &major, &minor, &release))
2250  {
2251  case 3:
2252  Log(LOG_LEVEL_VERBOSE, "This appears to be a Slackware %u.%u.%u system.", major, minor, release);
2253  snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u_%u", major, minor, release);
2254  EvalContextClassPutHard(ctx, classname, "inventory,attribute_name=none,source=agent");
2255  /* Fall-through */
2256  case 2:
2257  Log(LOG_LEVEL_VERBOSE, "This appears to be a Slackware %u.%u system.", major, minor);
2258  snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u", major, minor);
2259  EvalContextClassPutHard(ctx, classname, "inventory,attribute_name=none,source=agent");
2260  /* Fall-through */
2261  case 1:
2262  Log(LOG_LEVEL_VERBOSE, "This appears to be a Slackware %u system.", major);
2263  snprintf(classname, CF_MAXVARSIZE, "slackware_%u", major);
2264  EvalContextClassPutHard(ctx, classname, "inventory,attribute_name=none,source=agent");
2265  break;
2266  case 0:
2267  Log(LOG_LEVEL_VERBOSE, "No Slackware version number found.");
2268  return 2;
2269  }
2270  return 0;
2271 }
2272 
2273 /*
2274  * @brief Purge /etc/issue escapes on debian
2275  *
2276  * On debian, /etc/issue can include special characters escaped with
2277  * '\\' or '@'. This function removes such escape sequences.
2278  *
2279  * @param[in,out] buffer: string to be sanitized
2280  */
2281 static void LinuxDebianSanitizeIssue(char *buffer)
2282 {
2283  bool escaped = false;
2284  char *dst = buffer, *src = buffer, *tail = dst;
2285  while (*src != '\0')
2286  {
2287  char here = *src;
2288  src++;
2289  if (here == '\\' || here == '@' || escaped)
2290  {
2291  /* Skip over escapes and the character each acts on. */
2292  escaped = !escaped;
2293  }
2294  else
2295  {
2296  /* Copy everything else verbatim: */
2297  *dst = here;
2298  dst++;
2299  /* Keep track of (just after) last non-space: */
2300  if (!isspace(here))
2301  {
2302  tail = dst;
2303  }
2304  }
2305  }
2306 
2307  assert(tail == dst || isspace(*tail));
2308  *tail = '\0';
2309 }
2310 
2311 /******************************************************************/
2312 
2313 static int Linux_Misc_Version(EvalContext *ctx)
2314 {
2315  char flavor[CF_MAXVARSIZE];
2316  char version[CF_MAXVARSIZE];
2317  char os[CF_MAXVARSIZE];
2318  char buffer[CF_BUFSIZE];
2319 
2320  *os = '\0';
2321  *version = '\0';
2322 
2323  FILE *fp = safe_fopen(LSB_RELEASE_FILENAME, "r");
2324  if (fp != NULL)
2325  {
2326  while (!feof(fp))
2327  {
2328  if (fgets(buffer, CF_BUFSIZE, fp) == NULL)
2329  {
2330  if (ferror(fp))
2331  {
2332  break;
2333  }
2334  continue;
2335  }
2336 
2337  if (strstr(buffer, "Cumulus"))
2338  {
2339  EvalContextClassPutHard(ctx, "cumulus", "inventory,attribute_name=none,source=agent");
2340  strcpy(os, "cumulus");
2341  }
2342 
2343  char *sp = strstr(buffer, "DISTRIB_RELEASE=");
2344  if (sp)
2345  {
2346  version[0] = '\0';
2347  sscanf(sp + strlen("DISTRIB_RELEASE="), "%[^\n]", version);
2348  CanonifyNameInPlace(version);
2349  }
2350  }
2351  fclose(fp);
2352  }
2353 
2354  if (*os && *version)
2355  {
2356  snprintf(flavor, CF_MAXVARSIZE, "%s_%s", os, version);
2357  SetFlavor(ctx, flavor);
2358  return 1;
2359  }
2360 
2361  return 0;
2362 }
2363 
2364 /******************************************************************/
2365 
2366 static int Linux_Debian_Version(EvalContext *ctx)
2367 {
2368  int major = -1;
2369  int release = -1;
2370  int result;
2371  char classname[CF_MAXVARSIZE], buffer[CF_MAXVARSIZE], os[CF_MAXVARSIZE], version[CF_MAXVARSIZE];
2372 
2373  Log(LOG_LEVEL_VERBOSE, "This appears to be a debian system.");
2375  ctx,
2376  "debian",
2377  "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_VERSION_FILENAME);
2378 
2379  buffer[0] = classname[0] = '\0';
2380 
2381  Log(LOG_LEVEL_VERBOSE, "Looking for Debian version...");
2382 
2383  if (!ReadLine(DEBIAN_VERSION_FILENAME, buffer, sizeof(buffer)))
2384  {
2385  return 1;
2386  }
2387 
2388  result = sscanf(buffer, "%d.%d", &major, &release);
2389 
2390  switch (result)
2391  {
2392  case 2:
2393  Log(LOG_LEVEL_VERBOSE, "This appears to be a Debian %u.%u system.", major, release);
2394  snprintf(classname, CF_MAXVARSIZE, "debian_%u_%u", major, release);
2396  ctx,
2397  classname,
2398  "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_VERSION_FILENAME);
2399  snprintf(classname, CF_MAXVARSIZE, "debian_%u", major);
2400  SetFlavor(ctx, classname);
2401  break;
2402 
2403  case 1:
2404  Log(LOG_LEVEL_VERBOSE, "This appears to be a Debian %u system.", major);
2405  snprintf(classname, CF_MAXVARSIZE, "debian_%u", major);
2406  SetFlavor(ctx, classname);
2407  break;
2408 
2409  default:
2410  version[0] = '\0';
2411  sscanf(buffer, "%25[^/]", version);
2412  if (strlen(version) > 0)
2413  {
2414  snprintf(classname, CF_MAXVARSIZE, "debian_%s", version);
2416  ctx,
2417  classname,
2418  "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_VERSION_FILENAME);
2419  }
2420  break;
2421  }
2422 
2423  if (!ReadLine(DEBIAN_ISSUE_FILENAME, buffer, sizeof(buffer)))
2424  {
2425  return 1;
2426  }
2427 
2428  os[0] = '\0';
2429  sscanf(buffer, "%250s", os);
2430 
2431  if (strcmp(os, "Debian") == 0)
2432  {
2433  LinuxDebianSanitizeIssue(buffer);
2434  sscanf(buffer, "%*s %*s %[^./]", version);
2435  snprintf(buffer, CF_MAXVARSIZE, "debian_%s", version);
2437  ctx,
2438  "debian",
2439  "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_ISSUE_FILENAME);
2440  SetFlavor(ctx, buffer);
2441  }
2442  else if (strcmp(os, "Ubuntu") == 0)
2443  {
2444  LinuxDebianSanitizeIssue(buffer);
2445  char minor[CF_MAXVARSIZE] = {0};
2446  sscanf(buffer, "%*s %[^.].%s", version, minor);
2447  snprintf(buffer, CF_MAXVARSIZE, "ubuntu_%s", version);
2448  SetFlavor(ctx, buffer);
2450  ctx,
2451  "ubuntu",
2452  "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_ISSUE_FILENAME);
2453  if (release >= 0)
2454  {
2455  snprintf(buffer, CF_MAXVARSIZE, "ubuntu_%s_%s", version, minor);
2457  ctx,
2458  buffer,
2459  "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_ISSUE_FILENAME);
2460  }
2461  }
2462 
2463  return 0;
2464 }
2465 
2466 /******************************************************************/
2467 
2468 static int Linux_Mandrake_Version(EvalContext *ctx)
2469 {
2470 /* We are looking for one of the following strings... */
2471 #define MANDRAKE_ID "Linux Mandrake"
2472 #define MANDRAKE_REV_ID "Mandrake Linux"
2473 #define MANDRAKE_10_1_ID "Mandrakelinux"
2474 
2475 #define MANDRAKE_REL_FILENAME "/etc/mandrake-release"
2476 
2477  char relstring[CF_MAXVARSIZE];
2478  char *vendor = NULL;
2479 
2480  Log(LOG_LEVEL_VERBOSE, "This appears to be a mandrake system.");
2481  EvalContextClassPutHard(ctx, "Mandrake", "inventory,attribute_name=none,source=agent");
2482 
2483  if (!ReadLine(MANDRAKE_REL_FILENAME, relstring, sizeof(relstring)))
2484  {
2485  return 1;
2486  }
2487 
2488  Log(LOG_LEVEL_VERBOSE, "Looking for Mandrake linux info in '%s'", relstring);
2489 
2490 /* Older Mandrakes had the 'Mandrake Linux' string in reverse order */
2491 
2492  if (!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
2493  {
2494  vendor = "mandrake";
2495  }
2496  else if (!strncmp(relstring, MANDRAKE_REV_ID, strlen(MANDRAKE_REV_ID)))
2497  {
2498  vendor = "mandrake";
2499  }
2500 
2501  else if (!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
2502  {
2503  vendor = "mandrake";
2504  }
2505  else
2506  {
2507  Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from %s", MANDRAKE_REL_FILENAME);
2508  return 2;
2509  }
2510 
2511  return Linux_Mandriva_Version_Real(ctx, MANDRAKE_REL_FILENAME, relstring, vendor);
2512 }
2513 
2514 /******************************************************************/
2515 
2516 static int Linux_Mandriva_Version(EvalContext *ctx)
2517 {
2518 /* We are looking for the following strings... */
2519 #define MANDRIVA_ID "Mandriva Linux"
2520 
2521 #define MANDRIVA_REL_FILENAME "/etc/mandriva-release"
2522 
2523  char relstring[CF_MAXVARSIZE];
2524  char *vendor = NULL;
2525 
2526  Log(LOG_LEVEL_VERBOSE, "This appears to be a mandriva system.");
2527  EvalContextClassPutHard(ctx, "Mandrake", "inventory,attribute_name=none,source=agent");
2528  EvalContextClassPutHard(ctx, "Mandriva", "inventory,attribute_name=none,source=agent");
2529 
2530  if (!ReadLine(MANDRIVA_REL_FILENAME, relstring, sizeof(relstring)))
2531  {
2532  return 1;
2533  }
2534 
2535  Log(LOG_LEVEL_VERBOSE, "Looking for Mandriva linux info in '%s'", relstring);
2536 
2537  if (!strncmp(relstring, MANDRIVA_ID, strlen(MANDRIVA_ID)))
2538  {
2539  vendor = "mandriva";
2540  }
2541  else
2542  {
2543  Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from '%s'", MANDRIVA_REL_FILENAME);
2544  return 2;
2545  }
2546 
2547  return Linux_Mandriva_Version_Real(ctx, MANDRIVA_REL_FILENAME, relstring, vendor);
2548 
2549 }
2550 
2551 /******************************************************************/
2552 
2553 static int Linux_Mandriva_Version_Real(EvalContext *ctx, char *filename, char *relstring, char *vendor)
2554 {
2555  int major = -1, minor = -1;
2556  char strmajor[PRINTSIZE(major)], strminor[PRINTSIZE(minor)];
2557 
2558 #define RELEASE_FLAG "release "
2559  char *release = strstr(relstring, RELEASE_FLAG);
2560  if (release == NULL)
2561  {
2562  Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", filename);
2563  return 2;
2564  }
2565  else
2566  {
2567  release += strlen(RELEASE_FLAG);
2568  if (sscanf(release, "%d.%d", &major, &minor) == 2)
2569  {
2570  xsnprintf(strmajor, sizeof(strmajor), "%d", major);
2571  xsnprintf(strminor, sizeof(strminor), "%d", minor);
2572  }
2573  else
2574  {
2575  Log(LOG_LEVEL_VERBOSE, "Could not break down release version numbers in %s", filename);
2576  }
2577  }
2578 
2579  if (major != -1 && minor != -1 && strcmp(vendor, ""))
2580  {
2581  char classbuf[CF_MAXVARSIZE];
2582  classbuf[0] = '\0';
2583  strcat(classbuf, vendor);
2584  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2585  strcat(classbuf, "_");
2586  strcat(classbuf, strmajor);
2587  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2588  if (minor != -2)
2589  {
2590  strcat(classbuf, "_");
2591  strcat(classbuf, strminor);
2592  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2593  }
2594  }
2595 
2596  return 0;
2597 }
2598 
2599 /******************************************************************/
2600 
2601 static void Linux_Amazon_Version(EvalContext *ctx)
2602 {
2603  char buffer[CF_BUFSIZE];
2604 
2605  // Amazon Linux AMI release 2016.09
2606 
2607  if (ReadLine("/etc/system-release", buffer, sizeof(buffer)))
2608  {
2609  if (strstr(buffer, "Amazon") != NULL)
2610  {
2611  EvalContextClassPutHard(ctx, "amazon_linux",
2612  "inventory,attribute_name=none,source=agent"
2613  ",derived-from-file=/etc/system-release");
2614 
2615  char version[128];
2616  if (sscanf(buffer, "%*s %*s %*s %*s %127s", version) == 1)
2617  {
2618  char class[CF_MAXVARSIZE];
2619 
2620  CanonifyNameInPlace(version);
2621  snprintf(class, sizeof(class), "amazon_linux_%s", version);
2622  EvalContextClassPutHard(ctx, class,
2623  "inventory,attribute_name=none,source=agent"
2624  ",derived-from-file=/etc/system-release");
2625  }
2626  SetFlavor(ctx, "AmazonLinux");
2627  }
2628  }
2629 }
2630 
2631 /******************************************************************/
2632 
2633 static void Linux_Alpine_Version(EvalContext *ctx)
2634 {
2635  char buffer[CF_BUFSIZE];
2636 
2637  Log(LOG_LEVEL_VERBOSE, "This appears to be an AlpineLinux system.");
2638 
2639  EvalContextClassPutHard(ctx, "alpine_linux",
2640  "inventory,attribute_name=none,source=agent"
2641  ",derived-from-file=/etc/alpine-release");
2642 
2643  if (ReadLine("/etc/alpine-release", buffer, sizeof(buffer)))
2644  {
2645  char version[128];
2646  if (sscanf(buffer, "%127s", version) == 1)
2647  {
2648  char class[CF_MAXVARSIZE];
2649  CanonifyNameInPlace(version);
2650  snprintf(class, sizeof(class), "alpine_linux_%s", version);
2651  EvalContextClassPutHard(ctx, class,
2652  "inventory,attribute_name=none,source=agent"
2653  ",derived-from-file=/etc/alpine-release");
2654  }
2655  }
2656  SetFlavor(ctx, "alpinelinux");
2657 }
2658 
2659 /******************************************************************/
2660 
2661 static int EOS_Version(EvalContext *ctx)
2662 
2663 {
2664  char buffer[CF_BUFSIZE];
2665 
2666  // e.g. Arista Networks EOS 4.10.2
2667 
2668  if (ReadLine("/etc/Eos-release", buffer, sizeof(buffer)))
2669  {
2670  if (strstr(buffer, "EOS"))
2671  {
2672  char version[CF_MAXVARSIZE], class[CF_MAXVARSIZE];
2673  EvalContextClassPutHard(ctx, "eos", "inventory,attribute_name=none,source=agent");
2674  EvalContextClassPutHard(ctx, "arista", "source=agent");
2675  version[0] = '\0';
2676  sscanf(buffer, "%*s %*s %*s %s", version);
2677  CanonifyNameInPlace(version);
2678  snprintf(class, CF_MAXVARSIZE, "eos_%s", version);
2679  EvalContextClassPutHard(ctx, class, "inventory,attribute_name=none,source=agent");
2680  }
2681  }
2682 
2683  return 0;
2684 }
2685 
2686 /******************************************************************/
2687 
2688 static int MiscOS(EvalContext *ctx)
2689 
2690 { char buffer[CF_BUFSIZE];
2691 
2692  // e.g. BIG-IP 10.1.0 Build 3341.1084
2693 
2694  if (ReadLine("/etc/issue", buffer, sizeof(buffer)))
2695  {
2696  if (strstr(buffer, "BIG-IP"))
2697  {
2698  char version[CF_MAXVARSIZE], build[CF_MAXVARSIZE], class[CF_MAXVARSIZE];
2699  EvalContextClassPutHard(ctx, "big_ip", "inventory,attribute_name=none,source=agent");
2700  sscanf(buffer, "%*s %s %*s %s", version, build);
2701  CanonifyNameInPlace(version);
2702  CanonifyNameInPlace(build);
2703  snprintf(class, CF_MAXVARSIZE, "big_ip_%s", version);
2704  EvalContextClassPutHard(ctx, class, "inventory,attribute_name=none,source=agent");
2705  snprintf(class, CF_MAXVARSIZE, "big_ip_%s_%s", version, build);
2706  EvalContextClassPutHard(ctx, class, "inventory,attribute_name=none,source=agent");
2707  SetFlavor(ctx, "BIG-IP");
2708  }
2709  }
2710 
2711  return 0;
2712 }
2713 
2714 /******************************************************************/
2715 
2716 static int VM_Version(EvalContext *ctx)
2717 {
2718  char *sp, buffer[CF_BUFSIZE], classbuf[CF_BUFSIZE], version[CF_BUFSIZE];
2719  int major, minor, bug;
2720  int sufficient = 0;
2721 
2722  Log(LOG_LEVEL_VERBOSE, "This appears to be a VMware Server ESX/xSX system.");
2723  EvalContextClassPutHard(ctx, "VMware", "inventory,attribute_name=Virtual host,source=agent");
2724 
2725 /* VMware Server ESX >= 3 has version info in /proc */
2726  if (ReadLine("/proc/vmware/version", buffer, sizeof(buffer)))
2727  {
2728  if (sscanf(buffer, "VMware ESX Server %d.%d.%d", &major, &minor, &bug) > 0)
2729  {
2730  snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %d", major);
2731  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2732  snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %d.%d", major, minor);
2733  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2734  snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %d.%d.%d", major, minor, bug);
2735  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2736  sufficient = 1;
2737  }
2738  else if (sscanf(buffer, "VMware ESX Server %s", version) > 0)
2739  {
2740  snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %s", version);
2741  EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2742  sufficient = 1;
2743  }
2744  }
2745 
2746 /* Fall back to checking for other files */
2747 
2748  if (sufficient < 1 && (ReadLine("/etc/vmware-release", buffer, sizeof(buffer))
2749  || ReadLine("/etc/issue", buffer, sizeof(buffer))))
2750  {
2751  EvalContextClassPutHard(ctx, buffer, "inventory,attribute_name=none,source=agent");
2752 
2753  /* Strip off the release code name e.g. "(Dali)" */
2754  if ((sp = strchr(buffer, '(')) != NULL)
2755  {
2756  *sp = 0;
2757  Chop(buffer, CF_EXPANDSIZE);
2758  EvalContextClassPutHard(ctx, buffer, "inventory,attribute_name=none,source=agent");
2759  }
2760  sufficient = 1;
2761  }
2762 
2763  return sufficient < 1 ? 1 : 0;
2764 }
2765 
2766 /******************************************************************/
2767 
2768 static int Xen_Domain(EvalContext *ctx)
2769 {
2770  int sufficient = 0;
2771 
2772  Log(LOG_LEVEL_VERBOSE, "This appears to be a xen pv system.");
2773  EvalContextClassPutHard(ctx, "xen", "inventory,attribute_name=Virtual host,source=agent");
2774 
2775 /* xen host will have "control_d" in /proc/xen/capabilities, xen guest will not */
2776 
2777  FILE *fp = safe_fopen("/proc/xen/capabilities", "r");
2778  if (fp != NULL)
2779  {
2780  size_t buffer_size = CF_BUFSIZE;
2781  char *buffer = xmalloc(buffer_size);
2782 
2783  for (;;)
2784  {
2785  ssize_t res = CfReadLine(&buffer, &buffer_size, fp);
2786  if (res == -1)
2787  {
2788  if (!feof(fp))
2789  {
2790  /* Failure reading Xen capabilites. Do we care? */
2791  fclose(fp);
2792  free(buffer);
2793  return 1;
2794  }
2795  else
2796  {
2797  break;
2798  }
2799  }
2800 
2801  if (strstr(buffer, "control_d"))
2802  {
2803  EvalContextClassPutHard(ctx, "xen_dom0", "inventory,attribute_name=Virtual host,source=agent");
2804  sufficient = 1;
2805  }
2806  }
2807 
2808  if (!sufficient)
2809  {
2810  EvalContextClassPutHard(ctx, "xen_domu_pv", "inventory,attribute_name=Virtual host,source=agent");
2811  sufficient = 1;
2812  }
2813 
2814  fclose(fp);
2815  free(buffer);
2816  }
2817 
2818  return sufficient < 1 ? 1 : 0;
2819 }
2820 
2821 /******************************************************************/
2822 static void OpenVZ_Detect(EvalContext *ctx)
2823 {
2824 /* paths to file defining the type of vm (guest or host) */
2825 #define OPENVZ_HOST_FILENAME "/proc/bc/0"
2826 #define OPENVZ_GUEST_FILENAME "/proc/vz"
2827 /* path to the vzps binary */
2828 #define OPENVZ_VZPS_FILE "/bin/vzps"
2829  struct stat statbuf;
2830 
2831  /* The file /proc/bc/0 is present on host
2832  The file /proc/vz is present on guest
2833  If the host has /bin/vzps, we should use it for checking processes
2834  */
2835 
2836  if (stat(OPENVZ_HOST_FILENAME, &statbuf) != -1)
2837  {
2838  Log(LOG_LEVEL_VERBOSE, "This appears to be an OpenVZ/Virtuozzo/Parallels Cloud Server host system.\n");
2839  EvalContextClassPutHard(ctx, "virt_host_vz", "inventory,attribute_name=Virtual host,source=agent");
2840  /* if the file /bin/vzps is there, it is safe to use the processes promise type */
2841  if (stat(OPENVZ_VZPS_FILE, &statbuf) != -1)
2842  {
2843  EvalContextClassPutHard(ctx, "virt_host_vz_vzps", "inventory,attribute_name=Virtual host,source=agent");
2844  /* here we must redefine the value of VPSHARDCLASS */
2845  for (int i = 0; i < PLATFORM_CONTEXT_MAX; i++)
2846  {
2847  if (!strcmp(CLASSATTRIBUTES[i][0], "virt_host_vz_vzps"))
2848  {
2850  break;
2851  }
2852  }
2853  }
2854  else
2855  {
2856  Log(LOG_LEVEL_NOTICE, "This OpenVZ/Virtuozzo/Parallels Cloud Server host system does not have vzps installed; the processes promise type may not work as expected.\n");
2857  }
2858  }
2859  else if (stat(OPENVZ_GUEST_FILENAME, &statbuf) != -1)
2860  {
2861  Log(LOG_LEVEL_VERBOSE, "This appears to be an OpenVZ/Virtuozzo/Parallels Cloud Server guest system.\n");
2862  EvalContextClassPutHard(ctx, "virt_guest_vz", "inventory,attribute_name=Virtual host,source=agent");
2863  }
2864 }
2865 
2866 /******************************************************************/
2867 
2868 static bool ReadLine(const char *filename, char *buf, int bufsize)
2869 {
2870  FILE *fp = ReadFirstLine(filename, buf, bufsize);
2871 
2872  if (fp == NULL)
2873  {
2874  return false;
2875  }
2876  else
2877  {
2878  fclose(fp);
2879  return true;
2880  }
2881 }
2882 
2883 static FILE *ReadFirstLine(const char *filename, char *buf, int bufsize)
2884 {
2885  FILE *fp = safe_fopen(filename, "r");
2886 
2887  if (fp == NULL)
2888  {
2889  return NULL;
2890  }
2891 
2892  if (fgets(buf, bufsize, fp) == NULL)
2893  {
2894  fclose(fp);
2895  return NULL;
2896  }
2897 
2899 
2900  return fp;
2901 }
2902 #endif /* __linux__ */
2903 
2904 /******************************************************************/
2905 
2906 #ifdef XEN_CPUID_SUPPORT
2907 
2908 /* Borrowed and modified from Xen source/tools/libxc/xc_cpuid_x86.c */
2909 
2910 static void Xen_Cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
2911 {
2912 # ifdef __i386__
2913  /* On i386, %ebx register needs to be saved before usage and restored
2914  * thereafter for PIC-compliant code on i386. */
2915  asm("push %%ebx; cpuid; mov %%ebx,%1; pop %%ebx"
2916  : "=a"(*eax), "=r"(*ebx), "=c"(*ecx), "=d"(*edx)
2917  : "0" (idx), "2" (0) );
2918 # else
2919  asm("cpuid"
2920  : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
2921  : "0" (idx), "2" (0) );
2922 # endif
2923 }
2924 
2925 /******************************************************************/
2926 
2927 static bool Xen_Hv_Check(void)
2928 {
2929  /* CPUID interface to Xen from arch-x86/cpuid.h:
2930  * Leaf 1 (0x40000000)
2931  * EAX: Largest Xen-information leaf. All leaves up to an including @EAX
2932  * are supported by the Xen host.
2933  * EBX-EDX: "XenVMMXenVMM" signature, allowing positive identification
2934  * of a Xen host.
2935  *
2936  * Additional information can be found in the Hypervisor CPUID
2937  * Interface Proposal (https://lkml.org/lkml/2008/10/1/246)
2938  */
2939 
2940  uint32_t eax, base;
2941  union
2942  {
2943  uint32_t u[3];
2944  char s[13];
2945  } sig = {{0}};
2946 
2947  /*
2948  * For compatibility with other hypervisor interfaces, the Xen cpuid leaves
2949  * can be found at the first otherwise unused 0x100 aligned boundary starting
2950  * from 0x40000000.
2951  *
2952  * e.g If viridian extensions are enabled for an HVM domain, the Xen cpuid
2953  * leaves will start at 0x40000100
2954  */
2955  for (base = 0x40000000; base < 0x40010000; base += 0x100)
2956  {
2957  Xen_Cpuid(base, &eax, &sig.u[0], &sig.u[1], &sig.u[2]);
2958 
2959  if (memcmp("XenVMMXenVMM", &sig.s[0], 12) == 0)
2960  {
2961  /* The highest basic calling parameter (largest value that EAX can
2962  * be set to before calling CPUID) is returned in EAX. */
2963  if ((eax - base) < 2)
2964  {
2966  "Insufficient Xen CPUID Leaves (eax=%x at base %x)",
2967  eax, base);
2968  return false;
2969  }
2971  "Found Xen CPUID Leaf (eax=%x at base %x)", eax, base);
2972  return true;
2973  }
2974  }
2975 
2976  return false;
2977 }
2978 
2979 #endif /* XEN_CPUID_SUPPORT */
2980 
2981 static void GetCPUInfo(EvalContext *ctx)
2982 {
2983 #if defined(MINGW) || defined(NT)
2984  Log(LOG_LEVEL_VERBOSE, "!! cpu count not implemented on Windows platform");
2985  return;
2986 #else
2987  int count = 0;
2988 
2989  // http://preview.tinyurl.com/c9l2sh - StackOverflow on cross-platform CPU counting
2990 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
2991  // Linux, AIX, Solaris, Darwin >= 10.4
2992  count = (int)sysconf(_SC_NPROCESSORS_ONLN);
2993 #endif
2994 
2995 #if defined(HAVE_SYS_SYSCTL_H) && defined(HW_NCPU)
2996  // BSD-derived platforms
2997  int mib[2] = { CTL_HW, HW_NCPU };
2998  size_t len;
2999 
3000  len = sizeof(count);
3001  if(sysctl(mib, 2, &count, &len, NULL, 0) < 0)
3002  {
3003  Log(LOG_LEVEL_ERR, "!! failed to get cpu count: %s", strerror(errno));
3004  }
3005 #endif
3006 
3007 #ifdef HAVE_SYS_MPCTL_H
3008 // Itanium processors have Intel Hyper-Threading virtual-core capability,
3009 // and the MPC_GETNUMCORES_SYS operation counts each HT virtual core,
3010 // which is equivalent to what the /proc/stat scan delivers for Linux.
3011 //
3012 // A build on 11i v3 PA would have the GETNUMCORES define, but if run on an
3013 // 11i v1 system it would fail since that OS release has only GETNUMSPUS.
3014 // So in the presence of GETNUMCORES, we check for an invalid arg error
3015 // and fall back to GETNUMSPUS if necessary. An 11i v1 build would work
3016 // normally on 11i v3, because on PA-RISC cores == spus since there's no
3017 // HT on PA-RISC, and 11i v1 only runs on PA-RISC.
3018 # ifdef MPC_GETNUMCORES_SYS
3019  count = mpctl(MPC_GETNUMCORES_SYS, 0, 0);
3020  if (count == -1 && errno == EINVAL)
3021  {
3022  count = mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
3023  }
3024 # else
3025  count = mpctl(MPC_GETNUMSPUS_SYS, 0, 0); // PA-RISC processor count
3026 # endif
3027 #endif /* HAVE_SYS_MPCTL_H */
3028 
3029  if (count < 1)
3030  {
3031  Log(LOG_LEVEL_VERBOSE, "invalid processor count: %d", count);
3032  return;
3033  }
3034  Log(LOG_LEVEL_VERBOSE, "Found %d processor%s", count, count > 1 ? "s" : "");
3035 
3036  char buf[CF_SMALLBUF] = "1_cpu";
3037  if (count == 1)
3038  {
3039  EvalContextClassPutHard(ctx, buf, "source=agent,derived-from=sys.cpus"); // "1_cpu" from init - change if buf is ever used above
3040  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cpus", "1", CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CPU logical cores");
3041  }
3042  else
3043  {
3044  snprintf(buf, CF_SMALLBUF, "%d_cpus", count);
3045  EvalContextClassPutHard(ctx, buf, "source=agent,derived-from=sys.cpus");
3046  snprintf(buf, CF_SMALLBUF, "%d", count);
3047  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cpus", buf, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CPU logical cores");
3048  }
3049 #endif /* MINGW || NT */
3050 }
3051 
3052 /******************************************************************/
3053 
3054 // Implemented in Windows specific section.
3055 #ifndef __MINGW32__
3056 
3057 /**
3058  Return the number of seconds the system has been online given the current
3059  time() as an argument, or return -1 if unavailable or unimplemented.
3060 */
3061 int GetUptimeSeconds(time_t now)
3062 {
3063  time_t boot_time = 0;
3064  errno = 0;
3065 
3066 #if defined(BOOT_TIME_WITH_SYSINFO) // Most GNU, Linux platforms
3067 
3068  struct sysinfo s;
3069  if (sysinfo(&s) == 0)
3070  {
3071  // Don't return yet, sanity checking below
3072  boot_time = now - s.uptime;
3073  }
3074 
3075 #elif defined(BOOT_TIME_WITH_KSTAT) // Solaris platform
3076 
3077  /* From command line you can get this with:
3078  kstat -p unix:0:system_misc:boot_time */
3079  kstat_ctl_t *kc = kstat_open();
3080  if(kc != 0)
3081  {
3082  kstat_t *kp = kstat_lookup(kc, "unix", 0, "system_misc");
3083  if(kp != 0)
3084  {
3085  if (kstat_read(kc, kp, NULL) != -1)
3086  {
3087  kstat_named_t *knp = kstat_data_lookup(kp, "boot_time");
3088  if (knp != NULL)
3089  {
3090  boot_time = knp->value.ui32;
3091  }
3092  }
3093  }
3094  kstat_close(kc);
3095  }
3096 
3097 #elif defined(BOOT_TIME_WITH_PSTAT_GETPROC) // HP-UX platform only
3098 
3099  struct pst_status p;
3100  if (pstat_getproc(&p, sizeof(p), 0, 1) == 1)
3101  {
3102  boot_time = (time_t)p.pst_start;
3103  }
3104 
3105 #elif defined(BOOT_TIME_WITH_SYSCTL) // BSD-derived platforms
3106 
3107  int mib[2] = { CTL_KERN, KERN_BOOTTIME };
3108  struct timeval boot;
3109  size_t len = sizeof(boot);
3110  if (sysctl(mib, 2, &boot, &len, NULL, 0) == 0)
3111  {
3112  boot_time = boot.tv_sec;
3113  }
3114 
3115 #elif defined(BOOT_TIME_WITH_PROCFS)
3116 
3117  struct stat p;
3118  if (stat("/proc/1", &p) == 0)
3119  {
3120  boot_time = p.st_ctime;
3121  }
3122 
3123 #elif defined(BOOT_TIME_WITH_UTMP) /* SystemV, highly portable way */
3124 
3125  struct utmp query = { .ut_type = BOOT_TIME };
3126  struct utmp *result;
3127  setutent();
3128  result = getutid(&query);
3129  if (result != NULL)
3130  {
3131  boot_time = result->ut_time;
3132  }
3133  endutent();
3134 
3135 #elif defined(BOOT_TIME_WITH_UTMPX) /* POSIX way */
3136 
3137  struct utmpx query = { .ut_type = BOOT_TIME };
3138  struct utmpx *result;
3139  setutxent();
3140  result = getutxid(&query);
3141  if (result != NULL)
3142  {
3143  boot_time = result->ut_tv.tv_sec;
3144  }
3145  endutxent();
3146 
3147 #endif
3148 
3149  if(errno)
3150  {
3151  Log(LOG_LEVEL_VERBOSE, "boot time discovery error: %s", GetErrorStr());
3152  }
3153 
3154  if(boot_time > now || boot_time <= 0)
3155  {
3156  Log(LOG_LEVEL_VERBOSE, "invalid boot time found; trying uptime command");
3157  boot_time = GetBootTimeFromUptimeCommand(now);
3158  }
3159 
3160  return boot_time > 0 ? now - boot_time : -1;
3161 }
3162 #endif // !__MINGW32__
3163 
3164 int GetUptimeMinutes(time_t now)
3165 {
3166  return GetUptimeSeconds(now) / SECONDS_PER_MINUTE;
3167 }
3168 
3169 /******************************************************************/
3170 
3171 // Last resort: parse the output of the uptime command with a PCRE regexp
3172 // and convert the uptime to boot time using "now" argument.
3173 //
3174 // The regexp needs to match all variants of the uptime command's output.
3175 // Solaris 8/9/10: 10:45am up 109 day(s), 19:56, 1 user, load average:
3176 // HP-UX 11.11: 9:24am up 1 min, 1 user, load average:
3177 // 8:23am up 23 hrs, 0 users, load average:
3178 // 9:33am up 2 days, 10 mins, 0 users, load average:
3179 // 11:23am up 2 days, 2 hrs, 0 users, load average:
3180 // Red Hat Linux: 10:51:23 up 5 days, 19:54, 1 user, load average:
3181 //
3182 // UPTIME_BACKREFS must be set to this regexp's maximum backreference
3183 // index number (i.e., the count of left-parentheses):
3184 #define UPTIME_REGEXP " up (\\d+ day[^,]*,|) *(\\d+( ho?u?r|:(\\d+))|(\\d+) min)"
3185 #define UPTIME_BACKREFS 5
3186 #define UPTIME_OVECTOR ((UPTIME_BACKREFS + 1) * 3)
3187 
3188 static time_t GetBootTimeFromUptimeCommand(time_t now)
3189 {
3190  FILE *uptimecmd;
3191  pcre *rx;
3192  int ovector[UPTIME_OVECTOR], i;
3193  char *backref = NULL;
3194  const char *uptimepath = "/usr/bin/uptime";
3195  time_t uptime = 0;
3196  const char *errptr;
3197  int erroffset;
3198 
3199  rx = pcre_compile(UPTIME_REGEXP, 0, &errptr, &erroffset, NULL);
3200  if (rx == NULL)
3201  {
3202  Log(LOG_LEVEL_DEBUG, "failed to compile regexp to parse uptime command");
3203  return(-1);
3204  }
3205 
3206  // Try "/usr/bin/uptime" first, then "/bin/uptime"
3207  uptimecmd = cf_popen(uptimepath, "r", false);
3208  uptimecmd = uptimecmd ? uptimecmd : cf_popen((uptimepath + 4), "r", false);
3209  if (!uptimecmd)
3210  {
3211  Log(LOG_LEVEL_ERR, "uptime failed: (cf_popen: %s)", GetErrorStr());
3212  return -1;
3213  }
3214 
3215  size_t uptime_output_size = CF_SMALLBUF;
3216  char *uptime_output = xmalloc(uptime_output_size);
3217  i = CfReadLine(&uptime_output, &uptime_output_size, uptimecmd);
3218 
3219  cf_pclose(uptimecmd);
3220  if (i == -1 && !feof(uptimecmd))
3221  {
3222  Log(LOG_LEVEL_ERR, "Reading uptime output failed. (getline: '%s')", GetErrorStr());
3223  return -1;
3224  }
3225 
3226  if ((i > 0) && (pcre_exec(rx, NULL, (const char *)uptime_output, i, 0, 0, ovector, UPTIME_OVECTOR) > 1))
3227  {
3228  for (i = 1; i <= UPTIME_BACKREFS ; i++)
3229  {
3230  if (ovector[i * 2 + 1] - ovector[i * 2] == 0) // strlen(backref)
3231  {
3232  continue;
3233  }
3234  backref = uptime_output + ovector[i * 2];
3235  // atoi() ignores non-digits, so no need to null-terminate backref
3236 
3237  time_t seconds;
3238  switch(i)
3239  {
3240  case 1: // Day
3241  seconds = SECONDS_PER_DAY;
3242  break;
3243  case 2: // Hour
3244  seconds = SECONDS_PER_HOUR;
3245  break;
3246  case 4: // Minute
3247  case 5:
3248  seconds = SECONDS_PER_MINUTE;
3249  break;
3250  default:
3251  seconds = 0;
3252  }
3253  uptime += ((time_t) atoi(backref)) * seconds;
3254  }
3255  }
3256  else
3257  {
3258  Log(LOG_LEVEL_ERR, "uptime PCRE match failed: regexp: '%s', uptime: '%s'", UPTIME_REGEXP, uptime_output);
3259  }
3260  pcre_free(rx);
3261  Log(LOG_LEVEL_VERBOSE, "Reading boot time from uptime command successful.");
3262  return(uptime ? (now - uptime) : -1);
3263 }
3264 
3265 /*****************************************************************************/
3266 
3267 /* TODO accept a const char * and move the ifdefs away from
3268  * evalfunction.c:FnCallGetUserInfo() to here. */
3269 JsonElement* GetUserInfo(const void *passwd)
3270 {
3271 #ifdef __MINGW32__
3272  return NULL;
3273 
3274 #else /* !__MINGW32__ */
3275 
3276  // we lose the const to set pw if passwd is NULL
3277  struct passwd *pw = (struct passwd*) passwd;
3278 
3279  if (pw == NULL)
3280  {
3281  pw = getpwuid(getuid());
3282  }
3283 
3284  if (pw == NULL)
3285  {
3286  return NULL;
3287  }
3288 
3289  JsonElement *result = JsonObjectCreate(10);
3290  JsonObjectAppendString(result, "username", pw->pw_name);
3291  JsonObjectAppendString(result, "description", pw->pw_gecos);
3292  JsonObjectAppendString(result, "home_dir", pw->pw_dir);
3293  JsonObjectAppendString(result, "shell", pw->pw_shell);
3294  JsonObjectAppendInteger(result, "uid", pw->pw_uid);
3295  JsonObjectAppendInteger(result, "gid", pw->pw_gid);
3296  //JsonObjectAppendBool(result, "locked", IsAccountLocked(pw->pw_name, pw));
3297  // TODO: password: { format: "hash", data: { ...GetPasswordHash()... } }
3298  // TODO: group_primary: name of group
3299  // TODO: groups_secondary: [ names of groups ]
3300  // TODO: gids_secondary: [ gids of groups ]
3301 
3302  return result;
3303 #endif
3304 }
3305 
3306 /*****************************************************************************/
3307 
3309 {
3310  /* Get info for current user. */
3311  JsonElement *info = GetUserInfo(NULL);
3312  if (info != NULL)
3313  {
3315  info, CF_DATA_TYPE_CONTAINER,
3316  "source=agent,user_info");
3317  JsonDestroy(info);
3318  }
3319 }
3320 
3321 /*****************************************************************************/
3322 
3324 {
3326  ctx, SPECIAL_SCOPE_DEF, "jq",
3327  "jq --compact-output --monochrome-output --ascii-output --unbuffered --sort-keys",
3328  CF_DATA_TYPE_STRING, "invocation,source=agent,command_name=jq");
3329 }
3330 /*****************************************************************************/
3331 
3333 {
3334  GetNameInfo3(ctx);
3335  GetInterfacesInfo(ctx);
3336  GetNetworkingInfo(ctx);
3337  Get3Environment(ctx);
3338  BuiltinClasses(ctx);
3339  OSClasses(ctx);
3340  GetSysVars(ctx);
3341  GetDefVars(ctx);
3342 }
void * xmalloc(size_t size)
Definition: alloc-mini.c:46
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xasprintf(char **strp, const char *fmt,...)
Definition: alloc.c:71
#define CF_ENV_FILE
Definition: cf3.defs.h:95
#define SECONDS_PER_DAY
Definition: cf3.defs.h:72
#define SECONDS_PER_HOUR
Definition: cf3.defs.h:71
DataType
Definition: cf3.defs.h:368
@ CF_DATA_TYPE_REAL
Definition: cf3.defs.h:371
@ CF_DATA_TYPE_STRING_LIST
Definition: cf3.defs.h:372
@ CF_DATA_TYPE_STRING
Definition: cf3.defs.h:369
@ CF_DATA_TYPE_INT
Definition: cf3.defs.h:370
@ CF_DATA_TYPE_COUNTER
Definition: cf3.defs.h:383
@ CF_DATA_TYPE_CONTAINER
Definition: cf3.defs.h:384
#define SECONDS_PER_MINUTE
Definition: cf3.defs.h:70
HashMethod CF_DEFAULT_DIGEST
Definition: cf3globals.c:88
char VUQNAME[]
Definition: cf3globals.c:59
struct utsname VSYSNAME
Definition: cf3globals.c:38
void free(void *)
char VDOMAIN[]
Definition: cf3globals.c:60
char VFQNAME[]
Definition: cf3globals.c:58
char VIPADDRESS[64]
Definition: cf3globals.c:81
bool NextDB(DBCursor *cursor, char **key, int *ksize, void **value, int *vsize)
Definition: dbm_api.c:601
bool OpenDB(DBHandle **dbp, dbid id)
Definition: dbm_api.c:441
bool DeleteDBCursor(DBCursor *cursor)
Definition: dbm_api.c:617
void CloseDB(DBHandle *handle)
Definition: dbm_api.c:472
bool NewDBCursor(DBHandle *handle, DBCursor **cursor)
Definition: dbm_api.c:588
@ dbid_static
Definition: dbm_api.h:50
#define CF_BUFSIZE
Definition: definitions.h:50
#define CF_EXPANDSIZE
Definition: definitions.h:51
#define CF_MAXVARSIZE
Definition: definitions.h:36
#define CF_SMALLBUF
Definition: definitions.h:49
void EnterpriseContext(EvalContext *ctx)
bool EvalContextClassPutHard(EvalContext *ctx, const char *name, const char *tags)
bool EvalContextVariablePutSpecial(EvalContext *ctx, SpecialScope scope, const char *lval, const void *value, DataType type, const char *tags)
Class * EvalContextClassGet(const EvalContext *ctx, const char *ns, const char *name)
void CreateHardClassesFromFeatures(EvalContext *ctx, char *tags)
Definition: feature.c:44
ssize_t CfReadLine(char **buff, size_t *size, FILE *fp)
Works exactly like posix 'getline', EXCEPT it does not include carriage return at the end.
Definition: file_lib.c:1476
FILE * safe_fopen(const char *const path, const char *const mode)
Definition: file_lib.c:812
char * MapName(char *s)
Definition: file_lib.c:441
#define FILE_SEPARATOR
Definition: file_lib.h:102
char * CanonifyName(const char *str)
Definition: files_names.c:483
const char * Version(void)
const char * NameVersion(void)
int errno
#define NULL
Definition: getopt1.c:56
void HashPubKey(const RSA *const key, unsigned char digest[EVP_MAX_MD_SIZE+1], const HashMethod type)
Definition: hash.c:530
char * HashPrintSafe(char *dst, size_t dst_size, const unsigned char *digest, HashMethod type, bool use_prefix)
Definition: hash.c:612
#define CF_HOSTKEY_STRING_SIZE
Definition: hash.h:151
Item * SplitString(const char *string, char sep)
Definition: item_lib.c:546
void DeleteItemList(Item *item)
Definition: item_lib.c:808
JsonElement * JsonReadDataFile(const char *log_identifier, const char *input_path, const DataFileType requested_mode, size_t size_max)
Definition: json-utils.c:323
@ DATAFILETYPE_ENV
Definition: json-utils.h:34
JsonElement * JsonObjectCreate(const size_t initialCapacity)
Create a new JSON object.
Definition: json.c:880
void JsonDestroy(JsonElement *const element)
Destroy a JSON element.
Definition: json.c:386
void JsonObjectAppendInteger(JsonElement *const object, const char *const key, const int value)
Append an integer field to an object.
Definition: json.c:1062
const char * JsonObjectGetAsString(const JsonElement *const object, const char *const key)
Get the value of a field in an object, as a string.
Definition: json.c:1204
void JsonObjectAppendString(JsonElement *const object, const char *const key, const char *const value)
Append a string field to an object.
Definition: json.c:1055
const char * GetInputDir(void)
Definition: known_dirs.c:182
const char * GetLogDir(void)
Definition: known_dirs.c:146
const char * GetPidDir(void)
Definition: known_dirs.c:153
const char * GetStateDir(void)
Definition: known_dirs.c:186
const char * GetBinDir(void)
Definition: known_dirs.c:121
const char * GetMasterDir(void)
Definition: known_dirs.c:184
const char * GetWorkDir(void)
Definition: known_dirs.c:114
const char * GetErrorStr(void)
Definition: logging.c:275
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_NOTICE
Definition: logging.h:44
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
@ LOG_LEVEL_INFO
Definition: logging.h:45
void xsnprintf(char *str, size_t str_size, const char *format,...)
Definition: misc_lib.c:114
#define UnexpectedError(...)
Definition: misc_lib.h:38
void Banner(const char *s)
Definition: ornaments.c:219
int cf_pclose(FILE *pp)
Definition: pipes_unix.c:812
FILE * cf_popen(const char *command, const char *type, bool capture_stderr)
Definition: pipes_unix.c:332
uid_t getuid(void)
#define MIN(a, b)
Definition: platform.h:478
#define S_ISDIR(m)
Definition: platform.h:916
int uname(struct utsname *buf)
#define PATH_MAX
Definition: platform.h:176
#define _SYS_NMLN
Definition: platform.h:104
#define PRINTSIZE(what)
Definition: printsize.h:66
bool StringMatchFull(const char *regex, const char *str)
Definition: regex.c:106
Rlist * RlistParseShown(const char *string)
Definition: rlist.c:686
Rlist * RlistFromSplitString(const char *string, char sep)
Definition: rlist.c:1067
void RlistDestroy(Rlist *rl)
Definition: rlist.c:501
@ SPECIAL_SCOPE_MON
Definition: scope.h:37
@ SPECIAL_SCOPE_SYS
Definition: scope.h:38
@ SPECIAL_SCOPE_DEF
Definition: scope.h:41
char * strerror(int err)
Definition: strerror.c:35
char * SafeStringDuplicate(const char *str)
Definition: string_lib.c:172
bool StringEqual(const char *const a, const char *const b)
Definition: string_lib.c:256
int Chop(char *str, size_t max_length)
Remove trailing spaces.
Definition: string_lib.c:1174
int StripTrailingNewline(char *str, size_t max_length)
Strips the newline character off a string, in place.
Definition: string_lib.c:1138
void CanonifyNameInPlace(char *s)
Definition: string_lib.c:1574
void ToLowerStrInplace(char *str)
Definition: string_lib.c:162
size_t strlcat(char *dst, const char *src, size_t siz)
Definition: strlcat.c:36
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:34
char * strstr(const char *haystack, const char *needle)
Definition: strstr.c:35
Definition: item_lib.h:33
Item * next
Definition: item_lib.h:38
char * name
Definition: item_lib.h:34
Definition: rlist.h:35
char version[257]
Definition: platform.h:111
char sysname[257]
Definition: platform.h:108
char nodename[257]
Definition: platform.h:109
char release[257]
Definition: platform.h:110
char machine[257]
Definition: platform.h:112
#define UPTIME_REGEXP
Definition: sysinfo.c:3184
static const char *const VEXPORTS[]
Definition: sysinfo.c:262
static void Get3Environment(EvalContext *ctx)
Definition: sysinfo.c:910
void CreateHardClassesFromCanonification(EvalContext *ctx, const char *canonified, char *tags)
Definition: sysinfo.c:1041
static time_t GetBootTimeFromUptimeCommand(time_t now)
Definition: sysinfo.c:3188
#define UPTIME_BACKREFS
Definition: sysinfo.c:3185
int GetUptimeSeconds(time_t now)
Definition: sysinfo.c:3061
#define LSB_RELEASE_FILENAME
Definition: sysinfo.c:142
#define DEBIAN_VERSION_FILENAME
Definition: sysinfo.c:143
static const char *const VRESOLVCONF[]
Definition: sysinfo.c:212
void CalculateDomainName(const char *nodename, const char *dnsname, char *fqname, size_t fqname_size, char *uqname, size_t uqname_size, char *domain, size_t domain_size)
Definition: sysinfo.c:290
void DiscoverVersion(EvalContext *ctx)
Definition: sysinfo.c:386
void LoadSlowlyVaryingObservations(EvalContext *ctx)
Definition: sysinfo.c:839
#define COMPONENTS_SIZE
static void BuiltinClasses(EvalContext *ctx)
Definition: sysinfo.c:1027
static void GetNameInfo3(EvalContext *ctx)
Definition: sysinfo.c:416
static const char *const CLASSATTRIBUTES[][3]
Definition: sysinfo.c:185
void DetectDomainName(EvalContext *ctx, const char *orig_nodename)
Definition: sysinfo.c:331
static const char *const VMAILDIR[]
Definition: sysinfo.c:237
JsonElement * GetUserInfo(const void *passwd)
Definition: sysinfo.c:3269
#define UPTIME_OVECTOR
Definition: sysinfo.c:3186
void GetSysVars(EvalContext *ctx)
Definition: sysinfo.c:3308
void DetectEnvironment(EvalContext *ctx)
Definition: sysinfo.c:3332
#define DEBIAN_ISSUE_FILENAME
Definition: sysinfo.c:144
int GetUptimeMinutes(time_t now)
Definition: sysinfo.c:3164
void GetDefVars(EvalContext *ctx)
Definition: sysinfo.c:3323
static void GetCPUInfo(EvalContext *ctx)
Definition: sysinfo.c:2981
static void SetFlavor(EvalContext *ctx, const char *flavor)
Definition: sysinfo.c:1058
static void OSClasses(EvalContext *ctx)
Definition: sysinfo.c:1196
void GetInterfacesInfo(EvalContext *ctx)
Definition: unix_iface.c:354
void GetNetworkingInfo(EvalContext *ctx)
Definition: unix_iface.c:1261
const char *const CLASSTEXT[]
Definition: systype.c:42
PlatformContext VPSHARDCLASS
Definition: systype.c:37
const char *const VFSTAB[]
Definition: systype.c:126
PlatformContext VSYSTEMHARDCLASS
Definition: systype.c:36
PlatformContext
Definition: systype.h:31
@ PLATFORM_CONTEXT_UNKNOWN
Definition: systype.h:32
@ PLATFORM_CONTEXT_NETBSD
Definition: systype.h:41
@ PLATFORM_CONTEXT_OPENVZ
Definition: systype.h:33
@ PLATFORM_CONTEXT_MINGW
Definition: systype.h:50
@ PLATFORM_CONTEXT_AIX
Definition: systype.h:35
@ PLATFORM_CONTEXT_SOLARIS
Definition: systype.h:38
@ PLATFORM_CONTEXT_DRAGONFLY
Definition: systype.h:49
@ PLATFORM_CONTEXT_VMWARE
Definition: systype.h:51
@ PLATFORM_CONTEXT_FREEBSD
Definition: systype.h:40
@ PLATFORM_CONTEXT_MAX
Definition: systype.h:54
@ PLATFORM_CONTEXT_HP
Definition: systype.h:34
@ PLATFORM_CONTEXT_QNX
Definition: systype.h:48
@ PLATFORM_CONTEXT_DARWIN
Definition: systype.h:47
@ PLATFORM_CONTEXT_LINUX
Definition: systype.h:36
@ PLATFORM_CONTEXT_OPENBSD
Definition: systype.h:45
@ PLATFORM_CONTEXT_SYSTEMV
Definition: systype.h:44
@ PLATFORM_CONTEXT_ANDROID
Definition: systype.h:52
@ PLATFORM_CONTEXT_CFSCO
Definition: systype.h:46
@ PLATFORM_CONTEXT_BUSYBOX
Definition: systype.h:37
@ PLATFORM_CONTEXT_SUN_SOLARIS
Definition: systype.h:39
@ PLATFORM_CONTEXT_WINDOWS_NT
Definition: systype.h:43
@ PLATFORM_CONTEXT_CRAYOS
Definition: systype.h:42
RSA * PUBKEY
Definition: tls_client.c:44