Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtterm / DtTermLogit.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: DtTermLogit.c /main/6 1998/07/23 18:08:59 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <time.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <sys/times.h>
40 #include <pwd.h>
41
42 #include <sys/utsname.h>
43
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netdb.h>
48
49 #define LOG_HOST        "hpcvusj.cv.hp.com"
50 #define LOG_ADDR        "15.0.209.35"
51 #define LOG_PORT        "4444"
52 #define WAIT_INTERVAL   5
53 #define RETRIES         5
54
55 /*
56 #define DEBUG_LOGIT
57 */
58 #ifdef  DEBUG_LOGIT
59 #define logitmain       main
60 #endif  /* DEBUG_LOGIT */
61
62 #ifdef  LOG_USAGE
63 void LogStart(int noFork, int argc, char **argv);
64 void LogFinish(int noFork, int sessions);
65 void LogBumpSessionCount(int count);
66 static void doLog(int noFork, char *msg);
67 static void ding(int sig);
68 static void autoLogFinish();
69
70 static time_t startTime;
71 static char *id = (char *) 0;
72 static int sessionCount = 0;
73 static int savedNoFork = 0;
74 static int sequence = 0;
75
76 void
77 LogBumpSessionCount(int count)
78 {
79     sessionCount += count;
80 }
81
82 void
83 LogStart(int noFork, int argc, char **argv)
84 {
85     char buffer[BUFSIZ];
86     char *c1;
87     char *c2;
88     char *tstring;
89     struct utsname uts;
90     struct passwd *pw;
91     int i1;
92
93     if (getenv("DTTERM_NOLOG")) {
94         return;
95     }
96
97     /* save away noFork... */
98     savedNoFork = noFork;
99
100     *buffer = '\0';
101     (void) strcat(buffer, "START");
102     (void) strcat(buffer, " USER=\"");
103     if (c1 = getlogin()) {
104         (void) strcat(buffer, c1);
105     } else {
106         if ((pw = getpwuid(getuid())) && pw->pw_name && *pw->pw_name) {
107             (void) strcat(buffer, pw->pw_name);
108         } else {
109             (void) strcat(buffer, "???");
110         }
111     }
112
113     (void) strcat(buffer, "\"" );
114     if (uname(&uts) != -1) {
115         (void) strcat(buffer, " UNAME=\"");
116         (void) strcat(buffer, uts.sysname);
117         (void) strcat(buffer, " ");
118         (void) strcat(buffer, uts.nodename);
119         (void) strcat(buffer, " ");
120         (void) strcat(buffer, uts.release);
121         (void) strcat(buffer, " ");
122         (void) strcat(buffer, uts.version);
123         (void) strcat(buffer, " ");
124         (void) strcat(buffer, uts.machine);
125         (void) strcat(buffer, "\"");
126     }
127
128     (void) time(&startTime);
129     tstring = ctime(&startTime);
130     /* remove the trailing '\n'... */
131     tstring[strlen(tstring) - 1] = '\0';
132     (void) strcat(buffer, " TIME=\"");
133     (void) strcat(buffer, tstring);
134     (void) strcat(buffer, "\"");
135
136     (void) strcat(buffer, " ARGS=\"");
137     c1 = buffer + strlen(buffer);
138     for (i1 = 0; i1 < argc; i1++) {
139         if (i1 > 0) {
140             *c1++ = ' ';
141         }
142
143         for (c2 = argv[i1]; *c2; c2++) {
144             if (iscntrl(*c2)) {
145                 *c1++ = '^';
146                 *c1++ = '@' + *c2;
147             } else if (isprint(*c2)) {
148                 switch (*c2) {
149                 case '"' :
150                 case '\\' :
151                 case ' ' :
152                     *c1++ = '\\';
153                     *c1++ = *c2;
154                     break;
155
156                 default:
157                     *c1++ = *c2;
158                     break;
159                 }
160             } else {
161                 *c1++ = '\\';
162                 *c1++ = '0' + (*c2 / 0100) & 07;
163                 *c1++ = '0' + (*c2 / 0010) & 07;
164                 *c1++ = '0' + (*c2 / 0001) & 07;
165             }
166         }
167     }
168     *c1++ = '"';
169     *c1++ = '\0';
170
171     (void) doLog(noFork, buffer);
172     atexit(autoLogFinish);
173 }
174
175 void
176 LogFinish(int noFork, int sessions)
177 {
178     char buffer[BUFSIZ];
179     char buffer2[BUFSIZ];
180     time_t now;
181     long cpuTime;
182     int i1;
183     struct tms tms;
184     long clkTick = 0;
185
186     if (getenv("DTTERM_NOLOG")) {
187         return;
188     }
189
190     *buffer = '\0';
191     (void) strcat(buffer, "FINISH");
192
193     (void) sprintf(buffer2, " SESSIONS=\"%d\"", sessions);
194     (void) strcat(buffer, buffer2);
195
196     (void) time(&now);
197     (void) sprintf(buffer2, " ELAPSED=\"%ld\"", now - startTime);
198     (void) strcat(buffer, buffer2);
199
200     (void) times(&tms);
201
202     clkTick = sysconf(_SC_CLK_TCK);
203     if (clkTick) {
204         cpuTime = (tms.tms_utime = tms.tms_stime) / clkTick;
205     } else {
206         cpuTime = -1;
207     }
208         
209     (void) sprintf(buffer2, " CPU=\"%ld\"", cpuTime);
210     (void) strcat(buffer, buffer2);
211
212     (void) doLog(noFork, buffer);
213 }
214
215 static void
216 autoLogFinish()
217 {
218     (void) LogFinish(savedNoFork, sessionCount);
219 }
220
221 static void
222 doLog(int noFork, char *msg)
223 {
224     char *sbuffer;
225     char rbuffer[BUFSIZ];
226     char thisId[BUFSIZ];
227     static int s = -1;
228     int i1;
229     int len;
230     char *c1;
231     int retries = RETRIES;
232     struct hostent *hp;
233     static struct sockaddr_in myaddr_in;
234     static struct sockaddr_in servaddr_in;
235     struct sigaction sa;
236     struct sigaction oldSa;
237     time_t now;
238     pid_t pid;
239     int doRead;
240
241     sbuffer = malloc(2*BUFSIZ);
242     if (!id) {
243         (void) time(&now);
244         (void) sprintf(sbuffer, "%ld.%ld", now, (long)getpid());
245         id = strdup(sbuffer);
246     }
247         
248     /* bump the sequence number before we fork()...  */
249     (void) sequence++;
250
251     if (noFork) {
252         pid = 0;
253     } else {
254         pid = fork();
255     }
256
257     if (pid != 0) {
258         return;
259     }
260
261     if (s < 0) {
262         (void) memset(&servaddr_in, '\0', sizeof(servaddr_in));
263         (void) memset(&myaddr_in, '\0', sizeof(myaddr_in));
264
265         /* set up the server address... */
266         servaddr_in.sin_family = AF_INET;
267         hp = gethostbyname((c1 = getenv("DTTERM_LOG_HOST")) ? c1 : LOG_HOST);
268
269         if (hp) {
270             servaddr_in.sin_addr.s_addr =
271                     ((struct in_addr *)(hp->h_addr))->s_addr;
272         } else {
273             servaddr_in.sin_addr.s_addr =
274                     inet_addr((c1 = getenv("DTTERM_LOG_ADDR")) ? c1 : LOG_ADDR);
275         }
276             
277         servaddr_in.sin_port =
278                 atoi((c1 = getenv("DTTERM_LOG_PORT")) ? c1 : LOG_PORT);
279
280         /* create the socket... */
281         s = socket(AF_INET, SOCK_DGRAM, 0);
282         if (s < 0) {
283             if (!noFork) {
284                 (void) _exit(1);
285             }
286             return;
287         }
288
289         /* bind to some local address so we can get a reply... */
290         myaddr_in.sin_family = AF_INET;
291         myaddr_in.sin_port = 0;
292         myaddr_in.sin_addr.s_addr = INADDR_ANY;
293         if (bind(s, &myaddr_in, sizeof(myaddr_in)) == -1) {
294             if (!noFork) {
295                 (void) _exit(1);
296             }
297             (void) close(s);
298             s = -1;
299             return;
300         }
301     }
302
303     if (!noFork) {
304         for (i1 = 0; i1 < _NFILE; i1++) {
305             if (i1 != s) {
306                 (void) close(i1);
307             }
308         }
309     }
310
311     (void) sprintf(thisId, "ID=\"%s.%d\"", id, sequence);
312     (void) sprintf(sbuffer, "%s %s", thisId, msg);
313
314     /* set up a signal handler... */
315     (void) sigemptyset(&sa.sa_mask);
316     sa.sa_flags = 0;
317     sa.sa_handler = ding;
318
319     (void) sigaction(SIGALRM, &sa, &oldSa);
320
321     /* try to send the message... */
322     while (retries > 0) {
323         if (sendto(s, sbuffer, strlen(sbuffer), 0, &servaddr_in,
324                 sizeof(servaddr_in)) < 0) {
325             if (!noFork) {
326                 (void) _exit(1);
327             }
328             (void) close(s);
329             s = -1;
330             return;
331         }
332
333         /* set a timeout... */
334         (void) alarm(WAIT_INTERVAL);
335
336         for (doRead = 1; doRead; ) {
337             if ((len = recv(s, rbuffer, sizeof(rbuffer) -1, 0)) < 0) {
338                 if (errno == EINTR) {
339                     if (--retries < 0) {
340                         /* give up... */
341                         if (!noFork) {
342                             (void) _exit(1);
343                         }
344                         (void) alarm(0);
345                         (void) close(s);
346                         s = -1;
347                         return;
348                     }
349
350                     /* we need to resend before doing another read... */
351                     doRead = 0;
352                 } else {
353                     /* give up... */
354                     if (!noFork) {
355                         (void) _exit(1);
356                     }
357                     (void) alarm(0);
358                     (void) close(s);
359                     s = -1;
360                     return;
361                 }
362             } else {
363                 /* got ack... */
364                 (void) alarm(0);
365
366                 /* null term the string... */
367                 rbuffer[len] = '\0';
368
369                 /* compare it against the id... */
370                 if (!strncmp(rbuffer, thisId, strlen(thisId))) {
371                     /* match... */
372                     doRead = 0;
373                     retries = 0;
374                     break;
375                 }
376                 /* ignore it and get the next one... */
377             }
378         }
379     }
380
381     /* clear the alarm and re-install the old signal handler... */
382     (void) alarm(0);
383     (void) sigaction(SIGALRM, &oldSa, (struct sigaction *) 0);
384     if (!noFork) {
385         _exit(0);
386     }
387     free(sbuffer);
388     return;
389 }
390                     
391 static void
392 ding(int sig)
393 {
394     /* since we are using sigaction, we don't need to reinstall
395      * ourself...
396      */
397 }
398
399 #ifdef  DEBUG_LOGIT
400 int
401 logitmain(int argc, char **argv)
402 {
403     int i1;
404     int noFork = 0;
405     extern char *optarg;
406     extern int optind, optopt;
407
408     while(EOF != (i1 = getopt(argc, argv, "f"))) {
409         switch(i1) {
410         case 'f' :
411             noFork = 1;
412             break;
413         }
414     }
415
416     (void) LogStart(noFork, argc, argv);
417     (void) sleep(5);
418     /*
419     (void) LogFinish(noFork, 123);
420     */
421 }
422 #endif  /* DEBUG_LOGIT */
423 #endif  /* LOG_USAGE */