1 /*
2 * Copyright (c) 2015 PLUMgrid, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <cstring>
17 #include <memory>
18 #include <string>
19 #include <vector>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <ftw.h>
23
24 #define PROC_KHEADERS_PATH "/sys/kernel/kheaders.tar.xz"
25
26 namespace ebpf {
27
28 struct FileDeleter {
operatorFileDeleter29 void operator() (FILE *fp) {
30 fclose(fp);
31 }
32 };
33 typedef std::unique_ptr<FILE, FileDeleter> FILEPtr;
34
35 // Helper with pushd/popd semantics
36 class DirStack {
37 public:
DirStack(const std::string & dst)38 explicit DirStack(const std::string &dst) : ok_(false) {
39 if (getcwd(cwd_, sizeof(cwd_)) == NULL) {
40 ::perror("getcwd");
41 return;
42 }
43 if (::chdir(dst.c_str())) {
44 fprintf(stderr, "chdir(%s): %s\n", dst.c_str(), strerror(errno));
45 return;
46 }
47 ok_ = true;
48 }
~DirStack()49 ~DirStack() {
50 if (!ok_) return;
51 if (::chdir(cwd_)) {
52 fprintf(stderr, "chdir(%s): %s\n", cwd_, strerror(errno));
53 }
54 }
ok()55 bool ok() const { return ok_; }
cwd()56 const char * cwd() const { return cwd_; }
57 private:
58 bool ok_;
59 char cwd_[256];
60 };
61
ftw_cb(const char * path,const struct stat *,int,struct FTW *)62 static int ftw_cb(const char *path, const struct stat *, int, struct FTW *) {
63 return ::remove(path);
64 }
65
66 // Scoped class to manage the creation/deletion of tmpdirs
67 class TmpDir {
68 public:
69 explicit TmpDir(const std::string &prefix = "/tmp/bcc-")
ok_(false)70 : ok_(false), prefix_(prefix) {
71 prefix_ += "XXXXXX";
72 if (::mkdtemp((char *)prefix_.data()) == NULL)
73 ::perror("mkdtemp");
74 else
75 ok_ = true;
76 }
~TmpDir()77 ~TmpDir() {
78 if (::nftw(prefix_.c_str(), ftw_cb, 20, FTW_DEPTH) < 0)
79 ::perror("ftw");
80 else
81 ::remove(prefix_.c_str());
82 }
ok()83 bool ok() const { return ok_; }
str()84 const std::string & str() const { return prefix_; }
85 private:
86 bool ok_;
87 std::string prefix_;
88 };
89
90 // Compute the kbuild flags for the currently running kernel
91 // Do this by:
92 // 1. Create temp Makefile with stub dummy.c
93 // 2. Run module build on that makefile, saving the computed flags to a file
94 // 3. Cache the file for fast flag lookup in subsequent runs
95 // Note: Depending on environment, different cache locations may be desired. In
96 // case we eventually support non-root user programs, cache in $HOME.
97 class KBuildHelper {
98 public:
99 explicit KBuildHelper(const std::string &kdir, bool has_source_dir);
100 int get_flags(const char *uname_machine, std::vector<std::string> *cflags);
101 private:
102 std::string kdir_;
103 bool has_source_dir_;
104 };
105
106 int get_proc_kheaders(std::string &dir);
107 } // namespace ebpf
108