pmm  1.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
pmm_cond.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008-2010 Robert Higgins
3  Author: Robert Higgins <robert.higgins@ucd.ie>
4 
5  This file is part of PMM.
6 
7  PMM is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  PMM is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with PMM. If not, see <http://www.gnu.org/licenses/>.
19 */
20 /*!
21  * @file pmm_cond.c
22  *
23  * @brief Functions to test system conditions
24  *
25  * this file contains the code for testing system conditions which may limit
26  * or permit the construction of models by the pmm daemon
27  */
28 #if HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <stdlib.h> // for getloadavg
33 #include <stdio.h> // for snprintf
34 #include <utmp.h> // for utmp
35 #include <paths.h> // for _UTMP_PATH
36 #include <sys/types.h> // for stat
37 #include <sys/stat.h> // for stat
38 #include <unistd.h> // for stat
39 #include <sys/param.h> // for MAXPATHLEN
40 
41 #include "pmm_model.h"
42 #include "pmm_cond.h"
43 
44 int ttystat(char *line, int sz);
45 int num_users();
46 
47 /*!
48  * checks that the tty a user is logged into (as per utmp) exists in /dev
49  *
50  * This indicates whether a user has an interactive session or not
51  *
52  *
53  * code comes from FreeBSD /usr/src/usr.bin/w/w.c
54  *
55  * @param line pointer to line of the utmp file
56  * @param sz size of the line
57  *
58  * @return 1 if user has a tty, 0 if user does not.
59  *
60  */
61 int
62 ttystat(char *line, int sz)
63 {
64  // TODO portable ?
65  static struct stat sb;
66  char ttybuf[MAXPATHLEN];
67 
68  //create the string /dev/<terminal user is logged into>
69  (void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
70 
71  //check that the terminal/file exists by stat'ing it
72  if(stat(ttybuf, &sb) == 0) {
73  return 1; // terminal exists, great
74  }
75  else {
76  return 0; // terminal does not exist, corrupt utmp line
77  }
78 }
79 
80 
81 /*!
82  * counts the number of users logged into a system by reading utmp returns
83  * the number of users logged in.
84  *
85  * code comes from FreeBSD /usr/src/usr.bin/w/w.c
86  *
87  * @return number of users logged in
88  */
89 int
91 {
92  //TODO portable on windows/NON-posix ?
93  FILE *ut;
94  struct utmp utmp;
95  int nusers;
96 
97  //open utmp file stream
98  if((ut = fopen(_PATH_UTMP, "r")) == NULL) {
99  printf("Error calculating users logged in, could not read file %s\n",
100  _PATH_UTMP);
101  exit(EXIT_FAILURE);
102  }
103 
104  nusers=0;
105  for(;fread(&utmp, sizeof(utmp), 1, ut);) {
106 
107  if(utmp.ut_name[0] == '\0') {
108  continue;
109  }
110 
111  //check that the tty if the user exists in /dev
112  if(!ttystat(utmp.ut_line, UT_LINESIZE)) {
113  continue; //corrupted record
114  }
115 
116  nusers++;
117  }
118  fclose(ut);
119 
120  return nusers;
121 }
122 
123 /*
124  * Test system for users
125  *
126  * @return 1 if users are logged into system, 0 if not
127  */
128 int cond_users() {
129  if(num_users() > 0) {
130  return 1;
131  } else {
132  return 0;
133  }
134 }
135 
136 /*!
137  * test system for idleness
138  *
139  * true if 5 minute load is below 0.1
140  *
141  * return 0 if not idle, 1 if idle
142  */
143 int cond_idle() {
144  double loadavg[3];
145 
146  if(!getloadavg(loadavg, 3)) {
147  printf("Error, could not retreive system load averages.\n");
148  exit(EXIT_FAILURE);
149  }
150 
151  // if load is below 0.10, i.e. 10% untilisation
152  if(loadavg[1] < 0.10) {
153  return 1;
154  }
155  else {
156  return 0;
157  }
158 }
159 
160 /*!
161  * check if conditions for execution of a routine are satisfied and
162  * set executable parameter of routine accordingly
163  *
164  * @param r pointer to the routine
165  *
166  * @return 0 if routine is not execuable based on conditions, 1 if
167  * it is
168  */
169 int
171 {
172  // TODO add CC_UNTIL and CC_PERIODIC to this function ...
173  // TODO permit multiple conditions in one routine
174  // TODO permit system wide conditions applicable to all routines
175  //
176  r->executable = 0;
177  if(r->condition == CC_NOW) {
178  r->executable = 1;
179 
180  }
181  else if(r->condition == CC_IDLE) {
182  if(cond_idle()) {
183  r->executable = 1;
184  }
185  }
186  else if(r->condition == CC_NOUSERS) {
187  if(!cond_users()) {
188  r->executable = 1;
189  }
190  }
191 
192  return r->executable;
193 }
194