xref: /dragonfly/usr.bin/dsynth/subs.c (revision a361ab312536a661d74caf5630c7ae20bcd8e3e4)
1 /*
2  * Copyright (c) 2019-2020 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * This code uses concepts and configuration based on 'synth', by
8  * John R. Marino <draco@marino.st>, which was written in ada.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  * 3. Neither the name of The DragonFly Project nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific, prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include "dsynth.h"
39 
40 struct logerrinfo {
41           struct logerrinfo *next;
42           char      *logid;
43           pid_t     pid;
44           long      seq;
45           int       exited;
46 };
47 
48 buildenv_t *BuildEnv;
49 static buildenv_t **BuildEnvTail = &BuildEnv;
50 
51 extern char **environ;
52 
53 static void *dexec_logerr_thread(void *info);
54 
55 #define EINFO_HSIZE 1024
56 #define EINFO_HMASK (EINFO_HSIZE - 1)
57 
58 static struct logerrinfo *EInfo[EINFO_HSIZE];
59 static pthread_t ETid;
60 static int EFds[2];
61 static pthread_cond_t ECond;
62 
63 static __inline
64 struct logerrinfo **
einfohash(pid_t pid)65 einfohash(pid_t pid)
66 {
67           return(&EInfo[pid & EINFO_HMASK]);
68 }
69 
70 __dead2 void
_dfatal(const char * file __unused,int line __unused,const char * func,int do_errno,const char * ctl,...)71 _dfatal(const char *file __unused, int line __unused, const char *func,
72           int do_errno, const char *ctl, ...)
73 {
74           va_list va;
75 
76           fprintf(stderr, "%s: ", func);
77           va_start(va, ctl);
78           vfprintf(stderr, ctl, va);
79           va_end(va);
80           if (do_errno & 1)
81                     fprintf(stderr, ": %s", strerror(errno));
82           fprintf(stderr, "\n");
83           fflush(stderr);
84 
85           if (do_errno & 2)
86                     kill(getpid(), SIGQUIT);
87           exit(1);
88 }
89 
90 void
_ddprintf(int tab,const char * ctl,...)91 _ddprintf(int tab, const char *ctl, ...)
92 {
93           va_list va;
94 
95           if (tab)
96                     printf("%*.*s", tab, tab, "");
97           va_start(va, ctl);
98           vfprintf(stdout, ctl, va);
99           va_end(va);
100 }
101 
102 char *
strdup_or_null(char * str)103 strdup_or_null(char *str)
104 {
105           if (str && str[0])
106                     return(strdup(str));
107           return NULL;
108 }
109 
110 static const char *DLogNames[] = {
111           "00_last_results.log",
112           "01_success_list.log",
113           "02_failure_list.log",
114           "03_ignored_list.log",
115           "04_skipped_list.log",
116           "05_abnormal_command_output.log",
117           "06_obsolete_packages.log",
118           "07_debug.log",
119 };
120 
121 static int DLogFd[DLOG_COUNT];
122 static pthread_mutex_t DLogFdMutex;
123 
124 #define arysize(ary)          (sizeof((ary)) / sizeof((ary)[0]))
125 
126 static int
dlogfd(int which,int modes)127 dlogfd(int which, int modes)
128 {
129           char *path;
130           int fd;
131 
132           which &= DLOG_MASK;
133           if ((fd = DLogFd[which]) > 0)
134                     return fd;
135           pthread_mutex_lock(&DLogFdMutex);
136           if ((fd = DLogFd[which]) <= 0) {
137                     asprintf(&path, "%s/%s", LogsPath, DLogNames[which]);
138                     fd = open(path, modes, 0666);
139                     DLogFd[which] = fd;
140                     free(path);
141           }
142           pthread_mutex_unlock(&DLogFdMutex);
143 
144           return fd;
145 }
146 
147 
148 void
dlogreset(void)149 dlogreset(void)
150 {
151           int i;
152 
153           ddassert(DLOG_COUNT == arysize(DLogNames));
154           for (i = 0; i < DLOG_COUNT; ++i) {
155                     if (DLogFd[i] > 0) {
156                               close(DLogFd[i]);
157                               DLogFd[i] = -1;
158                     }
159                     (void)dlogfd(i, O_RDWR|O_CREAT|O_TRUNC|O_APPEND);
160           }
161 }
162 
163 void
_dlog(int which,const char * ctl,...)164 _dlog(int which, const char *ctl, ...)
165 {
166           va_list va;
167           char *buf;
168           char *ptr;
169           size_t len;
170           int fd;
171           int filter;
172 
173           filter = which;
174           which &= DLOG_MASK;
175 
176           ddassert((uint)which < DLOG_COUNT);
177           va_start(va, ctl);
178           vasprintf(&buf, ctl, va);
179           va_end(va);
180           len = strlen(buf);
181 
182           /*
183            * The special sequence ## right-justfies the text after the ##.
184            *
185            * NOTE: Alignment test includes \n so use 80 instead of 79 to
186            *         leave one char unused on a 80-column terminal.
187            */
188           if ((ptr = strstr(buf, "##")) != NULL) {
189                     size_t l2;
190                     size_t l1;
191                     char *b2;
192                     int spc;
193 
194                     l1 = (int)(ptr - buf);
195                     l2 = len - l1 - 2;
196                     if (l1 <= 80 - l2) {
197                               spc = 80 - l1 - l2;
198                               buf[l1] = 0;
199                               asprintf(&b2, "%s%*.*s%s",
200                                          buf, spc, spc, "", ptr + 2);
201                     } else {
202                               buf[l1] = 0;
203                               asprintf(&b2, "%s%s", buf, ptr + 2);
204                     }
205                     len = strlen(b2);
206                     free(buf);
207                     buf = b2;
208           }
209 
210           /*
211            * All logs also go to log 00.
212            */
213           if (which != DLOG_ALL) {
214                     fd = dlogfd(DLOG_ALL, O_RDWR|O_CREAT|O_APPEND);
215                     if (fd > 0)
216                               write(fd, buf, len);
217           }
218 
219           /*
220            * Nominal log target
221            */
222           fd = dlogfd(which, O_RDWR|O_CREAT|O_APPEND);
223           write(fd, buf, len);
224 
225           /*
226            * If ncurses is not being used, all log output also goes
227            * to stdout, unless filtered.
228            */
229           if ((UseNCurses == 0 || (filter & DLOG_STDOUT)) &&
230               (filter & DLOG_FILTER) == 0) {
231                     if (ColorOpt) {
232                               if (filter & DLOG_GRN)
233                                         write(1, "\x1b[0;32m", 7);
234                               if (filter & DLOG_RED)
235                                         write(1, "\x1b[0;31m", 7);
236                     }
237                     write(1, buf, len);
238                     if (ColorOpt && (filter & (DLOG_GRN|DLOG_RED))) {
239                               write(1, "\x1b[0;39m", 7);
240                     }
241           }
242           free(buf);
243 }
244 
245 int
dlog00_fd(void)246 dlog00_fd(void)
247 {
248           return(dlogfd(DLOG_ALL, O_RDWR|O_CREAT|O_APPEND));
249 }
250 
251 /*
252  * Bulk and Build environment control.  These routines are only called
253  * unthreaded or when dsynth threads are idle.
254  */
255 void
addbuildenv(const char * label,const char * data,int type)256 addbuildenv(const char *label, const char *data, int type)
257 {
258           buildenv_t *env;
259 
260           env = calloc(1, sizeof(*env));
261           env->a1 = strdup(label);
262           env->a2 = strdup(data);
263           env->label = env->a1;
264           env->data = env->a2;
265           env->type = type;
266           *BuildEnvTail = env;
267           BuildEnvTail = &env->next;
268 }
269 
270 void
delbuildenv(const char * label)271 delbuildenv(const char *label)
272 {
273           buildenv_t **envp;
274           buildenv_t *env;
275 
276           envp = &BuildEnv;
277           while ((env = *envp) != NULL) {
278                     if (strcmp(env->label, label) == 0) {
279                               *envp = env->next;
280                               if (env->a1)
281                                         free(env->a1);
282                               if (env->a2)
283                                         free(env->a2);
284                               free(env);
285                     } else {
286                               envp = &env->next;
287                     }
288           }
289           BuildEnvTail = envp;
290 }
291 
292 const char *
getbuildenv(const char * label)293 getbuildenv(const char *label)
294 {
295           buildenv_t **envp;
296           buildenv_t *env;
297 
298           envp = &BuildEnv;
299           while ((env = *envp) != NULL) {
300                     if (strcmp(env->label, label) == 0)
301                               return env->data;
302                     envp = &env->next;
303           }
304           return NULL;
305 }
306 
307 void
freestrp(char ** strp)308 freestrp(char **strp)
309 {
310           if (*strp) {
311                     free(*strp);
312                     *strp = NULL;
313           }
314 }
315 
316 void
dupstrp(char ** strp)317 dupstrp(char **strp)
318 {
319           if (*strp)
320                     *strp = strdup(*strp);
321 }
322 
323 int
ipcreadmsg(int fd,wmsg_t * msg)324 ipcreadmsg(int fd, wmsg_t *msg)
325 {
326           size_t res;
327           ssize_t r;
328           char *ptr;
329 
330           res = sizeof(*msg);
331           ptr = (char *)(void *)msg;
332           while (res) {
333                     r = read(fd, ptr, res);
334                     if (r <= 0) {
335                               if (errno == EINTR)
336                                         continue;
337                               return -1;
338                     }
339                     res -= (size_t)r;
340                     ptr += r;
341           }
342           return 0;
343 }
344 
345 int
ipcwritemsg(int fd,wmsg_t * msg)346 ipcwritemsg(int fd, wmsg_t *msg)
347 {
348           size_t res;
349           ssize_t r;
350           char *ptr;
351 
352           res = sizeof(*msg);
353           ptr = (char *)(void *)msg;
354           while (res) {
355                     r = write(fd, ptr, res);
356                     if (r < 0) {
357                               if (errno == EINTR)
358                                         continue;
359                               return -1;
360                     }
361                     res -= (size_t)r;
362                     ptr += r;
363           }
364           return 0;
365 }
366 
367 int
askyn(const char * ctl,...)368 askyn(const char *ctl, ...)
369 {
370           va_list va;
371           char buf[256];
372           int res = 0;
373 
374           if (YesOpt)
375                     return 1;
376 
377           for (;;) {
378                     va_start(va, ctl);
379                     vprintf(ctl, va);
380                     va_end(va);
381                     fflush(stdout);
382                     if (fgets(buf, sizeof(buf), stdin) == NULL)
383                               break;
384                     if (buf[0] == 'y' || buf[0] == 'Y') {
385                               res = 1;
386                               break;
387                     }
388                     if (buf[0] == 'n' || buf[0] == 'N') {
389                               res = 0;
390                               break;
391                     }
392                     printf("Please type y/n\n");
393           }
394           return res;
395 }
396 
397 /*
398  * Get swap% used 0.0-1.0.
399  *
400  * NOTE: This routine is intended to return quickly.
401  *
402  * NOTE: swap_cache (caching for hard drives) is persistent and should
403  *         not be counted for our purposes.
404  */
405 double
getswappct(int * noswapp)406 getswappct(int *noswapp)
407 {
408           long swap_size = 0;
409           long swap_anon = 0;
410           long swap_cache __unused = 0;
411           size_t len;
412           double dswap;
413 
414           len = sizeof(swap_size);
415           sysctlbyname("vm.swap_size", &swap_size, &len, NULL, 0);
416           len = sizeof(swap_size);
417           sysctlbyname("vm.swap_anon_use", &swap_anon, &len, NULL, 0);
418           len = sizeof(swap_size);
419           sysctlbyname("vm.swap_cache_use", &swap_cache, &len, NULL, 0);
420           if (swap_size) {
421                     dswap = (double)(swap_anon /*+swap_cache*/) / (double)swap_size;
422                     *noswapp = 0;
423           } else {
424                     dswap = 0.0;
425                     *noswapp = 1;
426           }
427           return dswap;
428 }
429 
430 /*
431  * dexec_open()/fgets/dexec_close()
432  *
433  * Similar to popen() but directly exec()s the argument list (cav[0] must
434  * be an absolute path).
435  *
436  * If xenv is non-NULL its an array of local buildenv_t's to be used.
437  * The array is terminated with a NULL xenv->label.
438  *
439  * If with_env is non-zero the configured environment is included.
440  *
441  * If with_mvars is non-zero the make environment is passed as VAR=DATA
442  * elements on the command line.
443  */
444 FILE *
dexec_open(const char * logid,const char ** cav,int cac,pid_t * pidp,buildenv_t * xenv,int with_env,int with_mvars)445 dexec_open(const char *logid, const char **cav, int cac,
446              pid_t *pidp, buildenv_t *xenv, int with_env, int with_mvars)
447 {
448           buildenv_t *benv;
449           const char **cenv;
450           char *allocary[MAXCAC*2];
451           int env_basei;
452           int envi;
453           int alloci;
454           int nullfd;
455           int fds[2];         /* stdout */
456           pid_t pid;
457           FILE *fp;
458           struct logerrinfo *einfo;
459           static int warned;
460 
461           /*
462            * Error logging thread setup
463            */
464           if (ETid == 0) {
465                     pthread_mutex_lock(&DLogFdMutex);
466                     if (ETid == 0) {
467                               if (socketpair(AF_UNIX, SOCK_DGRAM, 0, EFds) < 0)
468                                         dfatal_errno("socketpair");
469 #ifdef SO_PASSCRED
470                               int optval = 1;
471                               if (setsockopt(EFds[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) {
472                                         if (warned == 0) {
473                                                   warned = 1;
474                                                   fprintf(stderr, "SO_PASSCRED not supported\n");
475                                         }
476                               }
477 #endif
478 
479                               pthread_cond_init(&ECond, NULL);
480                               pthread_create(&ETid, NULL, dexec_logerr_thread, NULL);
481                     }
482                     pthread_mutex_unlock(&DLogFdMutex);
483           }
484 
485           env_basei = 0;
486 #if 0
487           /*
488            * For now we are ignoring the passed-in environment, so don't
489            * copy the existing environment into the exec environment.
490            */
491           while (environ[env_basei])
492                     ++env_basei;
493 #endif
494           cenv = calloc(env_basei + MAXCAC, sizeof(char *));
495           for (envi = 0; envi < env_basei; ++envi)
496                     cenv[envi] = environ[envi];
497 
498           alloci = 0;
499           for (benv = BuildEnv; benv; benv = benv->next) {
500                     if (with_mvars &&
501                         (benv->type & BENV_CMDMASK) == BENV_MAKECONF) {
502                               asprintf(&allocary[alloci], "%s=%s",
503                                          benv->label, benv->data);
504                               cav[cac++] = allocary[alloci];
505                               ++alloci;
506                     }
507                     if (with_env &&
508                         (benv->type & BENV_PKGLIST) &&
509                         (benv->type & BENV_CMDMASK) == BENV_ENVIRONMENT) {
510                               asprintf(&allocary[alloci], "%s=%s",
511                                          benv->label, benv->data);
512                               cenv[envi++] = allocary[alloci];
513                               ++alloci;
514                     }
515                     ddassert(cac < MAXCAC && envi - env_basei < MAXCAC);
516           }
517 
518           /*
519            * Extra environment specific to this particular dexec
520            */
521           while (xenv && xenv->label) {
522                     asprintf(&allocary[alloci], "%s=%s",
523                                xenv->label, xenv->data);
524                     cenv[envi++] = allocary[alloci];
525                     ++alloci;
526                     ++xenv;
527           }
528 
529           cav[cac] = NULL;
530           cenv[envi] = NULL;
531 
532           if (pipe2(fds, O_CLOEXEC) < 0)
533                     dfatal_errno("pipe");
534           nullfd = open("/dev/null", O_RDWR | O_CLOEXEC);
535           if (nullfd < 0)
536                     dfatal_errno("open(\"/dev/null\")");
537 
538           /*
539            * We have to be very careful using vfork(), do only the bare
540            * minimum necessary in the child to set it up and exec it.
541            */
542           pid = vfork();
543           if (pid == 0) {
544 #if 0
545                     int i;
546                     printf("%s", cav[0]);
547                     for (i = 0; cav[i]; ++i)
548                               printf(" %s", cav[i]);
549                     printf("\n");
550                     printf("ENV: ");
551                     for (i = 0; cenv[i]; ++i)
552                               printf(" %s", cenv[i]);
553 #endif
554 
555                     if (fds[1] != 1) {
556                               dup2(fds[1], 1);
557                               close(fds[1]);
558                     }
559                     if (EFds[1] != 2) {
560                               dup2(EFds[1], 2);
561                               close(EFds[1]);
562                     }
563                     close(fds[0]);                /* safety */
564                     close(EFds[0]);               /* safety */
565                     dup2(nullfd, 0);    /* no questions! */
566                     closefrom(3);                 /* be nice */
567 
568                     /*
569                      * Self-nice to be nice (ignore any error)
570                      */
571                     if (NiceOpt)
572                               setpriority(PRIO_PROCESS, 0, NiceOpt);
573 
574                     /*
575                      * Throw in some capability restrictions
576                      */
577                     set_capability_restrictions();
578 
579                     execve(cav[0], (void *)cav, (void *)cenv);
580                     write(2, "EXEC FAILURE\n", 13);
581                     _exit(1);
582           }
583           close(nullfd);
584           close(fds[1]);
585           if (pid < 0) {
586                     close(fds[0]);
587                     dfatal_errno("vfork failed");
588           }
589           fp = fdopen(fds[0], "r");
590           *pidp = pid;
591 
592           /*
593            * einfo setup
594            */
595           einfo = calloc(1, sizeof(*einfo));
596           if (logid)
597                     einfo->logid = strdup(logid);
598 
599           pthread_mutex_lock(&DLogFdMutex);
600           einfo->pid = pid;
601           einfo->next = *einfohash(pid);
602           *einfohash(pid) = einfo;
603           pthread_cond_signal(&ECond);
604           pthread_mutex_unlock(&DLogFdMutex);
605 
606           while (--alloci >= 0)
607                     free(allocary[alloci]);
608           free(cenv);
609 
610           return fp;
611 }
612 
613 int
dexec_close(FILE * fp,pid_t pid)614 dexec_close(FILE *fp, pid_t pid)
615 {
616           struct logerrinfo **einfop;
617           struct logerrinfo *einfo;
618           pid_t rpid;
619           int status;
620 
621           fclose(fp);
622           while ((rpid = waitpid(pid, &status, 0)) != pid) {
623                     if (rpid < 0) {
624                               if (errno == EINTR)
625                                         continue;
626                               return 1;
627                     }
628           }
629 
630           pthread_mutex_lock(&DLogFdMutex);
631           einfop = einfohash(pid);
632           while ((einfo = *einfop) != NULL) {
633                     if (einfo->pid == pid) {
634                               einfo->exited = 1;
635                               break;
636                     }
637                     einfop = &einfo->next;
638           }
639           pthread_mutex_unlock(&DLogFdMutex);
640 
641           return (WEXITSTATUS(status));
642 }
643 
644 static void *
dexec_logerr_thread(void * dummy __unused)645 dexec_logerr_thread(void *dummy __unused)
646 {
647           char buf[4096];
648           union {
649                     char cbuf[CMSG_SPACE(sizeof(struct ucred))];
650                     struct cmsghdr cbuf_align;
651           } cmsg_buf;
652           struct cmsghdr *cmsg;
653           struct logerrinfo **einfop;
654           struct logerrinfo *einfo;
655           struct msghdr msg;
656           struct iovec iov;
657           ssize_t len;
658           int mflags = MSG_DONTWAIT;
659           int fd;
660 
661           pthread_detach(pthread_self());
662 
663           msg.msg_name = NULL;
664           msg.msg_namelen = 0;
665           msg.msg_iov = &iov;
666 
667           msg.msg_control = cmsg_buf.cbuf;
668           msg.msg_controllen = sizeof(cmsg_buf.cbuf);
669 
670           fd = EFds[0];
671           for (;;) {
672                     int i;
673 
674                     msg.msg_iovlen = 1;
675                     iov.iov_base = buf;
676                     iov.iov_len = sizeof(buf) - 1;
677 
678                     /*
679                      * Wait for message, if none are pending then clean-up
680                      * exited einfos (this ensures that we have flushed all
681                      * error output before freeing the structure).
682                      *
683                      * Don't obtain the mutex until we really need it.  The
684                      * parent thread can only 'add' einfo entries to the hash
685                      * table so we are basically scan-safe.
686                      */
687                     len = recvmsg(fd, &msg, mflags);
688                     if (len < 0) {
689                               if (errno != EAGAIN) {        /* something messed up */
690                                         fprintf(stderr, "ERRNO %d\n", errno);
691                                         break;
692                               }
693 
694                               for (i = 0; i < EINFO_HSIZE; ++i) {
695                                         einfo = EInfo[i];
696                                         while (einfo) {
697                                                   if (einfo->exited)
698                                                             break;
699                                                   einfo = einfo->next;
700                                         }
701                                         if (einfo == NULL)
702                                                   continue;
703                                         pthread_mutex_lock(&DLogFdMutex);
704                                         einfop = &EInfo[i];
705                                         while ((einfo = *einfop) != NULL) {
706                                                   if (einfo->exited) {
707                                                             *einfop = einfo->next;
708                                                             if (einfo->logid)
709                                                                       free(einfo->logid);
710                                                             free(einfo);
711                                                   } else {
712                                                             einfop = &einfo->next;
713                                                   }
714                                         }
715                                         pthread_mutex_unlock(&DLogFdMutex);
716                               }
717                               mflags = 0;
718                               continue;
719                     }
720 
721                     /*
722                      * Process SCM_CREDS, if present.  Throw away SCM_RIGHTS
723                      * if some sub-process stupidly sent it.
724                      */
725                     einfo = NULL;
726                     mflags = MSG_DONTWAIT;
727 
728                     if (len && buf[len-1] == '\n')
729                               --len;
730                     buf[len] = 0;
731 
732                     for (cmsg = CMSG_FIRSTHDR(&msg);
733                          cmsg;
734                          cmsg = CMSG_NXTHDR(&msg, cmsg)) {
735                               struct cmsgcred *cred;
736                               int *fds;
737                               int n;
738 
739                               if (cmsg->cmsg_level != SOL_SOCKET)
740                                         continue;
741 
742                               switch(cmsg->cmsg_type) {
743                               case SCM_CREDS:
744 
745                                         cred = (void *)CMSG_DATA(cmsg);
746 
747                                         einfo = *einfohash(cred->cmcred_pid);
748                                         while (einfo && einfo->pid != cred->cmcred_pid)
749                                                   einfo = einfo->next;
750                                         break;
751                               case SCM_RIGHTS:
752                                         fds = (void *)CMSG_DATA(cmsg);
753                                         n = (cmsg->cmsg_len - sizeof(cmsg)) /
754                                             sizeof(int);
755                                         for (i = 0; i < n; ++i)
756                                                   close(fds[i]);
757                                         break;
758                               }
759                     }
760 
761                     if (einfo && einfo->logid) {
762                               dlog(DLOG_ALL | DLOG_STDOUT,
763                                    "%s: %s\n",
764                                    einfo->logid, buf);
765                     } else {
766                               dlog(DLOG_ALL | DLOG_STDOUT, "%s", buf);
767                     }
768           }
769           return NULL;
770 }
771 
772 const char *
getphasestr(worker_phase_t phaseid)773 getphasestr(worker_phase_t phaseid)
774 {
775           const char *phase;
776 
777           switch(phaseid) {
778           case PHASE_PENDING:
779                     phase = "pending";
780                     break;
781           case PHASE_INSTALL_PKGS:
782                     phase = "install-pkgs";
783                     break;
784           case PHASE_CHECK_SANITY:
785                     phase = "check-sanity";
786                     break;
787           case PHASE_PKG_DEPENDS:
788                     phase = "pkg-depends";
789                     break;
790           case PHASE_FETCH_DEPENDS:
791                     phase = "fetch-depends";
792                     break;
793           case PHASE_FETCH:
794                     phase = "fetch";
795                     break;
796           case PHASE_CHECKSUM:
797                     phase = "checksum";
798                     break;
799           case PHASE_EXTRACT_DEPENDS:
800                     phase = "extract-depends";
801                     break;
802           case PHASE_EXTRACT:
803                     phase = "extract";
804                     break;
805           case PHASE_PATCH_DEPENDS:
806                     phase = "patch-depends";
807                     break;
808           case PHASE_PATCH:
809                     phase = "patch";
810                     break;
811           case PHASE_BUILD_DEPENDS:
812                     phase = "build-depends";
813                     break;
814           case PHASE_LIB_DEPENDS:
815                     phase = "lib-depends";
816                     break;
817           case PHASE_CONFIGURE:
818                     phase = "configure";
819                     break;
820           case PHASE_BUILD:
821                     phase = "build";
822                     break;
823           case PHASE_RUN_DEPENDS:
824                     phase = "run-depends";
825                     break;
826           case PHASE_STAGE:
827                     phase = "stage";
828                     break;
829           case PHASE_TEST:
830                     phase = "test";
831                     break;
832           case PHASE_CHECK_PLIST:
833                     phase = "check-plist";
834                     break;
835           case PHASE_PACKAGE:
836                     phase = "package";
837                     break;
838           case PHASE_INSTALL:
839                     phase = "install";
840                     break;
841           case PHASE_DEINSTALL:
842                     phase = "deinstall";
843                     break;
844           case PHASE_DUMP_ENV:
845                     phase = "dump-env";
846                     break;
847           case PHASE_DUMP_VAR:
848                     phase = "dump-var";
849                     break;
850           case PHASE_SHOW_CONFIG:
851                     phase = "show-config";
852                     break;
853           case PHASE_DUMP_MAKECONF:
854                     phase = "make-conf";
855                     break;
856           default:
857                     phase = "Run-Unknown";
858                     break;
859           }
860           return phase;
861 }
862 
863 int
readlogline(monitorlog_t * log,char ** bufp)864 readlogline(monitorlog_t *log, char **bufp)
865 {
866           int r;
867           int n;
868 
869           /*
870            * Reset buffer as an optimization to avoid unnecessary
871            * shifts.
872            */
873           *bufp = NULL;
874           if (log->buf_beg == log->buf_end) {
875                     log->buf_beg = 0;
876                     log->buf_end = 0;
877                     log->buf_scan = 0;
878           }
879 
880           /*
881            * Look for newline, handle discard mode
882            */
883 again:
884           for (n = log->buf_scan; n < log->buf_end; ++n) {
885                     if (log->buf[n] == '\n') {
886                               *bufp = log->buf + log->buf_beg;
887                               r = n - log->buf_beg;
888                               log->buf_beg = n + 1;
889                               log->buf_scan = n + 1;
890 
891                               if (log->buf_discard_mode == 0)
892                                         return r;
893                               log->buf_discard_mode = 0;
894                               goto again;
895                     }
896           }
897 
898           /*
899            * Handle overflow
900            */
901           if (n == sizeof(log->buf)) {
902                     if (log->buf_beg) {
903                               /*
904                                * Shift the buffer to make room and read more data.
905                                */
906                               bcopy(log->buf + log->buf_beg,
907                                     log->buf,
908                                     n - log->buf_beg);
909                               log->buf_end -= log->buf_beg;
910                               log->buf_scan -= log->buf_beg;
911                               n -= log->buf_beg;
912                               log->buf_beg = 0;
913                     } else if (log->buf_discard_mode) {
914                               /*
915                                * Overflow.  If in discard mode just throw it all
916                                * away.  Stay in discard mode.
917                                */
918                               log->buf_beg = 0;
919                               log->buf_end = 0;
920                               log->buf_scan = 0;
921                     } else {
922                               /*
923                                * Overflow.  If not in discard mode return a truncated
924                                * line and enter discard mode.
925                                *
926                                * The caller will temporarily set ptr[r] = 0 so make
927                                * sure that does not overflow our buffer as we are not
928                                * at a newline.
929                                *
930                                * (log->buf_beg is 0);
931                                */
932                               *bufp = log->buf + log->buf_beg;
933                               r = n - 1;
934                               log->buf_beg = n;
935                               log->buf_scan = n;
936                               log->buf_discard_mode = 1;
937 
938                               return r;
939                     }
940           }
941 
942           /*
943            * Read more data.  If there is no data pending then return -1,
944            * otherwise loop up to see if more complete line(s) are available.
945            */
946           r = pread(log->fd,
947                       log->buf + log->buf_end,
948                       sizeof(log->buf) - log->buf_end,
949                       log->offset);
950           if (r <= 0)
951                     return -1;
952           log->offset += r;
953           log->buf_end += r;
954           goto again;
955 }
956 
957 uint32_t
crcDirTree(const char * path)958 crcDirTree(const char *path)
959 {
960           FTS *fts;
961           FTSENT *fen;
962           struct stat *st;
963           char *pav[2];
964           uint32_t crc;
965           uint32_t val;
966 
967           crc = 0;
968           pav[0] = strdup(path);
969           pav[1] = NULL;
970 
971           fts = fts_open(pav, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
972           if (fts == NULL)
973                     goto failed;
974           while ((fen = fts_read(fts)) != NULL) {
975                     if (fen->fts_info != FTS_F && fen->fts_info != FTS_SL)
976                               continue;
977                     /*
978                      * Ignore hidden dot files or ones ending with .core from the
979                      * calculated CRC sum to prevent unnecessary rebuilds.
980                      */
981                     if (fen->fts_name[0] == '.')
982                               continue;
983                     if (fen->fts_namelen >= 5 &&
984                         !strcmp(fen->fts_name + fen->fts_namelen - 5, ".core")) {
985                               continue;
986                     }
987 
988                     st = fen->fts_statp;
989 
990                     val = iscsi_crc32(&st->st_mtime, sizeof(st->st_mtime));
991                     val = iscsi_crc32_ext(&st->st_size, sizeof(st->st_size), val);
992                     val = iscsi_crc32_ext(fen->fts_path, fen->fts_pathlen, val);
993                     crc ^= val;
994           }
995           fts_close(fts);
996 failed:
997           free(pav[0]);
998 
999           return crc;
1000 }
1001 
1002 void
set_capability_restrictions(void)1003 set_capability_restrictions(void)
1004 {
1005           if (CapabilityRestrictions) {
1006 #if !defined(SYSCAP_UNAVAILABLE)
1007                     syscap_set(SYSCAP_RESTRICTEDROOT, __SYSCAP_ALL,
1008                                  NULL, 0);
1009                     syscap_set(SYSCAP_SENSITIVEROOT, __SYSCAP_ALL,
1010                                  NULL, 0);
1011                     syscap_set(SYSCAP_NONET_SENSITIVE, __SYSCAP_ALL,
1012                                  NULL, 0);
1013                     syscap_set(SYSCAP_NOVFS_SENSITIVE, __SYSCAP_ALL,
1014                                  NULL, 0);
1015                     syscap_set(SYSCAP_NOMOUNT, __SYSCAP_ALL,
1016                                  NULL, 0);
1017                     syscap_set(SYSCAP_NOJAIL, __SYSCAP_ALL,
1018                                  NULL, 0);
1019                     syscap_set(SYSCAP_NONET_RESPORT, __SYSCAP_ALL,
1020                                  NULL, 0);
1021                     syscap_set(SYSCAP_NONET_RAW, __SYSCAP_ALL,
1022                                  NULL, 0);
1023 #endif
1024           }
1025 }
1026