1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
#!/usr/bin/env lua5.3
-- needs xsel, clipnotify
-- luarocks-5.3 install --local luaposix
-- luarocks-5.3 install --local argparse
-- cat .clip_history | dmenu -l 10 | xsel -ib
local string = require("string")
local signal = require("posix.signal")
local argparse = require("argparse")
local sys_stat = require("posix.sys.stat")
local unistd_getuid = require("posix.unistd.getuid")
local unistd_getgid = require("posix.unistd.getgid")
local unistd_getpid = require("posix.unistd.getpid")
local posix_syslog = require("posix.syslog")
local function default_luarocks_modules()
local luarocks_handle = io.popen("luarocks-5.3 path --bin")
local path_b = false
local cpath_b = false
for line in luarocks_handle:lines() do
local path = string.match(line, "LUA_PATH%s*=%s*('.+')")
local cpath = string.match(line, "LUA_CPATH%s*=%s*('.+')")
if path ~= nil then
package.path = package.path .. ";" .. string.sub(path, 2, -2)
end
if cpath ~= nil then
package.cpath = package.cpath .. ";" .. string.sub(cpath, 2, -2)
end
end
if path_b then os.exit(1) end
if cpath_b then os.exit(1) end
end
default_luarocks_modules()
local function sleep(n) os.execute("sleep " .. tonumber(n)) end
local function trim(s) return s:gsub("^%s+", ""):gsub("%s+$", "") end
local parser = argparse()
parser:option("-s --hist_size", "history file size", 200)
parser:option("-f --hist_file", "history file location",
"/home/devi/.clip_history")
local function log_to_syslog(log_str, log_priority)
posix_syslog.openlog("clipd",
posix_syslog.LOG_NDELAY | posix_syslog.LOG_PID,
posix_syslog.LOG_LOCAL0)
posix_syslog.syslog(log_priority, log_str)
posix_syslog.closelog()
end
local function check_clip_hist_perms(clip_hist)
local uid = unistd_getuid()
local gid = unistd_getgid()
for k, v in pairs(sys_stat.stat(clip_hist)) do
if k == "st_uid" then
if v ~= uid then
log_to_syslog(
"clipboard history file owned by uid other than the clipd uid",
posix_syslog.LOG_CRIT)
os.exit(1)
end
end
if k == "st_gid" then
if v ~= gid then
log_to_syslog(
"clipboard history file owned by gid other than the clipd gid",
posix_syslog.LOG_CRIT)
os.exit(1)
end
end
if k == "st_mode" then
if v & sys_stat.S_IRWXU ~= 0 then
log_to_syslog(
"file permissions are too open. they need to be 0600.",
posix_syslog.LOG_CRIT)
os.exit(1)
end
end
end
end
local function check_pid_file()
local f = sys_stat("/var/run/clipd.pid")
if f ~= nil then
log_to_syslog("clipd is already running", posix_syslog.LOG_CRIT)
os.exit(1)
end
end
local function write_pid_file()
local f = io.open("/var/run/clipd.pid")
f.write(unistd_getpid())
end
local function remove_pid_file() end
local function loop(clip_hist, clip_hist_size)
local clips_table = {}
local hist_current_count = 0
local hist_file = io.open(clip_hist, "r")
if hist_file ~= nil then
for line in hist_file:lines() do
if line ~= "\n" and line ~= "" and line ~= "\r\n" and line ~= " " then
clips_table[line] = true
hist_current_count = hist_current_count + 1
end
end
end
hist_file:close()
while true do
local wait_for_event = io.popen("clipnotify")
local handle = io.popen("xsel -ob")
local last_clip_entry = handle:read("*a")
if last_clip_entry[-1] == "\n" then
clips_table[string.sub(last_clip_entry, 0,
string.len(last_clip_entry))] = true
else
clips_table[last_clip_entry] = true;
end
hist_current_count = hist_current_count + 1
if hist_current_count >= tonumber(clip_hist_size) then
table.remove(clips_table, 1)
hist_current_count = hist_current_count - 1
end
hist_file = io.open(clip_hist, "w")
for k, _ in pairs(clips_table) do
if clips_table[k] then hist_file:write(trim(k) .. "\n") end
end
hist_file:close()
wait_for_event:close()
handle:close()
sleep(.2)
end
end
local function main()
signal.signal(signal.SIGINT, function(signum) os.exit(128 + signum) end)
local args = parser:parse()
check_clip_hist_perms(args["hist_file"])
check_pid_file()
write_pid_file()
local status, err = pcall(loop(args["hist_file"], args["hist_size"]))
if ~status then log_to_syslog(err, posix_syslog.LOG_CRIT) end
remove_pid_file()
end
main()
|