usr.sbin/makefs: Sync with sys/vfs/hammer2
[dragonfly.git] / usr.bin / dsynth / config.c
blobb1204ad6af5b8bec09ba610eb44545f210c46fbb
1 /*
2 * Copyright (c) 2019 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * This code uses concepts and configuration based on 'synth', by
8 * John R. Marino <draco@marino.st>, which was written in ada.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
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.
38 #include "dsynth.h"
40 int UseCCache;
41 int UseUsrSrc;
42 int UseTmpfs;
43 int NumCores = 1;
44 int MaxBulk = 8;
45 int MaxWorkers = 8;
46 int MaxJobs = 8;
47 int UseTmpfsWork = 1;
48 int UseTmpfsBase = 1;
49 int UseNCurses = -1; /* indicates default operation (enabled) */
50 int LeveragePrebuilt = 0;
51 int WorkerProcFlags = 0;
52 int DeleteObsoletePkgs;
53 long PhysMem;
54 const char *OperatingSystemName = "Unknown"; /* e.g. "DragonFly" */
55 const char *ArchitectureName = "unknown"; /* e.g. "x86_64" */
56 const char *MachineName = "unknown"; /* e.g. "x86_64" */
57 const char *VersionName = "unknown"; /* e.g. "DragonFly 5.7-SYNTH" */
58 const char *VersionOnlyName = "unknown"; /* e.g. "5.7-SYNTH" */
59 const char *VersionFromParamHeader = "unknown"; /* e.g. "500704" */
60 const char *VersionFromSysctl = "unknown"; /* e.g. "500704" */
61 const char *ReleaseName = "unknown"; /* e.g. "5.7" */
62 const char *DPortsPath = "/usr/dports";
63 const char *CCachePath = DISABLED_STR;
64 const char *PackagesPath = "/build/synth/live_packages";
65 const char *RepositoryPath = "/build/synth/live_packages/All";
66 const char *OptionsPath = "/build/synth/options";
67 const char *DistFilesPath = "/build/synth/distfiles";
68 const char *BuildBase = "/build/synth/build";
69 const char *LogsPath = "/build/synth/logs";
70 const char *SystemPath = "/";
71 const char *UsePkgSufx = USE_PKG_SUFX;
72 char *StatsBase;
73 char *StatsFilePath;
74 char *StatsLockPath;
75 static const char *ProfileLabel = "[LiveSystem]"; /* with the brackets */
76 const char *Profile = "LiveSystem"; /* without the brackets */
77 int MetaVersion = 2;
80 * Hooks are scripts in ConfigBase
82 int UsingHooks;
83 const char *HookRunStart;
84 const char *HookRunEnd;
85 const char *HookPkgSuccess;
86 const char *HookPkgFailure;
87 const char *HookPkgIgnored;
88 const char *HookPkgSkipped;
90 const char *ConfigBase; /* The config base we found */
91 const char *ConfigBase1 = "/etc/dsynth";
92 const char *ConfigBase2 = "/usr/local/etc/dsynth";
94 static void parseConfigFile(const char *path);
95 static void parseProfile(const char *cpath, const char *path);
96 static char *stripwhite(char *str);
97 static int truefalse(const char *str);
98 static char *dokernsysctl(int m1, int m2);
99 static void getElfInfo(const char *path);
100 static char *checkhook(const char *scriptname);
102 void
103 ParseConfiguration(int isworker)
105 struct stat st;
106 size_t len;
107 int reln;
108 char *synth_config;
109 char *buf;
110 char *osreldate;
113 * Get the default OperatingSystemName, ArchitectureName, and
114 * ReleaseName.
116 OperatingSystemName = dokernsysctl(CTL_KERN, KERN_OSTYPE);
117 ArchitectureName = dokernsysctl(CTL_HW, HW_MACHINE_ARCH);
118 MachineName = dokernsysctl(CTL_HW, HW_MACHINE);
119 ReleaseName = dokernsysctl(CTL_KERN, KERN_OSRELEASE);
120 asprintf(&osreldate, "%d", getosreldate());
121 VersionFromSysctl = osreldate;
124 * Retrieve resource information from the system. Note that
125 * NumCores and PhysMem will also be used for dynamic load
126 * management.
128 NumCores = 1;
129 len = sizeof(NumCores);
130 if (sysctlbyname("hw.ncpu", &NumCores, &len, NULL, 0) < 0)
131 dfatal_errno("Cannot get hw.ncpu");
133 len = sizeof(PhysMem);
134 if (sysctlbyname("hw.physmem", &PhysMem, &len, NULL, 0) < 0)
135 dfatal_errno("Cannot get hw.physmem");
138 * Calculate nominal defaults.
140 MaxBulk = NumCores;
141 MaxWorkers = MaxBulk / 2;
142 if (MaxWorkers > (int)((PhysMem + (ONEGB/2)) / ONEGB))
143 MaxWorkers = (PhysMem + (ONEGB/2)) / ONEGB;
145 if (MaxBulk < 1)
146 MaxBulk = 1;
147 if (MaxWorkers < 1)
148 MaxWorkers = 1;
149 if (MaxJobs < 1)
150 MaxJobs = 1;
153 * Configuration file must exist. Look for it in
154 * "/etc/dsynth" and "/usr/local/etc/dsynth".
156 ConfigBase = ConfigBase1;
157 asprintf(&synth_config, "%s/dsynth.ini", ConfigBase1);
158 if (stat(synth_config, &st) < 0) {
159 ConfigBase = ConfigBase2;
160 asprintf(&synth_config, "%s/dsynth.ini", ConfigBase2);
163 if (stat(synth_config, &st) < 0) {
164 dfatal("Configuration file missing, "
165 "could not find %s/dsynth.ini or %s/dsynth.ini\n",
166 ConfigBase1,
167 ConfigBase2);
171 * Check to see what hooks we have
173 HookRunStart = checkhook("hook_run_start");
174 HookRunEnd = checkhook("hook_run_end");
175 HookPkgSuccess = checkhook("hook_pkg_success");
176 HookPkgFailure = checkhook("hook_pkg_failure");
177 HookPkgIgnored = checkhook("hook_pkg_ignored");
178 HookPkgSkipped = checkhook("hook_pkg_skipped");
181 * Parse the configuration file(s). This may override some of
182 * the above defaults.
184 parseConfigFile(synth_config);
185 parseProfile(synth_config, ProfileLabel);
188 * Figure out whether CCache is configured. Also set UseUsrSrc
189 * if it exists under the system path.
191 * Not supported for the moment
193 if (strcmp(CCachePath, "disabled") != 0) {
194 /* dfatal("Directory_ccache is not supported, please\n"
195 " set to 'disabled'\n"); */
196 UseCCache = 1;
198 asprintf(&buf, "%s/usr/src/sys/Makefile", SystemPath);
199 if (stat(buf, &st) == 0)
200 UseUsrSrc = 1;
201 free(buf);
204 * Default pkg dependency memory target. This is a heuristical
205 * calculation for how much memory we are willing to put towards
206 * pkg install dependencies. The builder count is reduced as needed.
208 * Reduce the target even further when CCache is enabled due to
209 * its added overhead (even though it doesn't use tmpfs).
210 * (NOT CURRENTLY IMPLEMENTED, LEAVE THE SAME)
212 if (PkgDepMemoryTarget == 0) {
213 if (UseCCache)
214 PkgDepMemoryTarget = PhysMem / 3;
215 else
216 PkgDepMemoryTarget = PhysMem / 3;
220 * If this is a dsynth WORKER exec it handles a single slot,
221 * just set MaxWorkers to 1.
223 if (isworker)
224 MaxWorkers = 1;
227 * Final check
229 if (stat(DPortsPath, &st) < 0)
230 dfatal("Directory missing: %s", DPortsPath);
231 if (stat(PackagesPath, &st) < 0)
232 dfatal("Directory missing: %s", PackagesPath);
233 if (stat(OptionsPath, &st) < 0)
234 dfatal("Directory missing: %s", OptionsPath);
235 if (stat(DistFilesPath, &st) < 0)
236 dfatal("Directory missing: %s", DistFilesPath);
237 if (stat(BuildBase, &st) < 0)
238 dfatal("Directory missing: %s", BuildBase);
239 if (stat(LogsPath, &st) < 0)
240 dfatal("Directory missing: %s", LogsPath);
241 if (stat(SystemPath, &st) < 0)
242 dfatal("Directory missing: %s", SystemPath);
243 if (UseCCache && stat(CCachePath, &st) < 0)
244 dfatal("Directory missing: %s", CCachePath);
247 * Now use the SystemPath to retrieve file information from /bin/sh,
248 * and use this to set OperatingSystemName, ArchitectureName,
249 * MachineName, and ReleaseName.
251 * Since this method is used to build for specific releases, require
252 * that it succeed.
254 asprintf(&buf, "%s/bin/sh", SystemPath);
255 getElfInfo(buf);
256 free(buf);
259 * Calculate VersionName from OperatingSystemName and ReleaseName.
261 if (strchr(ReleaseName, '-')) {
262 reln = strchr(ReleaseName, '-') - ReleaseName;
263 asprintf(&buf, "%s %*.*s-SYNTH",
264 OperatingSystemName,
265 reln, reln, ReleaseName);
266 VersionName = buf;
267 asprintf(&buf, "%*.*s-SYNTH", reln, reln, ReleaseName);
268 VersionOnlyName = buf;
269 } else {
270 asprintf(&buf, "%s %s-SYNTH",
271 OperatingSystemName,
272 ReleaseName);
273 asprintf(&buf, "%s-SYNTH", ReleaseName);
274 VersionOnlyName = buf;
278 * Get __DragonFly_version from the system header via SystemPath
281 char *ptr;
282 FILE *fp;
284 asprintf(&buf, "%s/usr/include/sys/param.h", SystemPath);
285 fp = fopen(buf, "r");
286 if (fp == NULL)
287 dpanic_errno("Cannot open %s", buf);
288 while ((ptr = fgetln(fp, &len)) != NULL) {
289 if (len == 0 || ptr[len-1] != '\n')
290 continue;
291 ptr[len-1] = 0;
292 if (strncmp(ptr, "#define __DragonFly_version", 27))
293 continue;
294 ptr += 27;
295 ptr = strtok(ptr, " \t\r\n");
296 VersionFromParamHeader = strdup(ptr);
297 break;
299 fclose(fp);
301 /* Warn the user that World/kernel are out of sync */
302 if (strcmp(VersionFromSysctl, VersionFromParamHeader)) {
303 dlog(DLOG_ALL, "Kernel (%s) out of sync with world (%s) on %s\n",
304 VersionFromSysctl, VersionFromParamHeader, SystemPath);
309 * If RepositoryPath is under PackagesPath, make sure it
310 * is created.
312 if (strncmp(RepositoryPath, PackagesPath, strlen(PackagesPath)) == 0) {
313 if (stat(RepositoryPath, &st) < 0) {
314 if (mkdir(RepositoryPath, 0755) < 0)
315 dfatal_errno("Cannot mkdir '%s'",
316 RepositoryPath);
320 if (stat(RepositoryPath, &st) < 0)
321 dfatal("Directory missing: %s", RepositoryPath);
324 * StatsBase, StatsFilePath, StatsLockPath
326 asprintf(&StatsBase, "%s/stats", LogsPath);
327 asprintf(&StatsFilePath, "%s/monitor.dat", StatsBase);
328 asprintf(&StatsLockPath, "%s/monitor.lk", StatsBase);
331 void
332 DoConfigure(void)
334 dfatal("Not Implemented");
337 static void
338 parseConfigFile(const char *path)
340 char buf[1024];
341 char copy[1024];
342 FILE *fp;
343 char *l1;
344 char *l2;
345 size_t len;
346 int mode = -1;
347 int lineno = 0;
349 fp = fopen(path, "r");
350 if (fp == NULL) {
351 ddprintf(0, "Warning: Config file %s does not exist\n", path);
352 return;
354 if (DebugOpt >= 2)
355 ddprintf(0, "ParseConfig %s\n", path);
357 if (ProfileOverrideOpt) {
358 Profile = strdup(ProfileOverrideOpt);
359 asprintf(&l2, "[%s]", Profile);
360 ProfileLabel = l2;
363 while (fgets(buf, sizeof(buf), fp) != NULL) {
364 ++lineno;
365 len = strlen(buf);
366 if (len == 0 || buf[len-1] != '\n')
367 continue;
368 buf[--len] = 0;
371 * Remove any trailing whitespace, ignore empty lines.
373 while (len > 0 && isspace(buf[len-1]))
374 --len;
375 if (len == 0)
376 continue;
377 buf[len] = 0;
380 * ignore comments
382 if (buf[0] == ';' || buf[0] == '#')
383 continue;
384 if (buf[0] == '[') {
385 if (strcmp(buf, "[Global Configuration]") == 0)
386 mode = 0; /* parse global config */
387 else if (strcmp(buf, ProfileLabel) == 0)
388 mode = 1; /* use profile */
389 else
390 mode = -1; /* ignore profile */
391 continue;
394 bcopy(buf, copy, len + 1);
396 l1 = strtok(copy, "=");
397 if (l1 == NULL) {
398 dfatal("Syntax error in config line %d: %s\n",
399 lineno, buf);
401 l2 = strtok(NULL, " \t\n");
402 if (l2 == NULL) {
403 dfatal("Syntax error in config line %d: %s\n",
404 lineno, buf);
406 l1 = stripwhite(l1);
407 l2 = stripwhite(l2);
409 switch(mode) {
410 case 0:
412 * Global Configuration
414 if (strcmp(l1, "profile_selected") == 0) {
415 if (ProfileOverrideOpt == NULL) {
416 Profile = strdup(l2);
417 asprintf(&l2, "[%s]", l2);
418 ProfileLabel = l2;
420 } else {
421 dfatal("Unknown directive in config "
422 "line %d: %s\n", lineno, buf);
424 break;
425 case 1:
427 * Selected Profile
429 l2 = strdup(l2);
430 if (strcmp(l1, "Operating_system") == 0) {
431 OperatingSystemName = l2;
432 } else if (strcmp(l1, "Directory_packages") == 0) {
433 PackagesPath = l2;
434 } else if (strcmp(l1, "Directory_repository") == 0) {
435 RepositoryPath = l2;
436 } else if (strcmp(l1, "Directory_portsdir") == 0) {
437 DPortsPath = l2;
438 } else if (strcmp(l1, "Directory_options") == 0) {
439 OptionsPath = l2;
440 } else if (strcmp(l1, "Directory_distfiles") == 0) {
441 DistFilesPath = l2;
442 } else if (strcmp(l1, "Directory_buildbase") == 0) {
443 BuildBase = l2;
444 } else if (strcmp(l1, "Directory_logs") == 0) {
445 LogsPath = l2;
446 } else if (strcmp(l1, "Directory_ccache") == 0) {
447 CCachePath = l2;
448 } else if (strcmp(l1, "Directory_system") == 0) {
449 SystemPath = l2;
450 } else if (strcmp(l1, "Package_suffix") == 0) {
451 UsePkgSufx = l2;
452 dassert(strcmp(l2, ".tgz") == 0 ||
453 strcmp(l2, ".tar") == 0 ||
454 strcmp(l2, ".txz") == 0 ||
455 strcmp(l2, ".tzst") == 0 ||
456 strcmp(l2, ".tbz") == 0,
457 "Config: Unknown Package_suffix,"
458 "specify .tgz .tar .txz .tbz or .tzst");
459 } else if (strcmp(l1, "Meta_version") == 0) {
460 MetaVersion = strtol(l2, NULL, 0);
461 } else if (strcmp(l1, "Number_of_builders") == 0) {
462 MaxWorkers = strtol(l2, NULL, 0);
463 if (MaxWorkers == 0)
464 MaxWorkers = NumCores / 2 + 1;
465 else
466 if (MaxWorkers < 0 || MaxWorkers > MAXWORKERS) {
467 dfatal("Config: Number_of_builders "
468 "must range %d..%d",
469 1, MAXWORKERS);
471 free(l2);
472 } else if (strcmp(l1, "Max_jobs_per_builder") == 0) {
473 MaxJobs = strtol(l2, NULL, 0);
474 if (MaxJobs == 0) {
475 MaxJobs = NumCores;
476 } else
477 if (MaxJobs < 0 || MaxJobs > MAXJOBS) {
478 dfatal("Config: Max_jobs_per_builder "
479 "must range %d..%d",
480 1, MAXJOBS);
482 free(l2);
483 } else if (strcmp(l1, "Tmpfs_workdir") == 0) {
484 UseTmpfsWork = truefalse(l2);
485 dassert(UseTmpfsWork == 1,
486 "Config: Tmpfs_workdir must be "
487 "set to true, 'false' not supported");
488 } else if (strcmp(l1, "Tmpfs_localbase") == 0) {
489 UseTmpfsBase = truefalse(l2);
490 dassert(UseTmpfsBase == 1,
491 "Config: Tmpfs_localbase must be "
492 "set to true, 'false' not supported");
493 } else if (strcmp(l1, "Display_with_ncurses") == 0) {
494 if (UseNCurses == -1)
495 UseNCurses = truefalse(l2);
496 } else if (strcmp(l1, "leverage_prebuilt") == 0) {
497 LeveragePrebuilt = truefalse(l2);
498 dassert(LeveragePrebuilt == 0,
499 "Config: leverage_prebuilt not "
500 "supported and must be set to false");
501 } else if (strcmp(l1, "Check_plist") == 0) {
502 if (truefalse(l2)) {
503 WorkerProcFlags |=
504 WORKER_PROC_CHECK_PLIST;
506 } else if (strcmp(l1, "Numa_setsize") == 0) {
507 NumaSetSize = strtol(l2, NULL, 0);
508 free(l2);
509 } else {
510 dfatal("Unknown directive in profile section "
511 "line %d: %s\n", lineno, buf);
513 break;
514 default:
516 * Ignore unselected profile
518 break;
521 fclose(fp);
525 * NOTE: profile has brackets, e.g. "[LiveSystem]".
527 static void
528 parseProfile(const char *cpath, const char *profile)
530 char buf[1024];
531 char copy[1024];
532 char *ppath;
533 FILE *fp;
534 char *l1;
535 char *l2;
536 int len;
537 int plen;
538 int lineno = 0;
540 len = strlen(cpath);
541 while (len && cpath[len-1] != '/')
542 --len;
543 if (len == 0)
544 ++len;
545 plen = strlen(profile);
546 ddassert(plen > 2 && profile[0] == '[' && profile[plen-1] == ']');
548 asprintf(&ppath, "%*.*s%*.*s-make.conf",
549 len, len, cpath, plen - 2, plen - 2, profile + 1);
550 fp = fopen(ppath, "r");
551 if (fp == NULL) {
552 ddprintf(0, "Warning: Profile %s does not exist\n", ppath);
553 return;
555 if (DebugOpt >= 2)
556 ddprintf(0, "ParseProfile %s\n", ppath);
557 free(ppath);
559 while (fgets(buf, sizeof(buf), fp) != NULL) {
560 ++lineno;
561 len = strlen(buf);
562 if (len == 0 || buf[len-1] != '\n')
563 continue;
564 buf[--len] = 0;
567 * Remove any trailing whitespace, ignore empty lines.
569 while (len > 0 && isspace(buf[len-1]))
570 --len;
571 buf[len] = 0;
572 stripwhite(buf);
575 * Allow empty lines, ignore comments.
577 len = strlen(buf);
578 if (len == 0)
579 continue;
580 if (buf[0] == ';' || buf[0] == '#')
581 continue;
584 * Require env variable name
586 bcopy(buf, copy, len + 1);
587 l1 = strtok(copy, "=");
588 if (l1 == NULL) {
589 dfatal("Syntax error in profile line %d: %s\n",
590 lineno, buf);
594 * Allow empty assignment
596 l2 = strtok(NULL, " \t\n");
597 if (l2 == NULL)
598 l2 = l1 + strlen(l1);
600 l1 = stripwhite(l1);
601 l2 = stripwhite(l2);
604 * Add to builder environment
606 addbuildenv(l1, l2, BENV_MAKECONF);
607 if (DebugOpt >= 2)
608 ddprintf(4, "%s=%s\n", l1, l2);
610 fclose(fp);
611 if (DebugOpt >= 2)
612 ddprintf(0, "ParseProfile finished\n");
615 static char *
616 stripwhite(char *str)
618 size_t len;
620 len = strlen(str);
621 while (len > 0 && isspace(str[len-1]))
622 --len;
623 str[len] =0;
625 while (*str && isspace(*str))
626 ++str;
627 return str;
630 static int
631 truefalse(const char *str)
633 if (strcmp(str, "0") == 0)
634 return 0;
635 if (strcmp(str, "1") == 0)
636 return 1;
637 if (strcasecmp(str, "false") == 0)
638 return 0;
639 if (strcasecmp(str, "true") == 0)
640 return 1;
641 dfatal("syntax error for boolean '%s': "
642 "must be '0', '1', 'false', or 'true'", str);
643 return 0;
646 static char *
647 dokernsysctl(int m1, int m2)
649 int mib[] = { m1, m2 };
650 char buf[1024];
651 size_t len;
653 len = sizeof(buf) - 1;
654 if (sysctl(mib, 2, buf, &len, NULL, 0) < 0)
655 dfatal_errno("sysctl for system/architecture");
656 buf[len] = 0;
657 return(strdup(buf));
660 struct NoteTag {
661 Elf_Note note;
662 char osname1[12];
663 int version; /* e.g. 500702 -> 5.7 */
664 int x1;
665 int x2;
666 int x3;
667 char osname2[12];
668 int zero;
671 static void
672 getElfInfo(const char *path)
674 struct NoteTag note;
675 char *cmd;
676 char *base;
677 FILE *fp;
678 size_t size;
679 size_t n;
680 int r;
681 uint32_t addr;
682 uint32_t v[4];
684 asprintf(&cmd, "readelf -x .note.tag %s", path);
685 fp = popen(cmd, "r");
686 dassert_errno(fp, "Cannot run: %s", cmd);
687 n = 0;
689 while (n != sizeof(note) &&
690 (base = fgetln(fp, &size)) != NULL && size) {
691 base[--size] = 0;
692 if (strncmp(base, " 0x", 3) != 0)
693 continue;
694 r = sscanf(base, "%x %x %x %x %x",
695 &addr, &v[0], &v[1], &v[2], &v[3]);
696 v[0] = ntohl(v[0]);
697 v[1] = ntohl(v[1]);
698 v[2] = ntohl(v[2]);
699 v[3] = ntohl(v[3]);
700 if (r < 2)
701 continue;
702 r = (r - 1) * sizeof(v[0]);
703 if (n + r > sizeof(note))
704 r = sizeof(note) - n;
705 bcopy((char *)v, (char *)&note + n, r);
706 n += r;
708 pclose(fp);
710 if (n != sizeof(note))
711 dfatal("Unable to parse output from: %s", cmd);
712 if (strncmp(OperatingSystemName, note.osname1, sizeof(note.osname1))) {
713 dfatal("%s ELF, mismatch OS name %.*s vs %s",
714 path, (int)sizeof(note.osname1),
715 note.osname1, OperatingSystemName);
717 free(cmd);
718 if (note.version) {
719 asprintf(&cmd, "%d.%d",
720 note.version / 100000,
721 (note.version % 100000) / 100);
722 } else if (note.zero) {
723 asprintf(&cmd, "%d.%d",
724 note.zero / 100000,
725 (note.zero % 100000) / 100);
726 } else {
727 dfatal("%s ELF, cannot extract version info", path);
729 ReleaseName = cmd;
732 static char *
733 checkhook(const char *scriptname)
735 struct stat st;
736 char *path;
738 asprintf(&path, "%s/%s", ConfigBase, scriptname);
739 if (stat(path, &st) < 0 || (st.st_mode & 0111) == 0) {
740 free(path);
741 return NULL;
743 UsingHooks = 1;
745 return path;