update package

This commit is contained in:
CN_SZTL 2019-07-02 18:06:49 +08:00
parent ddd789b04d
commit e20868d32d
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
983 changed files with 420002 additions and 1458 deletions

View File

@ -34,10 +34,8 @@ make -j1 V=s
# Origin source
### Based on: [coolsnowwolf/lede](https://github.com/coolsnowwolf/lede).<br/>
luci-app-koolproxy source: [openwrt-develop/luci-app-koolproxy](https://github.com/openwrt-develop/luci-app-koolproxy).<br/>
luci-app-udp2raw source: [sensec/luci-app-udp2raw](https://github.com/sensec/luci-app-udp2raw).<br/>
luci-app-haproxy source: [AlexZhuo/luci-app-haproxy-tcp](https://github.com/AlexZhuo/luci-app-haproxy-tcp).<br/>
luci-app-udpspeederv2 source: [haodong/luci-app-speederv2](https://github.com/haodong/luci-app-speederv2).<br/>
Packages jsda: [jsda/packages2](https://github.com/jsda/packages2).
luci-theme-netgearv2 source: [tracemouse/luci-theme-netgear](https://github.com/tracemouse/luci-theme-netgear).
# License

View File

@ -1,29 +0,0 @@
config arguments
option enabled '0'
config main_server
option server_weight '10'
option server_ip '1.2.3.4'
option server_port '443'
option server_name 'JP1'
option validate '1'
config backup_server
option server_name 'JP2'
option server_ip '2.2.2.2'
option server_port '8038'
option validate '1'
config backup_server
option server_name 'JP3'
option server_ip '3.3.3.3'
option server_port '443'
option validate '1'
config backup_server
option server_name 'JP4'
option server_ip '4.4.4.4'
option server_port '443'
option validate '1'

View File

@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -1,2 +0,0 @@
tools/po2lmo/src/po2lmo
tools/po2lmo/src/*.o

View File

@ -1,30 +0,0 @@
dist: trusty
sudo: true
language: c
env:
PACKAGE_NAME=`grep "PKG_NAME:=" Makefile | sed 's/.*:=//'`
PACKAGE_VERSION=`grep "PKG_VERSION:=" Makefile | sed 's/.*:=//'`
PACKAGE_RELEASE=`grep "PKG_RELEASE:=" Makefile | sed 's/.*:=//'`
PACKAGE_ARCH=`grep "PKGARCH:=" Makefile | sed 's/.*:=//'`
before_script:
- wget https://downloads.openwrt.org/releases/18.06.1/targets/bcm53xx/generic/openwrt-sdk-18.06.1-bcm53xx_gcc-7.3.0_musl_eabi.Linux-x86_64.tar.xz
- tar xf openwrt-sdk-18.06.1-bcm53xx_gcc-7.3.0_musl_eabi.Linux-x86_64.tar.xz
- mkdir -p openwrt-sdk-18.06.1-bcm53xx_gcc-7.3.0_musl_eabi.Linux-x86_64/package/${PACKAGE_NAME}
- mv files tools Makefile openwrt-sdk-18.06.1-bcm53xx_gcc-7.3.0_musl_eabi.Linux-x86_64/package/${PACKAGE_NAME}/
- cd openwrt-sdk-18.06.1-bcm53xx_gcc-7.3.0_musl_eabi.Linux-x86_64
- pushd package/${PACKAGE_NAME}/tools/po2lmo
- make
- sudo make install
- popd
- make defconfig
script:
- make package/${PACKAGE_NAME}/compile V=s
deploy:
provider: releases
api_key:
secure: kfupsEOntxxx5xjIrXIctCuPwPPh9eMLz1EYqeQl39mSBh6fCg1PpQoOemv/IeDMZh8u5XYRCMgelJ0F/IbF6rktLbrjbiEwV4QJzD1ReQRT2y1zFrNYrhy/kc9ptrSTMOk/Y15mf36i585nAtc3I+OCpnpdCaVxq4V6lIVf2p4mIEhYaz4f/Dv6rRrEDfkfgcinUOCsxIl3/s0OMZlvNE7GLoRCzbWO4MRyIRzqmIcAbvSLFXJ6PybJy1lniJZ69FgDJBxgq2H6iQTC/bdHPOd4h50VqR31naUZL6UBcprqxJjt4fEBvjXviPtTeJlsx8ajvgLGqS3AXS3Lcs8oc/h2Yj04/7fOqwxUYdAQVE0EXPAMVz1tGS2apDGlaalNWowF9rhN02+woEVewZLKCzSdWhU/Cv+hs4ClCbooR+MCT8Fm9lQS5LnoRd/bomXbU5bPBbznQs8HNUIzL9snUYC0n/ZavIi46ejK6Dkw28QDv2XeeLSgT6kjlQdwPrswZ8tgkOR1ZGk7iW3WAVgH2+dxfvCelm0Fsax/o3447huFAEXKATQ9t8UTZOXmvCHrajRYQuHJL4+bqykQGsPbhIoPL2SUOvZXMCnRkb8BiD7pBKtS4cYtyxh+slTEQOmHMgR2lotszHUVJAqmrTbB06E2ZrDpwp3LPRY/3h3JsTI=
file: bin/packages/arm_cortex-a9/base/${PACKAGE_NAME}_${PACKAGE_VERSION}-${PACKAGE_RELEASE}_${PACKAGE_ARCH}.ipk
skip_cleanup: true
on:
repo: haodong/${PACKAGE_NAME}
tags: true

View File

@ -0,0 +1,65 @@
#
# Copyright (C) 2015-2016 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v3.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=AdGuardHome
PKG_VERSION:=v0.96-hotfix
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=net
CATEGORY:=Network
TITLE:=AdGuardHome
DEPENDS:=
URL:=https://github.com/AdguardTeam/AdGuardHome/releases
endef
define Package/$(PKG_NAME)/description
AdGuardHome
endef
ifeq ($(ARCH),x86_64)
PKG_ARCH_AdGuardHome:=linux_amd64
endif
ifeq ($(ARCH),i386)
PKG_ARCH_AdGuardHome:=linux_386
endif
ifeq ($(ARCH),mipsel)
PKG_ARCH_AdGuardHome:=linux_mipsle
endif
ifeq ($(ARCH),mips)
PKG_ARCH_AdGuardHome:=linux_mips
endif
ifeq ($(ARCH),arm)
PKG_ARCH_AdGuardHome:=linux_arm
endif
ifeq ($(ARCH),aarch64)
PKG_ARCH_AdGuardHome:=linux_amd64
endif
define Build/Prepare
[ ! -f $(PKG_BUILD_DIR)/AdGuardHome_$(PKG_ARCH_AdGuardHome).tar.gz ] && wget https://github.com/AdguardTeam/AdGuardHome/releases/download/$(PKG_VERSION)/AdGuardHome_$(PKG_ARCH_AdGuardHome).tar.gz -O $(PKG_BUILD_DIR)/AdGuardHome_$(PKG_ARCH_AdGuardHome).tar.gz
tar -xzvf $(PKG_BUILD_DIR)/AdGuardHome_$(PKG_ARCH_AdGuardHome).tar.gz -C $(PKG_BUILD_DIR)
endef
define Build/Configure
endef
define Build/Compile
chmod +x $(PKG_BUILD_DIR)/AdGuardHome/AdGuardHome && upx --lzma $(PKG_BUILD_DIR)/AdGuardHome/AdGuardHome
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/AdGuardHome/AdGuardHome $(1)/usr/bin/AdGuardHome
$(INSTALL_DIR) $(1)/etc/AdGuardHome
$(CP) -r ./files/etc/AdGuardHome $(1)/etc
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -0,0 +1,102 @@
bind_host: 0.0.0.0
bind_port: 3000
auth_name: AdGuardHome
auth_pass: AdGuardHome
language: zh-cn
dns:
bind_host: 0.0.0.0
port: 5333
protection_enabled: true
filtering_enabled: true
blocked_response_ttl: 10
querylog_enabled: true
ratelimit: 20
ratelimit_whitelist: []
refuse_any: true
bootstrap_dns: 8.8.4.4:53
all_servers: true
parental_sensitivity: 0
parental_enabled: false
safesearch_enabled: false
safebrowsing_enabled: false
upstream_dns:
- 127.0.0.1:5383
- tls://1dot1dot1dot1.cloudflare-dns.com
- https://cloudflare-dns.com/dns-query
- https://1.0.0.1/dns-query
- https://dns.quad9.net/dns-query
- tcp://8.8.8.8
- tcp://8.8.4.4
tls:
enabled: false
server_name: ""
force_https: false
port_https: 443
port_dns_over_tls: 853
certificate_chain: ""
private_key: ""
filters:
- enabled: true
url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
name: AdGuard Simplified Domain Names filter
id: 1
- enabled: true
url: https://adaway.org/hosts.txt
name: AdAway
id: 2
- enabled: true
url: https://hosts-file.net/ad_servers.txt
name: hpHosts - Ad and Tracking servers only
id: 3
- enabled: true
url: http://www.malwaredomainlist.com/hostslist/hosts.txt
name: MalwareDomainList.com Hosts List
id: 4
- enabled: true
url: https://raw.githubusercontent.com/523860169/list/master/ad.txt
name: Diablo AdFilters
id: 1553073381
- enabled: true
url: http://tools.yiclear.com/ChinaList2.0.txt
name: ChinaListV2.0[20190224001]
id: 1553073382
- enabled: true
url: https://easylist-downloads.adblockplus.org/antiadblockfilters.txt
name: Adblock Warning Removal List
id: 1553073383
- enabled: true
url: https://fanboy.co.nz/fanboy-problematic-sites.txt
name: Fanboy's problematic-sites
id: 1553073384
- enabled: true
url: https://raw.githubusercontent.com/xinggsf/Adblock-Plus-Rule/master/ABP-FX.txt
name: "5"
id: 1553073385
- enabled: true
url: https://raw.githubusercontent.com/adbyby/xwhyc-rules/master/lazy.txt
name: "6"
id: 1553073386
- enabled: true
url: https://hosts.nfz.moe/127.0.0.1/full/hosts
name: "7"
id: 1553073387
- enabled: true
url: https://raw.githubusercontent.com/vokins/yhosts/master/hosts
name: "8"
id: 1553073388
- enabled: true
url: http://sub.adtchrome.com/adt-chinalist-easylist.txt
name: ChinaList+EasyList(修正)
id: 1553073405
user_rules: []
dhcp:
enabled: false
interface_name: ""
gateway_ip: ""
subnet_mask: ""
range_start: ""
range_end: ""
lease_duration: 0
log_file: ""
verbose: false
schema_version: 2

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,455 @@
[Adblock Plus 2.0]
! Checksum: YPOqcEwLkBYNPuxPC9uS9A
! Version: 201903200901
! Title: Adblock Warning Removal List
! Last modified: 20 Mar 2019 09:01 UTC
! Expires: 1 days (update frequency)
! Homepage: https://easylist.to/
!
! Please report any unblocked obtrusive anti adblock messages or problems
! in the forums (https://forums.lanik.us/) or via e-mail (easylist.subscription+anti@gmail.com).
! Please check our guidelines before reporting: https://easylist.to/2013/05/10/anti-adblock-guide-for-site-admins
!
! *** antiadblockfilters:antiadblockfilters/antiadblock_arabic.txt ***
!
/deadblocker/*
/mod_ablockdetector/*
!
###adblock_screen
###adblock_message
##.adblockInfo
##.adblock_floating_message
##.adblock_msg
##.deadblocker-header-bar
!
myegy.cc##.disclaimer
4algeria.com###exposeMask
4algeria.com##.xenOverlay
!
! *** antiadblockfilters:antiadblockfilters/antiadblock_chinese.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_czech.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_dutch.txt ***
bouweenpc.nl###header-banner
rtlxl.nl##.adblock
spele.nl##.adblocker
koolhydraatarmerecepten.info##body > [style^="z-index: 1000000; "]
! *** antiadblockfilters:antiadblockfilters/antiadblock_english.txt ***
flightradar24.com###bottomRightPanel
videofun.me###flowplayer > div[class][style]:first-child
abc-fonts.me###galepro-core-adb-enabled
yocast.tv###ra9e
flightradar24.com###responsiveBottomPanel
myanimelist.net##._unit
##.pane-emediate
##.ad-blocker-warning
mediafire.com###abnotify
biggestplayer.me##.adblock + *
hearthhead.com,wowhead.com##.block-bg
wowhead.com##.block-bgimg
euroiphone.eu##.div-download-h
euroiphone.eu##.div-download-v
findretros.com##.fuck-adblock
technologypep.com##.main-container-wrap > div[class$="-bg"]
technologypep.com##.main-container-wrap > div[id][class][style*="opacity"]
biggestplayer.me##.masr
videobug.net,videofun.me,vidzur.com##.randid
toolslib.net##.row > .col-md-7 > .panel-default
hearthhead.com,thottbot.com,wowhead.com##.sidebar-bg
biggestplayer.me##.soret
spanishdict.com##.whitelist
pkmods.com##body > div[style*="z-index"][style*="background"]
/adblock-alerter/js/adblock_alerter.js
/adblock-img.
play44.net,videobug.net,videofun.me,vidzur.com,yucache.net##[style^="position: absolute; width: 100%;"]
strikeout.co,vipbox.sx,vipleague.co,vipleague.is##div[style="display: block;"]
nexusmods.com##div[style="float: left; width: 728px; height: 90px; background: #313131;"]
playonlinux.com##div[style="text-align:center; border-radius:7px; width:160px; border:1px solid #666666; margin-left:5px;padding-right:5px;color:#FFF; background-color:#666;font-family:Maven Pro,century gothic, arial, helvetica, sans serif;padding-top:94px; height:600px; padding-left:5px; font-size:18px; "]
byzoo.org,videobug.net##div[style^="position: absolute; width: 300px;"]
homerun.re,strikeout.co,vipbox.sx,vipleague.ch,vipleague.co,vipleague.is,vipleague.me##span[id][style] > div[id]:first-child:last-child
||amazonaws.com^*/abb-msg.js$domain=hardocp.com
||corrosif.science^$domain=filerev.cc|pencurimovie.pw
||rockradio.com^*/blockadblock-$script,domain=rockradio.com
||static.game-state.com/images/main/alert/replacement/
||www.google.*/ajax/pi/phd?abd=0$xmlhttprequest
! NSFW
redtube.com###as_131
redtube.com###slidePanelContainerAB
redtube.com##.qb
shadbase.com##img[alt="adblock"]
! *** antiadblockfilters:antiadblockfilters/antiadblock_finnish.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_french.txt ***
!
-adblock-notice-
-adblock-notice/*
/ad-blocking-advisor/*
/adbl_dtct.
/adblock-detect/*
/adblock-notice-
/adblock-notify-by-bweb/*
/adblock-warning-teaser/*
/adblock_gate/images/animated.gif?
/adblock_notify.js
/adblocker_message_
/AdblockMessage.
/antiadblockmsg.
/blockadblock.js
/blockadblock.min.js
/wp-content/plugins/ad-block-defender/*
/wp-content/plugins/deadblocker/*
/wp-content/uploads/an-temp/*$script,stylesheet
/SvgAdblockDetected/*
!
||bdgest.com/js/site.js?
||cmath.fr/images/fond2.gif
||cmath.fr/images/fondsticky.gif
||ed-protect.org/cdn-cgi/apps/head/
||gameblog.fr/images/ablock/
||nikopik.com/wp-content/themes/*/js/nikopik.js
||nordpresse.be/wp-content/uploads/$script
||nrj.fr/nrj?Page=/rg.fake&
||skyrock.net/img/*/adblock/
!
@@/advertisement.js$script,~third-party,domain=fun-animes.fr
@@/noadblock-nice-message/assets/js/ads.js?$script,~third-party
!
@@||abcbourse.com/scripts/ads.js$script,~third-party
@@||ausujet.com/skins/common/ads.js
@@||cyberdean.fr/js/advertisement.js
@@||dbz-fantasy.com/ads.css
@@||dev-dyod.fr/styles/ads.css
@@||forums.macg.co/js/audentio/funbox/advertisement.js
@@||france.carbu.com/templates/media/js/ads.js$script
@@||frandroid.com/ads.js
@@||free-reseau.fr/css/publicite.css|$stylesheet
@@||fusacq.com/javascript/advertising.js|$script
@@||grattable.com/blogads.css
@@||hdnumerique.com/tpl/jscript/advert.js
@@||impactmangas.fr/ads.js|$script,~third-party
@@||item-voyage.fr/ads.css
@@||jeux-geographiques.com/js/adblock_detector.js
@@||jeuxvideo-live.com/js/ads.js
@@||ktu.sv2.biz/sv3/advertisement.js
@@||larvf.com/js/ads.js
@@||macg.co/js/audentio/funbox/advertisement.js
@@||manga-news.com/js/advert.js$script
@@||numerama.com/ads.js
@@||pagerank.fr/js*/advert.js?$script
@@||penducado.com/styles/ads.css
@@||presse-algerie.net/js/ads.js$script
@@||primfx.com/js/ads.js|$script,~third-party
@@||ps3-infos.fr/adsense/openads/ads/ads.js
@@||ptitchef.com/js/ads.js
@@||static.koreus.com/js/advert.js
@@||cdn4.tennistemple.com/js/advert.js|$script,~third-party
@@||trackr.fr/sites/all/themes/contrib/touch/js/miroirs/adwordstracking.js
@@||universfreebox.com/js/advertisement.js
@@||uplea.com/js/advertisement.js
@@||peimg.fr/js/ads.js$script,domain=pubeco.fr
@@||wamiz.com/css/ads.css
@@||zagaz.com/img/blogads.css
!
###AdBlockDialog
###abp-killer
###adBlockAlert
###adBlockAlertWrap
###adBlockDetect
###adBlockerModal
###ad_blocker
###adb-actived
###adb-enabled
###adb-enabled3
###adb-warning
###adblock-alert
###adblock-box
###adblock-modal
###adblock-msg
###adblock-notice
###adblock-overlay
###adblockDetect
###adblock_detected
###adblocker_announce
###adblocker_message
###adblocker_modal_overlay
###adblockinfo
###ads-blocked
###advertisementjsalert
###anti_adblock
###detection-block
###detection-block-overlay
###detectadblock
###fnAdblockingOverlay
###message_adblock
##.AdblockMessage
##.AdblockMessage_msg
##.ad-alert-wrapper
##.ad-block-detected
##.ad-block-enabled
##.ad-block-message
##.ad-blocked
##.ad-blocker-warning
##.ad-blocking-advisor-wrapper
##.ad_blocker
##.adBlockDetectedSign
##.adBlockNotification
##.adBlockNotificationOverlay
##.adBlockWarning
##.adb-enabled
##.adbd-background
##.adbd-message
##.adbd-wrapper
##.adblock-modal
##.adblock-modal-content
##.adblock-notification-wrapper
##.adblock-warning-teaser
##.adblockOverlay
##.adblock_detector
##.adblock_enabled
##.adblock_floating_message
##.adblocker-message
##.adblocker-wrap
##.counterAdblocks
##.deadblocker-header-bar
##.deadblocker-header-bar-inner
##.dispositifAdblock
##.dispositifAdblockContent
##.dispositifAdblockMessageBox
##.fuckYouAdBlock
##.fuckYouAdBlock2
##.js-checkad-warning
##.kill-adblock-container
##.noadblock
##.svg-adblock-full
##.svg-adblock-full--box
##.top-bar-adblock
##[class][data-sitename][data-header-version] > div[id^="detection-block"]
##adblock-detect
!
wamiz.com###adblocker
jaitoutcompris.com###antiBlock
developpez.com,developpez.net###encart_droite div[style="display: inline-block; width: 300px; height: 250px"]
iphonesoft.fr,iphonetweak.fr###msgNoPub
retinaboys.com###screen_block
lagrosseradio.com###warn
journaldugeek.com##.banner__content
ceesty.com,clkme.me,clkmein.com,cllkme.com,corneey.com,destyy.com,festyy.com,gestyy.com,jigbig.tk,newsfortrump.ga,sh.st,shorte.st,skiip.me,skipp.io,viid.me,wiid.me##.information-container
etr.fr##.no_block
radiox.com##.notifyjs-corner
papergeek.fr##[id^="padb_widget_"]
forumdz.com##body .breadcrumb + center > [color="red"] > b
forum.pcastuces.com##div > [src] + [id] + [class][style^="display: block;"]
closermag.fr##div[id^="detection-block"]
bd-sanctuary.com,cine-sanctuary.com,comics-sanctuary.com,manga-sanctuary.com##div[style^="background:#444;"]
developpez.com,developpez.net##div[id^="gabarit_pub"]
pausecafein.fr###adb-pop
!
#@##adblocktest
!
dbz-fantasy.com#@##adTeaser
dz-android.com,freeiphone.fr,hommedumatch.fr,jetetroll.com,testious.com#@##adsense
debrideurstream.fr#@##pubdirecte
ot-boutique.fr#@##publicite
iwin.com#@##sponsorText
fairytailmx.com#@##sponsored-ad
forum.virtualdjing.com#@#.adFrame
dealerdunet.fr#@#.text_ads
comptoir-info.com#@#.textad
!
! *** antiadblockfilters:antiadblockfilters/antiadblock_german.txt ***
##.diysdk_webServices_banners1und1MainContent
usgang.ch###rectangle-wrapper
||jappy.tv/i/wrbng/abb.png
! *** antiadblockfilters:antiadblockfilters/antiadblock_hebrew.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_indonesian.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_italian.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_latvian.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_romanian.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_russian.txt ***
delfi.ee###ab--notification-ribbon
minimultik.ru###abDetected
patrioty.org.ua###ad_pu_modal
mambaru###adblock-in-browser
dressupmix.ru,teensgames.ru###adblock_popup
vesti-ukr.com###adblockpopup
happy-hack.ru###admitad-cookie-check-popup
wotactions.com###ads_warning
firebit.info###adv-300 + div[class][align="center"][style^="background-color"]
novostroy-m.ru###advert_result
cxem.net###antiAdBlock
elhow.ru###b-info-wrapper
ma.by###bodysubcont > div[style^="padding"]:not([id]):not([class])
pln-pskov.ru###check_ad_block
helpsetup.ru###d930
delfi.ee###delfiTopBar
sd-company.su###dom_adblock
myshared.ru###download_form > .uk-margin-top[style]
forum.bestflowers.ru###exposeMask
gk-stalker.xyz###gkadblock
pastenow.ru###google-block
info-mage.ru###helpme[style="display: block;"]
poncy.ru###hide-adblock
kissvk.com###madBlockModal,.modal-backdrop
aratta-ukraine.com,gisclub.tv,teremok.org.ua,webos-forums.ru###mdl_adb
beadeath.dclans.ru###mdl_ctnr
ostroh.info###modal.modal-bg
photolessons.org###modal-adbmon-div
7days2die.info###nafikblock
all-episodes.net###odin
mover.uz###oframeplayer > [class][style^="display: block"]
center-yf.ru,lektsii.org,studopedia.com.ua,studopedia.org,studopedia.ru,studopedia.su###opaco,#popup
md4u.ru###pagecontent > div[style*="background-color"]
forummikrotik.ru###phpbb-ads-ab
kompravda.eu,kp.ru###popapIsBlockedAd
math-prosto.ru###requestShutOfBlocker
pb.wtf,piratbit.org,piratbit.ru###result > .request
mnogoto4ka.ru###sb-site > div[class][style*="z-index"][style*="999999"]
professorweb.ru###submain > div[class^="a"][style]
kaermorhen.ru###top-line-container
numberempire.com###toplink > h3[style="color: red"]
ganoderma-mushrooms.com,korrektor.name,varicream.org###turn_advert.adblock
czx.to###vdl_ctnr
chipinfo.pro###warning
sport-express.ru##.a-notice
scrin.org##.a-overlay
vsaduidoma.com##.ABD_display_wrapper
eurabota.com##.abtop
sprashivalka.com##.ad
topcraft.ru##.ad-info
cc-fan.tv,cn-fan.tv,fox-fan.tv,goodfon.ru,satsis.info,swordmaster.org##.adb
vsadu.ru##.adb-block
andevice.ru,dietdo.ru##.adb-def
tuchkatv.ru##.adb_m
besplatka.ua##.adBl
brazzers-hdx.club##.adblck
forum.qrz.ru,hentaiz.org,life.ru,mastergrad.com##.adblock
exler.ru##.adblock-pls
zakon.kz##.adblock_alert
ogorod.ru##.adblock_popup_warning
hentaiz.org##.adblocker
kubik3.ru##.adbs
print-post.com##.addbl
ideya-biznesa.ru##.admania_adblock_detector
24video.xxx##.adt
rusrek.com##.alert
benfilm.net##.alert-block
2ip.me,2ip.ua##.alert-mess > .row
stroi-help.ru##.alert_warn
ria.ru##.antiblock
rufilmtv.org##.attention
mel.fm##.b-ad-space__placeholder
ixbt.com##.b-blockadblock
d3.ru##.b-promo__placeholder
cs-amba.ru##.banka
it-actual.ru##.blok > div[class^="bl-"]
electric-house.ru##.blok_forum > div[style]
audio-hi-fi.ru,electro-sila.ru##.blok_new > div[style]
rutor1.ru##.box_in > .text > p > font
tsn.ua##.c-aside-embed
kanobu.ru##.c-moneyPlace_empty
kinoafisha.info,tvcook.ru##.cat
rusopen.com##.classblsi.addshr
smotrisport.online,smotrisport.tv##.dont-add-our-site-pls
goha.ru#@#.goha_ads
goha.ru#@#.goha_ads_acceptable
themoviebay.ru##.is-danger.notification
ivi.ru##.ivi-footer ~ div[class] > style + div[class]
doctorrouter.ru##.jgcabd-container
go.mail.ru##.js-adb-msg
space.utema.ru##.main-content-padding > div[class]:not([itemprop])
megatest.online##.msg-AdBlock
ykt.ru##.n-banner--adblocked
animeland.su,itcats.ru,nekto.me,noadsradio.ru,sharkgame.ru,studies.in.ua,w10.jeanzzz.ru##.no-adb
mail.rambler.ru##.notification-warning
delfi.lv##.notification-widget
radio.yandex.by,radio.yandex.kz,radio.yandex.ru,radio.yandex.ua##.page-root .notify
radio.yandex.by,radio.yandex.kz,radio.yandex.ru,radio.yandex.ua##.page-root .notify *
music.yandex.by,music.yandex.kz,music.yandex.ru,music.yandex.ua##.page-root > .notify
music.yandex.by,music.yandex.kz,music.yandex.ru,music.yandex.ua##.page-root > .notify *
alexfilm.cc##.panel-primary
darkteam.net##.pls_rmv
newnavitel.blogspot.com##.post-body > div[dir] > div[dir] > h1#result
animedub.ru##.poverh
015.by,023.by,0312.ua,032.ua,0332.ua,0342.ua,0352.ua,0362.ua,0372.ua,0382.ua,0412.ua,04141.com.ua,0432.ua,04563.com.ua,04596.com.ua,04597.com.ua,04598.com.ua,0462.ua,0472.ua,048.ua,04868.com.ua,0512.com.ua,05136.com.ua,05161.com.ua,0522.ua,0532.ua,05366.com.ua,0542.ua,05447.com.ua,0552.ua,056.ua,0564.ua,0566.com.ua,0569.com.ua,057.ua,061.ua,06153.com.ua,0619.com.ua,0623.com.ua,06236.com.ua,06237.com.ua,06239.com.ua,06242.ua,06252.com.ua,06267.com.ua,06272.com.ua,06274.com.ua,06277.com.ua,0629.com.ua,0642.ua,06452.com.ua,0652.ua,0692.ua,1rnd.ru,3652.ru,3654.ru,3849.com.ua,44.ua,4594.com.ua,5692.com.ua,62.ua,6262.com.ua,6264.com.ua,65.media,7232.kz,8422city.ru,anapa.life,angarsk38.ru,bazhopol.ru,city01.am,city41.ru,comores24.com,go01.ru,go11.kz,go212.by,go216.by,go26.ru,go31.ru,go61.ru,godublin.info,golondon.info,goriga.info,gorod3466.ru,gorodarmavir.ru,goroddomodedovo.ru,gorodpushkin.ru,goshymkent.kz,inaktau.kz,inalmaty.kz,inastana.kz,inatyrau.kz,infolyubertsy.ru,inform69.ru,vilniuje.info,yocity12.ru##.pray-container
pythonworld.ru##.pythonworld-contributor
fanfics.me##.red.nodata
101.ru##.showMessageAdBlock
playunturned.ru##.side_left > center
playunturned.ru##.side_right > center
objavlenija.respublika.cz##.sweet-alert,.sweet-overlay
kinoprofi.net##.warning-adblock
xn--80aikhbrhr.net,кинокрад.net##.warning-adblock-box
forum.bestflowers.ru##.xenOverlay
/cookie_check.min.js$domain=acetv.me
/forum/docs/requests.js$script,domain=nnm-club-me.appspot.com|nnm-club.lib|nnm-club.me|nnm-club.ws|nnmclub.to|nontorclub.in.net
/fuckadblock.js$domain=ace-stream.tv
@@||anime.anidub.com/ads.js$script,domain=anime.anidub.com
@@||goha.ru/app/video/adblock.teaser.js|$script,domain=goha.ru
@@||sports.ru^*/adfox.$xmlhttprequest
auto62rus.ru,eset-key.ru,mycrib.ru,piggy-bank.online,politonline.ru,showmehow.ru##[data-type="anti-abp"]
lr-club.com##a[href="https://adblockplus.org/ru/faq_basics#disable"]
drive2.ru##a[href][target="_blank"] > img[src][style^="width: 100%; height: auto;"][style*="vertical-align: middle; max-width: 240px;"]
pic4you.ru,pic5you.ru##body > #bb
forum.vip-cxema.org##body > #document_modal.modal,#some_ad_block_key_popup
it-enginer.ru##body > #modal[style*="blur"]
newkaliningrad.ru##body > .soclinks + script + div[class]:not([id])
nnm-club-me.appspot.com,nnm-club.lib,nnm-club.me,nnm-club.ws,nnmclub.to,nontorclub.in.net##body > .request
swaego.ru##body > .special-message-wrapper
ukr.net##body > .yellow-die
poznamka.ru##body > [id]:not([class])[style^="z-index"]
in-trend.biz##body > [id][style^="z-index"]
fightnews.info##body > blockquote
torrnado.win##body > div > .a-overlay
olegon.ru##body > div:not([id]):not([class])[style^="color"][style*="position: fixed; width: 99%"]
rp5.by,rp5.kz,rp5.ru,rp5.ua##body > div:not([id]):not([class])[style^="position"][style*="background"][style*="z-index"]
factorio.su##body > div[class][style*="background"][style*="display: block"]
gdekluet.ru##body > div[class^="stop-block"]
glav.su##body > div[id]:not([class])[style*="background"][style*="display: block"]
logist.uxxo.ru,maxpark.com,newdeaf-online.net,newsland.com##body > div[id]:not([class])[style="display: block;"]
factorio.su##body > div[id][class][style*="background"][style*="visible"]
gisher.news,gisher.org##body > div[id][class][style^="display"][style*="position"][style*="z-index"]
gaming.co.ua##body > div[id][class][style*="z-index"][style*="9999"],body > div[id][class][style*="z-index"][style*="9999"] + div[class][style*="z-index"][style*="9999"]
gta.com.ua##body > div[id][style*="background"][style*="visible"]
portfel.info##body > div[id][style="display: block;"]
tut.by##body > div[style*="position: fixed;"][style*="right: 0;"]
1snau.ru,bychico.net,dyrik.ru,ecosounds.net,in-drive.ru,musecube.org,obozrevatel.com,oknotivi.ru,pogodnik.com,sandero.ru,tehnobzor.ru,turbominer.ru##body > div[style*="z-index"][style*="9999"]
dugtor.ru##body > noindex
blackdesert-info.ru##div[class][style*="z-index"][style*="999999;"][style*="background"][style*="rgb"]
kinopad.net##div[class^="adblock-warning"]
lostfilm.tv##div[class^="alarm"]
gismeteo.by,gismeteo.ru##div[class^="stopblock"]
finfront.ru##div[class^="swal2"]
savevideo.me##div[id^="ads_notice_"]
forvk.space##div[id^="block"][style*="display: block;"]
acomics.ru##div[style*="/design/common/pic/please"]
abc-people.com##div[style*="background-color"][style*="position"][style*="z-index"]
pvcalc.ru##div[style^="position:fixed; top:0px; left:0px; opacity: 0.9;"]
ph4.ru##div[style^="width: 728px; height: 90px;"]
bdmbase.ru##html > .q1
7sim.net##html > body ~ div
d3.ru##section[data-uid="ad"]
d3.ru##section[data-uid="extraAd"]
ph4.ru##table[width][height="90"][style]
bigpuzzle.ru##td[valign="top"][width="200px"][height="600"] > div[style]
tproger.ru#?#article.type-post:-abp-has([href="/adblock"])
www.qrz.ru#?#.content_row > div[class]:-abp-has(> .inner > a[href="/help/adblock/"])
||adscat.ru^$third-party
||allnorilsk.ru/js/adb.js
||animeteatr.ru/a-detector/
||anivisual.net/mim*.js|$script,domain=anivisual.net
||avito.ru^*/some-pretty-script.js
||fainaidea.com/wp-content/uploads/*/*?ver=$script,stylesheet,domain=fainaidea.com
||fairtop.in/template/js/fdetect.js
||i140.ru/js/etxm*.js|$script
||ipprof.ru/wp-content/plugins/ad-blocking-advisor/
||kontrolnaya-rabota.ru^*/fuckadblock.js$script
||kontrolnaya-rabota.ru^*/toastr.$script,stylesheet
||mhelp.kz/wp-content/plugins/wp-adblock-dedect/
||nnm-club.ws/forum/docs/requests.js
||olegon.ru/jscookie.js
||pwnews.net/des/antiblock.js$script
||rockstargame.su/adb_script/
||rusnext.ru/advar.js$script
||sdamgia.ru/img/blockadblock_
||shellcat.ru^$third-party
||stroi-help.ru/forum/script_new.js
! *** antiadblockfilters:antiadblockfilters/antiadblock_slovak.txt ***
! *** antiadblockfilters:antiadblockfilters/antiadblock_spanish.txt ***

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,525 @@
# AdAway default blocklist
# Blocking mobile ad providers and some analytics providers
#
# Contribute:
# Create an issue at https://github.com/AdAway/AdAway/issues
#
# Changelog:
# 2016-07-18 Now hosted on GitHub + Cloudflare
# 2014-05-18 Now with a valid SSL certificate available at https://adaway.org/hosts.txt
# 2013-03-29 Integrated some hosts from
# http://adblock.gjtech.net/?format=hostfile
# 2013-03-14 Back from the dead
#
# License:
# CC Attribution 3.0 (http://creativecommons.org/licenses/by/3.0/)
#
# Contributions by:
# Kicelo, Dominik Schuermann
#
127.0.0.1 localhost
::1 localhost
# [General]
127.0.0.1 lb.usemaxserver.de
127.0.0.1 tracking.klickthru.com
127.0.0.1 gsmtop.net
127.0.0.1 click.buzzcity.net
127.0.0.1 ads.admoda.com
127.0.0.1 stats.pflexads.com
127.0.0.1 a.glcdn.co
127.0.0.1 wwww.adleads.com
127.0.0.1 ad.madvertise.de
127.0.0.1 apps.buzzcity.net
127.0.0.1 ads.mobgold.com
127.0.0.1 android.bcfads.com
127.0.0.1 show.buzzcity.net
127.0.0.1 api.analytics.omgpop.com
127.0.0.1 r.edge.inmobicdn.net
127.0.0.1 www.mmnetwork.mobi
127.0.0.1 img.ads.huntmad.com
127.0.0.1 creative1cdn.mobfox.com
127.0.0.1 admicro2.vcmedia.vn
127.0.0.1 admicro1.vcmedia.vn
127.0.0.1 s3.phluant.com
127.0.0.1 c.vrvm.com
127.0.0.1 go.vrvm.com
127.0.0.1 static.estebull.com
127.0.0.1 mobile.Banzai.it
127.0.0.1 ads.xxxad.net
127.0.0.1 img.ads.mojiva.com
127.0.0.1 adcontent.saymedia.com
127.0.0.1 ads.saymedia.com
127.0.0.1 ftpcontent.worldnow.com
127.0.0.1 s0.2mdn.net
127.0.0.1 img.ads.mocean.mobi
127.0.0.1 bigmobileads.com
127.0.0.1 banners.bigmobileads.com
127.0.0.1 ads.mopub.com
127.0.0.1 images.mpression.net
127.0.0.1 images.millennialmedia.com
127.0.0.1 oasc04012.247realmedia.com
127.0.0.1 assets.cntdy.mobi
127.0.0.1 ad.leadboltapps.net ## another airpush style ad#
127.0.0.1 api.airpush.com ## hope this is all #
127.0.0.1 ad.where.com
127.0.0.1 i.tapit.com
127.0.0.1 cdn1.crispadvertising.com
127.0.0.1 cdn2.crispadvertising.com
127.0.0.1 medrx.sensis.com.au
127.0.0.1 rs-staticart.ybcdn.net
127.0.0.1 img.ads.taptapnetworks.com
127.0.0.1 adserver.ubiyoo.com
127.0.0.1 c753738.r38.cf2.rackcdn.com
127.0.0.1 edge.reporo.net
127.0.0.1 ads.n-ws.org
127.0.0.1 adultmoda.com
127.0.0.1 ads.smartdevicemedia.com
127.0.0.1 b.scorecardresearch.com
127.0.0.1 m.adsymptotic.com
127.0.0.1 cdn.vdopia.com
127.0.0.1 api.yp.com
127.0.0.1 asotrack1.fluentmobile.com
127.0.0.1 android-sdk31.transpera.com
127.0.0.1 apps.mobilityware.com
127.0.0.1 ads.mobilityware.com
127.0.0.1 ads.admarvel.com
127.0.0.1 netdna.reporo.net
127.0.0.1 www.eltrafiko.com
127.0.0.1 cdn.trafficforce.com
127.0.0.1 gts-ads.twistbox.com
127.0.0.1 static.cdn.gtsmobi.com
127.0.0.1 ads.matomymobile.com
127.0.0.1 ads.adiquity.com
127.0.0.1 img.ads.mobilefuse.net
127.0.0.1 as.adfonic.net
127.0.0.1 media.mobpartner.mobi
127.0.0.1 cdn.us.goldspotmedia.com
127.0.0.1 ads2.mediaarmor.com
127.0.0.1 cdn.nearbyad.com
127.0.0.1 ads.ookla.com
127.0.0.1 mobiledl.adobe.com
127.0.0.1 ads.flurry.com
127.0.0.1 gemini.yahoo.com
# [hosted on cloudfront]
127.0.0.1 d3anogn3pbtk4v.cloudfront.net
127.0.0.1 d3oltyb66oj2v8.cloudfront.net
127.0.0.1 d2bgg7rjywcwsy.cloudfront.net
# [vserv.mobi]
127.0.0.1 a.vserv.mobi
127.0.0.1 admin.vserv.mobi
127.0.0.1 c.vserv.mobi
127.0.0.1 ads.vserv.mobi
127.0.0.1 sf.vserv.mobi
# [pflexads.com]
127.0.0.1 hybl9bazbc35.pflexads.com
127.0.0.1 hhbekxxw5d9e.pflexads.com
127.0.0.1 www.pflexads.com
127.0.0.1 orencia.pflexads.com
# [velti.com]
127.0.0.1 atti.velti.com
127.0.0.1 ru.velti.com
127.0.0.1 mwc.velti.com
# [celtra.com]
127.0.0.1 cdn.celtra.com
127.0.0.1 ads.celtra.com
127.0.0.1 cache-ssl.celtra.com
127.0.0.1 cache.celtra.com
127.0.0.1 track.celtra.com
# [inner-active.mobi]
127.0.0.1 wv.inner-active.mobi
127.0.0.1 cdn1.inner-active.mobi
127.0.0.1 m2m1.inner-active.mobi
# [Jumptab]
127.0.0.1 bos-tapreq01.jumptap.com
127.0.0.1 bos-tapreq02.jumptap.com
127.0.0.1 bos-tapreq03.jumptap.com
127.0.0.1 bos-tapreq04.jumptap.com
127.0.0.1 bos-tapreq05.jumptap.com
127.0.0.1 bos-tapreq06.jumptap.com
127.0.0.1 bos-tapreq07.jumptap.com
127.0.0.1 bos-tapreq08.jumptap.com
127.0.0.1 bos-tapreq09.jumptap.com
127.0.0.1 bos-tapreq10.jumptap.com
127.0.0.1 bos-tapreq11.jumptap.com
127.0.0.1 bos-tapreq12.jumptap.com
127.0.0.1 bos-tapreq13.jumptap.com
127.0.0.1 bos-tapreq14.jumptap.com
127.0.0.1 bos-tapreq15.jumptap.com
127.0.0.1 bos-tapreq16.jumptap.com
127.0.0.1 bos-tapreq17.jumptap.com
127.0.0.1 bos-tapreq18.jumptap.com
127.0.0.1 bos-tapreq19.jumptap.com
127.0.0.1 bos-tapreq20.jumptap.com
127.0.0.1 web64.jumptap.com
127.0.0.1 web63.jumptap.com
127.0.0.1 web65.jumptap.com
127.0.0.1 bo.jumptap.com
127.0.0.1 i.jumptap.com
# [applovin]
127.0.0.1 a.applovin.com
127.0.0.1 d.applovin.com
127.0.0.1 pdn.applovin.com
# [Mobpartner]
127.0.0.1 mobpartner.mobi
127.0.0.1 go.mobpartner.mobi
127.0.0.1 r.mobpartner.mobi
# [Adinfuse]
127.0.0.1 uk-ad2.adinfuse.com
127.0.0.1 adinfuse.com
127.0.0.1 go.adinfuse.com
127.0.0.1 ad1.adinfuse.com
127.0.0.1 ad2.adinfuse.com
127.0.0.1 sky.adinfuse.com
127.0.0.1 orange-fr.adinfuse.com
127.0.0.1 sky-connect.adinfuse.com
127.0.0.1 uk-go.adinfuse.com
127.0.0.1 orangeuk-mc.adinfuse.com
127.0.0.1 intouch.adinfuse.com
127.0.0.1 funnel0.adinfuse.com
# [mydas.mobi]
127.0.0.1 cvt.mydas.mobi
127.0.0.1 lp.mydas.mobi
127.0.0.1 golds.lp.mydas.mobi
127.0.0.1 suo.lp.mydas.mobi
127.0.0.1 aio.lp.mydas.mobi
127.0.0.1 lp.mp.mydas.mobi
127.0.0.1 media.mydas.mobi
127.0.0.1 ads.mp.mydas.mobi # with many subdomains
# [appads.com]
127.0.0.1 neptune.appads.com
127.0.0.1 neptune1.appads.com
127.0.0.1 neptune2.appads.com
127.0.0.1 neptune3.appads.com
127.0.0.1 saturn.appads.com
127.0.0.1 saturn1.appads.com
127.0.0.1 saturn2.appads.com
127.0.0.1 saturn3.appads.com
127.0.0.1 jupiter.appads.com
127.0.0.1 jupiter1.appads.com
127.0.0.1 jupiter2.appads.com
127.0.0.1 jupiter3.appads.com
127.0.0.1 req.appads.com
127.0.0.1 req1.appads.com
127.0.0.1 req2.appads.com
127.0.0.1 req3.appads.com
# [yandex.ru]
127.0.0.1 mc.yandex.ru
127.0.0.1 an.yandex.ru
# [tapad]
127.0.0.1 swappit.tapad.com
127.0.0.1 campaign-tapad.s3.amazonaws.com
127.0.0.1 adsrv1.tapad.com
# [mojiva.com]
127.0.0.1 ads1.mojiva.com
127.0.0.1 ads2.mojiva.com
127.0.0.1 ads3.mojiva.com
127.0.0.1 ads4.mojiva.com
127.0.0.1 ads5.mojiva.com
# [inmobi.com]
127.0.0.1 i.w.inmobi.com #
127.0.0.1 r.w.inmobi.com # in-app provider
127.0.0.1 c.w.inmobi.com
127.0.0.1 adtracker.inmobi.com
127.0.0.1 china.inmobi.com
127.0.0.1 japan.inmobi.com
# [phluantmobile.net]
127.0.0.1 mdn1.phluantmobile.net
127.0.0.1 mdn2.phluantmobile.net
127.0.0.1 mdn3.phluantmobile.net
127.0.0.1 mdn3origin.phluantmobile.net
# [smaato.net]
127.0.0.1 soma.smaato.net
127.0.0.1 c29new.smaato.net
127.0.0.1 c01.smaato.net
127.0.0.1 c02.smaato.net
127.0.0.1 c03.smaato.net
127.0.0.1 c04.smaato.net
127.0.0.1 c05.smaato.net
127.0.0.1 c06.smaato.net
127.0.0.1 c07.smaato.net
127.0.0.1 c08.smaato.net
127.0.0.1 c09.smaato.net
127.0.0.1 c10.smaato.net
127.0.0.1 c11.smaato.net
127.0.0.1 c12.smaato.net
127.0.0.1 c13.smaato.net
127.0.0.1 c14.smaato.net
127.0.0.1 c15.smaato.net
127.0.0.1 c16.smaato.net
127.0.0.1 c17.smaato.net
127.0.0.1 c18.smaato.net
127.0.0.1 c19.smaato.net
127.0.0.1 c20.smaato.net
127.0.0.1 c21.smaato.net
127.0.0.1 c22.smaato.net
127.0.0.1 c23.smaato.net
127.0.0.1 c24.smaato.net
127.0.0.1 c25.smaato.net
127.0.0.1 c26.smaato.net
127.0.0.1 c27.smaato.net
127.0.0.1 c28.smaato.net
127.0.0.1 c29.smaato.net
127.0.0.1 c30.smaato.net
127.0.0.1 c31.smaato.net
127.0.0.1 c32.smaato.net
127.0.0.1 c33.smaato.net
127.0.0.1 c34.smaato.net
127.0.0.1 c35.smaato.net
127.0.0.1 c36.smaato.net
127.0.0.1 c37.smaato.net
127.0.0.1 c38.smaato.net
127.0.0.1 c39.smaato.net
127.0.0.1 c40.smaato.net
127.0.0.1 c41.smaato.net
127.0.0.1 c42.smaato.net
127.0.0.1 c43.smaato.net
127.0.0.1 c44.smaato.net
127.0.0.1 c45.smaato.net
127.0.0.1 c46.smaato.net
127.0.0.1 c47.smaato.net
127.0.0.1 c48.smaato.net
127.0.0.1 c49.smaato.net
127.0.0.1 c50.smaato.net
127.0.0.1 c51.smaato.net
127.0.0.1 c52.smaato.net
127.0.0.1 c53.smaato.net
127.0.0.1 c54.smaato.net
127.0.0.1 c55.smaato.net
127.0.0.1 c56.smaato.net
127.0.0.1 c57.smaato.net
127.0.0.1 c58.smaato.net
127.0.0.1 c59.smaato.net
127.0.0.1 c60.smaato.net
127.0.0.1 f03.smaato.net
127.0.0.1 f04.smaato.net
127.0.0.1 f05.smaato.net
127.0.0.1 f06.smaato.net
127.0.0.1 f07.smaato.net
127.0.0.1 f08.smaato.net
127.0.0.1 f09.smaato.net
127.0.0.1 f10.smaato.net
127.0.0.1 f11.smaato.net
127.0.0.1 f12.smaato.net
127.0.0.1 f13.smaato.net
127.0.0.1 f14.smaato.net
127.0.0.1 f15.smaato.net
127.0.0.1 f16.smaato.net
127.0.0.1 f17.smaato.net
127.0.0.1 f18.smaato.net
127.0.0.1 f19.smaato.net
127.0.0.1 f20.smaato.net
127.0.0.1 f21.smaato.net
127.0.0.1 f22.smaato.net
127.0.0.1 f23.smaato.net
127.0.0.1 f24.smaato.net
127.0.0.1 f25.smaato.net
127.0.0.1 f26.smaato.net
127.0.0.1 f27.smaato.net
127.0.0.1 f28.smaato.net
127.0.0.1 f29.smaato.net
127.0.0.1 f30.smaato.net
127.0.0.1 f31.smaato.net
127.0.0.1 f32.smaato.net
127.0.0.1 f33.smaato.net
127.0.0.1 f34.smaato.net
127.0.0.1 f35.smaato.net
127.0.0.1 f36.smaato.net
127.0.0.1 f37.smaato.net
127.0.0.1 f38.smaato.net
127.0.0.1 f39.smaato.net
127.0.0.1 f40.smaato.net
127.0.0.1 f41.smaato.net
127.0.0.1 f42.smaato.net
127.0.0.1 f43.smaato.net
127.0.0.1 f44.smaato.net
127.0.0.1 f45.smaato.net
127.0.0.1 f46.smaato.net
127.0.0.1 f47.smaato.net
127.0.0.1 f48.smaato.net
127.0.0.1 f49.smaato.net
127.0.0.1 f50.smaato.net
127.0.0.1 f51.smaato.net
127.0.0.1 f52.smaato.net
127.0.0.1 f53.smaato.net
127.0.0.1 f54.smaato.net
127.0.0.1 f55.smaato.net
127.0.0.1 f56.smaato.net
127.0.0.1 f57.smaato.net
127.0.0.1 f58.smaato.net
127.0.0.1 f59.smaato.net
127.0.0.1 f60.smaato.net
# [mojiva.com]
127.0.0.1 img.ads1.mojiva.com
127.0.0.1 img.ads2.mojiva.com
127.0.0.1 img.ads3.mojiva.com
127.0.0.1 img.ads4.mojiva.com
# [mocean.mobi]
127.0.0.1 img.ads1.mocean.mobi
127.0.0.1 img.ads2.mocean.mobi
127.0.0.1 img.ads3.mocean.mobi
127.0.0.1 img.ads4.mocean.mobi
# [Smart Adserver]
127.0.0.1 akamai.smartadserver.com
127.0.0.1 cdn1.smartadserver.com
127.0.0.1 diff.smartadserver.com
127.0.0.1 diff2.smartadserver.com
127.0.0.1 diff3.smartadserver.com
127.0.0.1 eqx.smartadserver.com
127.0.0.1 im2.smartadserver.com
127.0.0.1 itx5-publicidad.smartadserver.com
127.0.0.1 itx5.smartadserver.com
127.0.0.1 tcy.smartadserver.com
127.0.0.1 ww129.smartadserver.com
127.0.0.1 ww13.smartadserver.com
127.0.0.1 ww14.smartadserver.com
127.0.0.1 ww234.smartadserver.com
127.0.0.1 ww251.smartadserver.com
127.0.0.1 ww264.smartadserver.com
127.0.0.1 ww302.smartadserver.com
127.0.0.1 ww362.smartadserver.com
127.0.0.1 ww370.smartadserver.com
127.0.0.1 ww381.smartadserver.com
127.0.0.1 ww392.smartadserver.com
127.0.0.1 ww55.smartadserver.com
127.0.0.1 ww57.smartadserver.com
127.0.0.1 ww84.smartadserver.com
127.0.0.1 www.smartadserver.com
127.0.0.1 www2.smartadserver.com
127.0.0.1 www3.smartadserver.com
127.0.0.1 www4.smartadserver.com
# [Mobclix]
127.0.0.1 ads.mobclix.com
127.0.0.1 data.mobclix.com
127.0.0.1 s.mobclix.com
# [MdotM, Inc.]
127.0.0.1 ads.mdotm.com
127.0.0.1 cdn.mdotm.com
# [Greystripe]
127.0.0.1 ads2.greystripe.com
127.0.0.1 adsx.greystripe.com
127.0.0.1 c.greystripe.com
# [Amazon]
127.0.0.1 aax-us-east.amazon-adsystem.com
127.0.0.1 aax-us-west.amazon-adsystem.com
127.0.0.1 s.amazon-adsystem.com
# [Hosted on Amazon AWS]
127.0.0.1 admarvel.s3.amazonaws.com
127.0.0.1 html5adkit.plusmo.s3.amazonaws.com
127.0.0.1 inneractive-assets.s3.amazonaws.com
127.0.0.1 strikeadcdn.s3.amazonaws.com
# [Admob]
127.0.0.1 a.admob.com
127.0.0.1 analytics.admob.com
127.0.0.1 c.admob.com
127.0.0.1 media.admob.com
127.0.0.1 p.admob.com
# [AdWhirl]
127.0.0.1 met.adwhirl.com
127.0.0.1 mob.adwhirl.com
# [Doubleclick (Google)]
127.0.0.1 ad-g.doubleclick.net
127.0.0.1 ad.doubleclick.net
127.0.0.1 ad.mo.doubleclick.net
127.0.0.1 doubleclick.net
127.0.0.1 googleads.g.doubleclick.net
# [Google]
127.0.0.1 pagead.googlesyndication.com
127.0.0.1 pagead1.googlesyndication.com
127.0.0.1 pagead2.googlesyndication.com
# [National Rail Enquiries, https://play.google.com/store/apps/details?id=uk.co.nationalrail.google]
127.0.0.1 events.foreseeresults.com
127.0.0.1 survey.foreseeresults.com
127.0.0.1 m.quantserve.com
# [leadboltmobile]
127.0.0.1 ad.leadboltmobile.net
# [MSN Ads, in Skype]
127.0.0.1 mobileads.msn.com
# [https://play.google.com/store/apps/details?id=myapp.devilbaby.android.music.newmusic]
127.0.0.1 img.adecorp.co.kr
127.0.0.1 us0.adlibr.com
127.0.0.1 ad.parrot.mable-inc.com
# [http://play.google.com/store/apps/details?id=com.chuangkai.phonehelper]
127.0.0.1 aos.wall.youmi.net
127.0.0.1 au.youmi.net
# [http://play.google.com/store/apps/details?id=com.coconuts.webnavigator]
127.0.0.1 coconuts.boy.jp
127.0.0.1 iacpromotion.s3.amazonaws.com
127.0.0.1 plugin.2easydroid.com
# [http://play.google.com/store/apps/details?id=com.babjul.billboard]
127.0.0.1 adimg3.search.naver.net
# [http://play.google.com/store/apps/details?id=com.taeyang.billboardtop]
127.0.0.1 st.a-link.co.kr
127.0.0.1 cdn.ajillionmax.com
127.0.0.1 dispatch.admixer.co.kr
127.0.0.1 ifc.inmobi.com
127.0.0.1 thinknear-hosted.thinknearhub.com
# [https://play.google.com/store/apps/details?id=com.buymeapie.bmap]
127.0.0.1 ads.adadapted.com
#
# ANALYTICS
#
127.0.0.1 analytics.localytics.com
# [Medialytics]
127.0.0.1 a.medialytics.com
127.0.0.1 c.medialytics.com
127.0.0.1 cdn.creative.medialytics.com
127.0.0.1 p.medialytics.com
127.0.0.1 px.cdn.creative.medialytics.com
127.0.0.1 t.medialytics.com
# [Google]
127.0.0.1 google-analytics.com
127.0.0.1 googlesyndication.com
# [applift]
127.0.0.1 applift.com
# use finer grained hostnames?
#127.0.0.1 tracking.applift.com
# [EFF Tracker Detection]
127.0.0.1 trackersimulator.org
127.0.0.1 eviltracker.net
127.0.0.1 do-not-tracker.org

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
#
# Copyright (C) 2015-2016 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v3.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=clash
PKG_VERSION:=0.14.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=net
CATEGORY:=Network
TITLE:=clash is a cross-platform proxy software
DEPENDS:=
URL:=https://github.com/Dreamacro/clash/releases
endef
define Package/$(PKG_NAME)/description
clash is a cross-platform proxy software
endef
ifeq ($(ARCH),x86_64)
PKG_ARCH_CLASH:=linux-amd64
endif
ifeq ($(ARCH),i386)
PKG_ARCH_CLASH:=linux-386
endif
ifeq ($(ARCH),mipsel)
PKG_ARCH_CLASH:=linux-mipsle
endif
ifeq ($(ARCH),mips)
PKG_ARCH_CLASH:=linux-mips-hardfloat
endif
ifeq ($(ARCH),arm)
PKG_ARCH_CLASH:=linux-armv6
endif
ifeq ($(ARCH),aarch64)
PKG_ARCH_CLASH:=linux-armv8
endif
define Build/Prepare
#[ ! -f $(PKG_BUILD_DIR)/clash-v$(PKG_VERSION)-$(PKG_ARCH_CLASH).tar.gz ] && wget https://github.com/Dreamacro/clash/releases/download/v$(PKG_VERSION)/clash-$(PKG_ARCH_CLASH).tar.gz -O $(PKG_BUILD_DIR)/clash-v$(PKG_VERSION)-$(PKG_ARCH_CLASH).tar.gz
#tar -xzvf $(PKG_BUILD_DIR)/clash-v$(PKG_VERSION)-$(PKG_ARCH_CLASH).tar.gz -C $(PKG_BUILD_DIR)
[ ! -f $(PKG_BUILD_DIR)/clash-$(PKG_ARCH_CLASH).gz ] && wget https://github.com/Dreamacro/clash/releases/download/v$(PKG_VERSION)/clash-$(PKG_ARCH_CLASH)-v$(PKG_VERSION).gz -O $(PKG_BUILD_DIR)/clash-$(PKG_ARCH_CLASH).gz
gunzip $(PKG_BUILD_DIR)/clash-$(PKG_ARCH_CLASH).gz
endef
define Build/Configure
endef
define Build/Compile
#chmod +x $(PKG_BUILD_DIR)/clash-v$(PKG_VERSION)-$(PKG_ARCH_CLASH) && upx --ultra-brute $(PKG_BUILD_DIR)/clash-v$(PKG_VERSION)-$(PKG_ARCH_CLASH)
#echo "$(PKG_VERSION)" > $(PKG_BUILD_DIR)/clash_version
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/clash
$(INSTALL_BIN) $(PKG_BUILD_DIR)/clash-$(PKG_ARCH_CLASH) $(1)/etc/clash/clash
#$(INSTALL_DIR) $(1)/usr/share/clash
#$(INSTALL_DATA) $(PKG_BUILD_DIR)/clash_version $(1)/usr/share/clash/clash_version
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -0,0 +1 @@
12

View File

@ -0,0 +1 @@
12

View File

@ -0,0 +1,154 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*
* Dynamic list implementation
*
*/
#include <stdlib.h>
#include <string.h>
#include "list.h"
#define EMPTYLIST NULL
void init_list(struct list *l,int keysize) {
l->first=l->last=NULL;
l->keysize=keysize;
l->count=0;
}
struct list_node *add_elem(struct list *l,void *elem) {
struct list_node *newnode=(struct list_node*)malloc(sizeof(struct list_node));
newnode->data=elem;
newnode->previous=l->last;
newnode->next=NULL;
if (l->count==0) {
l->first=l->last=newnode;
}
else {
l->last->next=newnode;
l->last=newnode;
}
l->count++;
return newnode;
}
void delete_node(struct list *l,struct list_node *node) {
if (l->count==1) {
l->first=l->last=NULL;
}
else if (node==l->first) {
node->next->previous=NULL;
l->first=node->next;
}
else if (node==l->last) {
node->previous->next=NULL;
l->last=node->previous;
}
else {
node->previous->next=node->next;
node->next->previous=node->previous;
}
l->count--;
free(node);
node = NULL;
}
void destroy_node(struct list *l,struct list_node *node) {
free(node->data);
node->data=NULL;
delete_node(l,node);
}
int is_EMPTYLIST_list(struct list *l) {
return (l->count==0?TRUE:FALSE);
}
int get_list_count(struct list *l) {
return l->count;
}
void *first_elem(struct list *l) {
return l->first->data;
}
struct list_node *first_node(struct list *l) {
return l->first;
}
void *last_elem(struct list *l) {
return l->last->data;
}
struct list_node *last_node(struct list *l) {
return l->last;
}
struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length) {
struct list_node *tmp;
tmp=l->first;
while(tmp!=NULL) {
if(!memcmp((char*)tmp->data+offset,elem,length==0?l->keysize:length)) return (tmp);
tmp=tmp->next;
}
return EMPTYLIST;
}
struct list_node *locate_node(struct list *l,void *elem) {
return(xlocate_node(l,elem,0,0));
}
void *xlocate_elem(struct list *l,void *elem,int offset,int length) {
struct list_node *node=xlocate_node(l,elem,offset,length);
return(node==NULL?NULL:node->data);
}
void *locate_elem(struct list *l,void *elem) {
return(xlocate_elem(l,elem,0,0));
}
void flush_list(struct list *l) {
struct list_node *tmp;
while(l->first!=EMPTYLIST) {
tmp=l->first;
l->first=l->first->next;
free(tmp);
tmp=NULL;
}
l->last=EMPTYLIST;
l->count=0;
}
void destroy_list(struct list *l) {
struct list_node *tmp;
while(l->first!=EMPTYLIST) {
tmp=l->first;
l->first=l->first->next;
free(tmp->data);
tmp->data=NULL;
free(tmp);
tmp=NULL;
}
l->last=EMPTYLIST;
l->count=0;
}

View File

@ -0,0 +1,601 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2012, by: Gang Liu <gangban.lau@gmail.com>
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*
* This is a simple program to limit the cpu usage of a process
* If you modify this code, send me a copy please
*
* Date: 30/8/2008
* Version: 1.2 beta
* Get the latest version at: http://cpulimit.sourceforge.net
*
* Changelog from 1.1:
* - reorganization of the code, splitted in more source files
* - cpu count detection, i.e. if you have 4 cpu, it is possible to limit up to 400%
* - in order to avoid deadlocks, cpulimit now prevents to limit itself
* - option --path eliminated, use --exe instead both for absolute path and file name
* - call setpriority() just once in limit_process()
* - no more segmentation fault when processes exit
* - no more memory corruption when processes exit
* - cpulimit exits if --lazy option is specified and the process terminates
* - target process can be created on-fly given command line
* - light and scalable algorithm for subprocesses detection and limitation
* - mac os support
* - minor enhancements and bugfixes
*
*/
#include <getopt.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include "process.h"
#include "procutils.h"
#include "list.h"
//some useful macro
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
//control time slot in microseconds
//each slot is splitted in a working slice and a sleeping slice
//TODO: make it adaptive, based on the actual system load
#define TIME_SLOT 100000
#define MAX_PRIORITY -10
/* GLOBAL VARIABLES */
//the "family"
struct process_family pf;
//pid of cpulimit
pid_t cpulimit_pid;
//name of this program (maybe cpulimit...)
char *program_name;
//number of cpu
int NCPU;
/* CONFIGURATION VARIABLES */
//verbose mode
int verbose = 0;
//lazy mode (exits if there is no process)
int lazy = 0;
static void *memrchr(const void *s, int c, size_t n)
{
const unsigned char *start = (const unsigned char*)s;
const unsigned char *end = (const unsigned char*)s;
end+=n-1;
while(end>=start) {
if(*end==c)
return (void *)end;
else
end--;
}
return NULL;
}
//SIGINT and SIGTERM signal handler
static void quit(int sig)
{
//let all the processes continue if stopped
struct list_node *node = NULL;
for (node=pf.members.first; node!= NULL; node=node->next) {
struct process *p = (struct process*)(node->data);
kill(p->pid, SIGCONT);
process_close(p);
}
//free all the memory
cleanup_process_family(&pf);
//fix ^C little problem
printf("\r");
fflush(stdout);
exit(0);
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2)
{
return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec);
}
static void print_usage(FILE *stream, int exit_code)
{
fprintf(stream, "Usage: %s [OPTIONS...] TARGET\n", program_name);
fprintf(stream, " OPTIONS\n");
fprintf(stream, " -l, --limit=N percentage of cpu allowed from 0 to %d (required)\n", 100*NCPU);
fprintf(stream, " -v, --verbose show control statistics\n");
fprintf(stream, " -z, --lazy exit if there is no target process, or if it dies\n");
fprintf(stream, " -i, --ignore-children don't limit children processes\n");
fprintf(stream, " -h, --help display this help and exit\n");
fprintf(stream, " TARGET must be exactly one of these:\n");
fprintf(stream, " -p, --pid=N pid of the process (implies -z)\n");
fprintf(stream, " -e, --exe=FILE name of the executable program file or path name\n");
fprintf(stream, " COMMAND [ARGS] run this command and limit it (implies -z)\n");
fprintf(stream, "\nReport bugs to <marlonx80@hotmail.com>.\n");
exit(exit_code);
}
static void increase_priority() {
//find the best available nice value
errno = 0; // clear errno first
int old_priority = getpriority(PRIO_PROCESS, 0);
if (errno)
{
perror("getpriority failed");
return;
}
int priority = old_priority;
while (priority > MAX_PRIORITY && setpriority(PRIO_PROCESS, 0, priority-1) == 0) {
priority--;
}
if (priority != old_priority) {
if (verbose) printf("Priority changed to %d\n", priority);
}
else {
if (verbose) printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
}
}
/* Get the number of CPUs */
static int get_ncpu() {
int ncpu = -1;
#ifdef _SC_NPROCESSORS_ONLN
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
#elif defined __APPLE__
int mib[2] = {CTL_HW, HW_NCPU};
size_t len = sizeof(ncpu);
sysctl(mib, 2, &ncpu, &len, NULL, 0);
#endif
return ncpu;
}
#ifdef __linux__
#include <sys/vfs.h>
static int check_proc()
{
struct statfs mnt;
if (statfs("/proc", &mnt) < 0)
return 0;
if (mnt.f_type!=0x9fa0)
return 0;
return 1;
}
#endif
void limit_process(pid_t pid, double limit, int ignore_children)
{
//slice of the slot in which the process is allowed to run
struct timespec twork;
//slice of the slot in which the process is stopped
struct timespec tsleep;
//when the last twork has started
struct timeval startwork;
//when the last twork has finished
struct timeval endwork;
//initialization
memset(&twork, 0, sizeof(struct timespec));
memset(&tsleep, 0, sizeof(struct timespec));
memset(&startwork, 0, sizeof(struct timeval));
memset(&endwork, 0, sizeof(struct timeval));
//last working time in microseconds
unsigned long workingtime = 0;
//generic list item
struct list_node *node;
//counter
int c = 0;
//get a better priority
//increase_priority();
//build the family
if (create_process_family(&pf, pid) == -1)
{
printf("create process family failed");
return ;
}
if (ignore_children) {
//delete any process with a different pid than the father
node = pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (proc->pid != pid)
{
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
node = node->next;
}
}
if (!ignore_children && verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.count);
//rate at which we are keeping active the processes (range 0-1)
//1 means that the process are using all the twork slice
double workingrate = -1;
while(1) {
if (!ignore_children && c%10==0) {
//update the process family (checks only for new members)
int new_children = update_process_family(&pf);
if (verbose && new_children) {
printf("%d new children processes detected (", new_children);
int j;
node = pf.members.last;
for (j=0; j<new_children; j++) {
printf("%d", ((struct process*)(node->data))->pid);
if (j<new_children-1) printf(" ");
node = node->previous;
}
printf(")\n");
}
}
if (pf.members.count==0) {
if (verbose) printf("No more processes.\n");
break;
}
//total cpu actual usage (range 0-1)
//1 means that the processes are using 100% cpu
double pcpu = -1;
//estimate how much the controlled processes are using the cpu in the working interval
node = pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (proc->is_zombie) {
//process is zombie, remove it from family
fprintf(stderr,"Process %d is zombie!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
if (process_monitor(proc) != 0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
node = node->next;
if (proc->cpu_usage<0) {
continue;
}
if (pcpu<0) pcpu = 0;
pcpu += proc->cpu_usage;
}
//adjust work and sleep time slices
if (pcpu < 0) {
//it's the 1st cycle, initialize workingrate
pcpu = limit;
workingrate = limit;
twork.tv_nsec = TIME_SLOT*limit*1000;
}
else {
//adjust workingrate
workingrate = MIN(workingrate / pcpu * limit, 1);
twork.tv_nsec = TIME_SLOT*1000*workingrate;
}
tsleep.tv_nsec = TIME_SLOT*1000-twork.tv_nsec;
if (verbose) {
if (c%200==0)
printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
if (c%10==0 && c>0)
printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100);
}
//resume processes
node = pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGCONT)!=0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
node=node->next;
}
//now processes are free to run (same working slice for all)
gettimeofday(&startwork, NULL);
nanosleep(&twork,NULL);
gettimeofday(&endwork, NULL);
workingtime = timediff(&endwork,&startwork);
long delay = workingtime-twork.tv_nsec/1000;
if (c>0 && delay>10000) {
//delay is too much! signal to user?
//fprintf(stderr, "%d %ld us\n", c, delay);
}
if (tsleep.tv_nsec>0) {
//stop only if tsleep>0, instead it's useless
node=pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGSTOP)!=0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node=pf.members.first;
continue;
}
node=node->next;
}
//now the processes are sleeping
nanosleep(&tsleep,NULL);
}
c++;
}
cleanup_process_family(&pf);
}
int main(int argc, char **argv) {
//argument variables
const char *exe = NULL;
int perclimit = 0;
int exe_ok = 0;
int pid_ok = 0;
int limit_ok = 0;
pid_t pid = 0;
int ignore_children = 0;
//get program name
char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
program_name = p==NULL?argv[0]:(p+1);
//get current pid
cpulimit_pid = getpid();
//get cpu count
NCPU = get_ncpu();
//parse arguments
int next_option;
int option_index = 0;
//A string listing valid short options letters
const char* short_options = "+p:e:l:vzih";
//An array describing valid long options
const struct option long_options[] = {
{ "pid", required_argument, NULL, 'p' },
{ "exe", required_argument, NULL, 'e' },
{ "limit", required_argument, NULL, 'l' },
{ "verbose", no_argument, NULL, 'v' },
{ "lazy", no_argument, NULL, 'z' },
{ "ignore-children", no_argument, NULL, 'i' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
do {
next_option = getopt_long(argc, argv, short_options,long_options, &option_index);
switch(next_option) {
case 'p':
pid = atoi(optarg);
pid_ok = 1;
break;
case 'e':
exe = optarg;
exe_ok = 1;
break;
case 'l':
perclimit = atoi(optarg);
limit_ok = 1;
break;
case 'v':
verbose = 1;
break;
case 'z':
lazy = 1;
break;
case 'i':
ignore_children = 1;
break;
case 'h':
print_usage(stdout, 1);
break;
case '?':
print_usage(stderr, 1);
break;
case -1:
break;
default:
abort();
}
} while(next_option != -1);
if (pid_ok && (pid<=1 || pid>=65536)) {
fprintf(stderr,"Error: Invalid value for argument PID\n");
print_usage(stderr, 1);
exit(1);
}
if (pid!=0) {
lazy = 1;
}
if (!limit_ok) {
fprintf(stderr,"Error: You must specify a cpu limit percentage\n");
print_usage(stderr, 1);
exit(1);
}
double limit = perclimit/100.0;
if (limit<0 || limit >NCPU) {
fprintf(stderr,"Error: limit must be in the range 0-%d00\n", NCPU);
print_usage(stderr, 1);
exit(1);
}
int command_mode = optind<argc;
if (exe_ok + pid_ok + command_mode == 0) {
fprintf(stderr,"Error: You must specify one target process, either by name, pid, or command line\n");
print_usage(stderr, 1);
exit(1);
}
if (exe_ok + pid_ok + command_mode > 1) {
fprintf(stderr,"Error: You must specify exactly one target process, either by name, pid, or command line\n");
print_usage(stderr, 1);
exit(1);
}
//all arguments are ok!
signal(SIGINT, quit);
signal(SIGTERM, quit);
//print the number of available cpu
if (verbose) printf("%d cpu detected\n", NCPU);
#ifdef __linux__
if (!check_proc()) {
fprintf(stderr, "procfs is not mounted!\nAborting\n");
exit(-2);
}
#endif
if (command_mode) {
int i;
//executable file
const char *cmd = argv[optind];
//command line arguments
char **cmd_args = (char**)malloc((argc-optind+1)*sizeof(char*));
if (cmd_args==NULL) exit(2);
for (i=0; i<argc-optind; i++) {
cmd_args[i] = argv[i+optind];
}
cmd_args[i] = NULL;
if (verbose) {
printf("Running command: '%s", cmd);
for (i=1; i<argc-optind; i++) {
printf(" %s", cmd_args[i]);
}
printf("'\n");
}
int child = fork();
if (child < 0) {
exit(EXIT_FAILURE);
}
else if (child > 0) {
//parent code
int limiter = fork();
if (limiter < 0) {
exit(EXIT_FAILURE);
}
else if (limiter > 0) {
//parent
int status_process;
int status_limiter;
waitpid(child, &status_process, 0);
waitpid(limiter, &status_limiter, 0);
if (WIFEXITED(status_process)) {
if (verbose) printf("Process %d terminated with exit status %d\n", child, (int)WEXITSTATUS(status_process));
exit(WEXITSTATUS(status_process));
}
printf("Process %d terminated abnormally\n", child);
exit(status_process);
}
else {
//limiter code
if (verbose) printf("Limiting process %d\n",child);
limit_process(child, limit, ignore_children);
exit(0);
}
}
else {
//target process code
int ret = execvp(cmd, cmd_args);
//if we are here there was an error, show it
perror("Error");
exit(ret);
}
}
while(1) {
//look for the target process..or wait for it
pid_t ret = 0;
if (pid_ok) {
//search by pid
ret = look_for_process_by_pid(pid);
if (ret == 0) {
printf("No process found\n");
}
else if (ret < 0) {
printf("Process found but you aren't allowed to control it\n");
}
}
else {
//search by file or path name
ret = look_for_process_by_name(exe);
if (ret == 0) {
printf("No process found\n");
}
else if (ret < 0) {
printf("Process found but you aren't allowed to control it\n");
}
else {
pid = ret;
}
}
if (ret > 0) {
if (ret == cpulimit_pid) {
printf("Process %d is cpulimit itself! Aborting to avoid deadlock\n", ret);
exit(1);
}
printf("Process %d found\n", pid);
//control
limit_process(pid, limit, ignore_children);
}
if (lazy) break;
sleep(2);
};
exit(0);
}

View File

@ -0,0 +1,20 @@
###############################################################################
# Gather all flags.
#
CFLAGS+=-DPOSIXLY_CORRECT -Wall -g
TARGET=cpulimit-ng
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
SOURCES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o, $(SOURCES))
$(TARGET) : $(OBJS)
$(CC) `for X in $(OBJS) ; do echo "$$X"; done` -o $(TARGET) $(LIBS) $(LDFLAGS)
all: $(TARGET)
clean:
rm -f *.o $(TARGET)

View File

@ -0,0 +1,76 @@
##############################################
# OpenWrt Makefile for cpulimit-ng program
#
#
# Most of the variables used here are defined in
# the include directives below. We just need to
# specify a basic description of the package,
# where to build our program, where to find
# the source files, and where to install the
# compiled program on the router.
#
# Be very careful of spacing in this file.
# Indents should be tabs, not spaces, and
# there should be no trailing whitespace in
# lines that are not commented.
#
##############################################
include $(TOPDIR)/rules.mk
# Name and release number of this package
PKG_NAME:=cpulimit-ng
PKG_VERSION:=1.2
PKG_RELEASE:=1
# This specifies the directory where we're going to build the program.
# The root build directory, $(BUILD_DIR), is by default the build_mipsel
# directory in your OpenWrt SDK directory
PKG_BUILD_DIR:=$(BUILD_DIR)/$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
# Specify package information for this program.
# The variables defined here should be self explanatory.
define Package/cpulimit-ng
SECTION:=utils
CATEGORY:=Utilities
TITLE:=CPU Usage Limiter for Linux
description:=\
cpulimit-ng is a simple program which attempts to \\\
limit the cpu usage of a process (expressed in \\\
percentage, not in cpu time).
endef
# Specify what needs to be done to prepare for building the package.
# In our case, we need to copy the source files to the build directory.
# This is NOT the default. The default uses the PKG_SOURCE_URL and the
# PKG_SOURCE which is not defined here to download the source from the web.
# In order to just build a simple program that we have just written, it is
# much easier to do it this way.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
# We do not need to define Build/Configure or Build/Compile directives
# The defaults are appropriate for compiling a simple program such as this one
# Specify where and how to install the program. Since we only have one file,
# the cpulimit-ng executable, install it by copying it to the /bin directory on
# the router. The $(1) variable represents the root directory on the router running
# OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install
# directory if it does not already exist. Likewise $(INSTALL_BIN) contains the
# command to copy the binary file from its current location (in our case the build
# directory) to the install directory.
define Package/cpulimit-ng/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/cpulimit-ng $(1)/bin/
endef
# This line executes the necessary commands to compile our program.
# The above define directives specify all the information needed, but this
# line calls BuildPackage which in turn actually uses this information to
# build a package.
$(eval $(call BuildPackage,cpulimit-ng))

View File

@ -0,0 +1,94 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PROCUTILS_H
#define __PROCUTILS_H
#include <sys/types.h>
#include <dirent.h>
#include "list.h"
#include "process.h"
#define PIDHASH_SZ 1024
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
// a hierarchy of processes
struct process_family {
//the (god)father of the process family
pid_t father;
//process list (father process is the first element)
//elements are struct process
struct list members;
//non-members list
//hashtable with all the processes (array of struct list of struct process)
struct list *proctable[PIDHASH_SZ];
//total process count
int count;
};
//TODO: use this object in proctable and delete member in struct process
struct table_item {
struct process *proc;
//1 if the process is a member of the family
int member;
};
// object to enumerate running processes
struct process_iterator {
#ifdef __linux__
DIR *dip;
struct dirent *dit;
#elif defined __APPLE__
struct kinfo_proc *procList;
int count;
int c;
#elif defined __hpux
int count;
#endif
struct process *current;
};
// searches for all the processes derived from father and stores them
// in the process family struct
int create_process_family(struct process_family *f, pid_t father);
// checks if there are new processes born in the specified family
// if any they are added to the members list
// the number of new born processes is returned
int update_process_family(struct process_family *f);
// removes a process from the family by its pid
void remove_process_from_family(struct process_family *f, pid_t pid);
// free the heap memory used by a process family
void cleanup_process_family(struct process_family *f);
// searches a process given the name of the executable file, or its absolute path
// returns the pid, or 0 if it's not found
int look_for_process_by_name(const char *process_name);
// searches a process given its pid
// returns the pid, or 0 if it's not found
int look_for_process_by_pid(pid_t pid);
#endif

View File

@ -0,0 +1,2 @@
based on cpulimit@sf svn version revision 41
Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>

View File

@ -0,0 +1,88 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PROCESS_H
#define __PROCESS_H
#include <sys/time.h>
#include <unistd.h>
#include <limits.h>
//USER_HZ detection, from openssl code
#ifndef HZ
# if defined(_SC_CLK_TCK) \
&& (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000)
# define HZ ((double)sysconf(_SC_CLK_TCK))
# else
# ifndef CLK_TCK
# ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
# define HZ 100.0
# else /* _BSD_CLK_TCK_ */
# define HZ ((double)_BSD_CLK_TCK_)
# endif
# else /* CLK_TCK */
# define HZ ((double)CLK_TCK)
# endif
# endif
#endif
// process descriptor
struct process {
//pid of the process
pid_t pid;
//pid of the process
pid_t ppid;
//start time
int starttime;
//is member of the family?
int member; //TODO: delete this field
//total number of jiffies used by the process at time last_sample
int last_jiffies;
//timestamp when last_jiffies and cpu_usage was calculated
struct timeval last_sample;
//actual cpu usage estimation (value in range 0-1)
double cpu_usage;
//1 if the process is zombie
int is_zombie;
//absolute path of the executable file
char command[PATH_MAX+1];
//system-dependent members
//TODO: delete these members for the sake of portability?
#ifdef __linux__
//preallocate buffers for performance
//name of /proc/PID/stat file
char stat_file[20];
//read buffer for /proc filesystem
char buffer[1024];
#endif
};
int get_proc_info(struct process *p, pid_t pid);
int process_init(struct process *proc, pid_t pid);
int process_monitor(struct process *proc);
int process_close(struct process *proc);
#endif

View File

@ -0,0 +1,283 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2012, by: Gang Liu <gangban.lau@gmail.com>
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//TODO: add documentation to public functions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <time.h>
#include <sys/utsname.h>
#include "process.h"
#ifdef __APPLE__
#include <sys/sysctl.h>
#include <errno.h>
#endif
#ifdef __linux__
int get_proc_info(struct process *p, pid_t pid) {
/* static char statfile[20];
static char buffer[64];
int ret;
sprintf(statfile, "/proc/%d/stat", pid);
FILE *fd = fopen(statfile, "r");
if (fd==NULL) return -1;
fgets(buffer, sizeof(buffer), fd);
fclose(fd);
char state;
int n = sscanf(buffer, "%d %s %c %d %d %d %d %d "
"%lu %lu %lu %lu %lu %lu %lu "
"%ld %ld %ld %ld %ld %ld "
"%lu ",
&p->pid,
&p->command,
&state,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
&utime,&stime,&cutime,&cstime,
NULL,NULL,NULL,NULL,
&starttime,
);*/
return 0;
}
#elif defined __APPLE__
int get_proc_info(struct process *p, pid_t pid) {
int err;
struct kinfo_proc *result = NULL;
size_t length;
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
/* We start by calling sysctl with result == NULL and length == 0.
That will succeed, and set length to the appropriate length.
We then allocate a buffer of that size and call sysctl again
with that buffer.
*/
length = 0;
err = sysctl(mib, 4, NULL, &length, NULL, 0);
if (err == -1) {
err = errno;
}
if (err == 0) {
result = malloc(length);
err = sysctl(mib, 4, result, &length, NULL, 0);
if (err == -1)
err = errno;
if (err == ENOMEM) {
free(result); /* clean up */
result = NULL;
}
}
p->pid = result->kp_proc.p_pid;
p->ppid = result->kp_eproc.e_ppid;
p->starttime = result->kp_proc.p_starttime.tv_sec;
p->last_jiffies = result->kp_proc.p_cpticks;
//p_pctcpu
return 0;
}
#endif
#ifdef __linux__
// TODO man 5 proc, scanf, see above get_proc_info
static char * get_proc_stat_field(const char * statfile, int idx)
{
char buffer[1024];
FILE *fd = fopen(statfile, "r");
if (fd==NULL)
{
perror("open process stat file failed");
return NULL;
}
if (fgets(buffer, sizeof(buffer), fd) == NULL)
{
perror("read process stat file failed");
fclose(fd);
return NULL;
}
fclose(fd);
char *p = buffer;
int slen = strlen(buffer);
int sp = idx;
while (sp-- && p != NULL && (p+1) < (buffer + slen))
p = strchr(p+1, ' ');
if (p==NULL || (p+1) >= (buffer + slen))
{
printf("process stat file format error");
return NULL;
}
char *q = strchr(p+1, ' ');
if (q==NULL)
{
printf("process stat file format error");
return NULL;
}
*q = '\0';
char *item = (char *)malloc(strlen(p+1) + 1);
if (item != NULL)
{
snprintf(item, strlen(p+1) + 1, "%s", p+1);
}
return item;
}
#endif
// returns the start time of a process (used with pid to identify a process)
static unsigned long long get_starttime(pid_t pid)
{
#ifdef __linux__
char file[20];
snprintf(file, sizeof(file), "/proc/%d/stat", pid);
//start time of the process
char *tbuf = get_proc_stat_field(file, 21);
if (tbuf == NULL)
return -1;
unsigned long long starttime = 0;
sscanf(tbuf, "%llu", &starttime);
free(tbuf);
return starttime;
#elif defined __APPLE__
struct process proc;
get_proc_info(&proc, pid);
return proc.starttime;
#endif
}
static int get_jiffies(struct process *proc) {
#ifdef __linux__
//user mode jiffies
char *tbuf = get_proc_stat_field(proc->stat_file, 13);
if (tbuf==NULL)
return -1;
unsigned long utime = 0;
sscanf(tbuf, "%lu", &utime);
free(tbuf);
//kernel mode jiffies
tbuf = get_proc_stat_field(proc->stat_file, 14);
if (tbuf==NULL)
return -1;
unsigned long stime = 0;
sscanf(tbuf, "%lu", &stime);
free(tbuf);
return utime+stime;
#elif defined __APPLE__
struct process proc2;
get_proc_info(&proc2, proc->pid);
return proc2.last_jiffies;
#endif
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2)
{
return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec);
}
/*static int*/ int process_update(struct process *proc) {
//TODO: get any process statistic here
//check that starttime is not changed(?), update jiffies, parent, zombie status
return 0;
}
int process_init(struct process *proc, int pid)
{
//general members
proc->pid = pid;
proc->starttime = get_starttime(pid);
if (proc->starttime == -1)
return -1;
//printf("process starttime %d\n", proc->starttime);
proc->cpu_usage = 0;
memset(&(proc->last_sample), 0, sizeof(struct timeval));
proc->last_jiffies = -1;
proc->is_zombie = 0;
//system dependent members
#ifdef __linux__
//TODO: delete these members for the sake of portability?
//test /proc file descriptor for reading
snprintf(proc->stat_file, sizeof(proc->stat_file), "/proc/%d/stat", pid);
// FILE *fd = fopen(proc->stat_file, "r");
// if (fd == NULL) return 1;
// fclose(fd);
#endif
return 0;
}
//parameter in range 0-1
#define ALFA 0.08
int process_monitor(struct process *proc)
{
int j = get_jiffies(proc);
if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead)
struct timeval now;
gettimeofday(&now, NULL);
if (proc->last_jiffies==-1) {
//store current time
proc->last_sample.tv_sec = now.tv_sec;
proc->last_sample.tv_usec = now.tv_usec;
//store current jiffies
proc->last_jiffies = j;
//it's the first sample, cannot figure out the cpu usage
proc->cpu_usage = -1;
return 0;
}
//time from previous sample (in ns)
long dt = timediff(&now, &(proc->last_sample));
//how many jiffies in dt?
double max_jiffies = dt * HZ / 1000000.0;
double sample = (j - proc->last_jiffies) / max_jiffies;
if (proc->cpu_usage == -1) {
//initialization
proc->cpu_usage = sample;
}
else {
//usage adjustment
proc->cpu_usage = (1-ALFA) * proc->cpu_usage + ALFA * sample;
}
//store current time
proc->last_sample.tv_sec = now.tv_sec;
proc->last_sample.tv_usec = now.tv_usec;
//store current jiffies
proc->last_jiffies = j;
return 0;
}
int process_close(struct process *proc)
{
if (kill(proc->pid,SIGCONT)!=0) {
fprintf(stderr,"Process %d is already dead!\n", proc->pid);
}
proc->pid = 0;
return 0;
}

View File

@ -0,0 +1,143 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*
* Dynamic list interface
*
*/
#ifndef __LIST__
#define __LIST__
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
struct list_node {
//pointer to the content of the node
void *data;
//pointer to previous node
struct list_node *previous;
//pointer to next node
struct list_node *next;
};
struct list {
//first node
struct list_node *first;
//last node
struct list_node *last;
//size of the search key in bytes
int keysize;
//element count
int count;
};
/*
* Initialize a list, with a specified key size
*/
void init_list(struct list *l,int keysize);
/*
* Add a new element at the end of the list
* return the pointer to the new node
*/
struct list_node *add_elem(struct list *l,void *elem);
/*
* Delete a node
*/
void delete_node(struct list *l,struct list_node *node);
/*
* Delete a node from the list, even the content pointed by it
* Use only when the content is a dynamically allocated pointer
*/
void destroy_node(struct list *l,struct list_node *node);
/*
* Check whether a list is empty or not
*/
int is_empty_list(struct list *l);
/*
* Return the element count of the list
*/
int get_list_count(struct list *l);
/*
* Return the first element (content of the node) from the list
*/
void *first_elem(struct list *l);
/*
* Return the first node from the list
*/
struct list_node *first_node(struct list *l);
/*
* Return the last element (content of the node) from the list
*/
void *last_elem(struct list *l);
/*
* Return the last node from the list
*/
struct list_node *last_node(struct list *l);
/*
* Search an element of the list by content
* the comparison is done from the specified offset and for a specified length
* if offset=0, the comparison starts from the address pointed by data
* if length=0, default keysize is used for length
* if the element is found, return the node address
* else return NULL
*/
struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length);
/*
* The same of xlocate_node(), but return the content of the node
*/
void *xlocate_elem(struct list *l,void *elem,int offset,int length);
/*
* The same of calling xlocate_node() with offset=0 and length=0
*/
struct list_node *locate_node(struct list *l,void *elem);
/*
* The same of locate_node, but return the content of the node
*/
void *locate_elem(struct list *l,void *elem);
/*
* Delete all the elements in the list
*/
void flush_list(struct list *l);
/*
* Delete every element in the list, and free the memory pointed by all the node data
*/
void destroy_list(struct list *l);
#endif

View File

@ -0,0 +1,544 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2012, by: Gang Liu <gangban.lau@gmail.com>
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "procutils.h"
#ifdef __APPLE__
#include <sys/sysctl.h>
#include <errno.h>
#endif
/* PROCESS STATISTICS FUNCTIONS */
//deprecated
// returns pid of the parent process
static pid_t getppid_of(pid_t pid)
{
#ifdef __linux__
char file[20];
char buffer[1024];
snprintf(file, sizeof(file), "/proc/%d/stat", pid);
FILE *fd = fopen(file, "r");
if (fd==NULL) return -1;
if (fgets(buffer, sizeof(buffer), fd)==NULL)
{
fclose(fd);
return -1;
}
fclose(fd);
char *p = buffer;
p = memchr(p+1,')', sizeof(buffer) - (p-buffer));
int sp = 2;
while (sp--)
p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
//pid of the parent process
pid_t ppid = atoi(p+1);
return ppid;
#elif defined __APPLE__
struct process p;
get_proc_info(&p, pid);
return p.ppid;
#endif
}
#ifdef __linux__
// detects whether a process is a kernel thread or not
static int is_kernel_thread(pid_t pid)
{
char statfile[20];
char buffer[64];
int ret;
snprintf(statfile, sizeof(statfile), "/proc/%d/statm", pid);
FILE *fd = fopen(statfile, "r");
if (fd==NULL)
{
perror("open process statm file failed");
return -1;
}
if (fgets(buffer, sizeof(buffer), fd)==NULL)
{
perror("read process statm file failed");
fclose(fd);
return -1;
}
ret = strncmp(buffer,"0 0 0",3)==0;
fclose(fd);
return ret;
}
#endif
//deprecated
// returns 1 if pid is an existing pid, 0 otherwise
static int process_exists(pid_t pid) {
#ifdef __linux__
char procdir[20];
struct stat procstat;
snprintf(procdir, sizeof(procdir), "/proc/%d", pid);
return stat(procdir, &procstat)==0;
#elif defined __APPLE__
struct process p;
return get_proc_info(&p, pid)==0;
#endif
}
/* PID HASH FUNCTIONS */
static int hash_process(struct process_family *f, struct process *p)
{
int ret;
struct list **l = &(f->proctable[pid_hashfn(p->pid)]);
if (*l == NULL) {
//there is no process in this hashtable item
//allocate the list
*l = (struct list*)malloc(sizeof(struct list));
init_list(*l, 4);
add_elem(*l, p);
ret = 0;
f->count++;
}
else {
//list already exists
struct process *tmp = (struct process*)locate_elem(*l, p);
if (tmp != NULL) {
//update process info
memcpy(tmp, p, sizeof(struct process));
free(p);
p = NULL;
ret = 1;
}
else {
//add new process
add_elem(*l, p);
ret = 0;
f->count++;
}
}
return ret;
}
static void unhash_process(struct process_family *f, pid_t pid) {
//remove process from hashtable
struct list **l = &(f->proctable[pid_hashfn(pid)]);
if (*l == NULL)
return; //nothing done
struct list_node *node = locate_node(*l, &pid);
if (node != NULL)
destroy_node(*l, node);
f->count--;
}
static struct process *seek_process(struct process_family *f, pid_t pid)
{
struct list **l = &(f->proctable[pid_hashfn(pid)]);
return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL;
}
/* PROCESS ITERATOR STUFF */
// creates an object that browse all running processes
int init_process_iterator(struct process_iterator *i) {
#ifdef __linux__
//open a directory stream to /proc directory
if ((i->dip = opendir("/proc")) == NULL) {
perror("opendir");
return -1;
}
#elif defined __APPLE__
int err;
struct kinfo_proc *result = NULL;
size_t length;
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
/* We start by calling sysctl with result == NULL and length == 0.
That will succeed, and set length to the appropriate length.
We then allocate a buffer of that size and call sysctl again
with that buffer.
*/
length = 0;
err = sysctl(mib, 4, NULL, &length, NULL, 0);
if (err == -1) {
err = errno;
}
if (err == 0) {
result = malloc(length);
err = sysctl(mib, 4, result, &length, NULL, 0);
if (err == -1)
err = errno;
if (err == ENOMEM) {
free(result); /* clean up */
result = NULL;
}
}
i->procList = result;
i->count = err == 0 ? length / sizeof *result : 0;
i->c = 0;
#endif
i->current = (struct process*)malloc(sizeof(struct process));
if (i->current == NULL)
{
perror("malloc falied");
closedir(i->dip);
return -1;
}
memset(i->current, 0, sizeof(struct process));
return 0;
}
// reads the next user process from /process
// automatic closing if the end of the list is reached
int read_next_process(struct process_iterator *i) {
#ifdef __linux__
pid_t pid = 0;
//TODO read this to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85
//read in from /proc and seek for process dirs
while ((i->dit = readdir(i->dip)) != NULL) {
if(strtok(i->dit->d_name, "0123456789") != NULL)
continue;
pid = atoi(i->dit->d_name);
if (is_kernel_thread(pid))
{
pid = 0;
continue;
}
//return the first found process
break;
}
if (pid == 0) {
//no more processes
closedir(i->dip);
i->dip = NULL;
free(i->current);
i->current = NULL;
return -1;
}
//read the executable link
char statfile[20];
snprintf(statfile, sizeof(statfile), "/proc/%d/cmdline",pid);
FILE *fd = fopen(statfile, "r");
if (fd == NULL)
{
perror("open process cmdline file failed");
return -1;
}
char buffer[1024];
if (fgets(buffer, sizeof(buffer), fd)==NULL)
{
perror("read process cmdline file falied");
fclose(fd);
return -2;
}
fclose(fd);
sscanf(buffer, "%s", (char*)&i->current->command);
i->current->pid = pid;
#elif defined __APPLE__
if (i->c >= i->count) {
//no more processes
free(i->procList);
i->procList = NULL;
free(i->current);
i->current = NULL;
return -1;
}
i->current->pid = i->procList[i->c].kp_proc.p_pid;
strncpy(i->current->command, i->procList[i->c].kp_proc.p_comm, MAXCOMLEN);
printf("%d %d %s\n", i->c, i->current->pid, i->current->command);//i->procList[i->c].kp_proc.p_comm);
//printf("%d %d %s\n", i->c, i->current->pid, i->proc[i->c].kp_proc.p_comm);
i->c++;
#endif
return 0;
}
/* PUBLIC FUNCTIONS */
// search for all the processes derived from father and stores them
// in the process family struct
int create_process_family(struct process_family *f, pid_t father)
{
//process iterator
struct process_iterator iter;
if (init_process_iterator(&iter) == -1)
return -1;
//process list initialization (4 bytes key)
init_list(&(f->members), 4);
//hashtable initialization
memset(&(f->proctable), 0, sizeof(f->proctable));
f->count = 0;
f->father = father;
int pid = 0;
while (read_next_process(&iter)==0) {
pid = iter.current->pid;
//check if process belongs to the family
int ppid = pid;
//TODO: optimize adding also these parents, and continue if process is already present
while(ppid!=1 && ppid!=father) {
//pid_t f = getppid(ppid);
ppid = getppid_of(ppid);
//printf("p1 %d, p2 %d\n", f, ppid);
}
//allocate process descriptor
struct process *p = (struct process*)malloc(sizeof(struct process));
//init process
if (process_init(p, pid) == -1)
{
printf("init process failed\n");
free(p);
continue;
}
if (ppid==1) {
//the init process
p->member = 0;
}
else if (pid != getpid()) {
//add to members (but exclude the current cpulimit process!)
p->member = 1;
add_elem(&(f->members), p);
}
//add to hashtable
hash_process(f, p);
}
if (iter.dip != NULL)
closedir(iter.dip);
if (iter.current != NULL)
free(iter.current);
return 0;
}
// checks if there are new processes born in the specified family
// if any they are added to the members list
// the number of new born processes is returned
int update_process_family(struct process_family *f)
{
//process iterator
struct process_iterator iter;
if (init_process_iterator(&iter) == -1)
return -1;
int ret = 0;
int pid = 0;
while (read_next_process(&iter)==0) {
pid = iter.current->pid;
struct process *newp = seek_process(f, pid);
if (newp != NULL) continue; //already known //TODO: what if newp is a new process with the same PID??
//the process is new, check if it belongs to the family
int ppid = getppid_of(pid);
//search the youngest known ancestor of the process
struct process *ancestor = NULL;
while((ancestor=seek_process(f, ppid))==NULL) {
ppid = getppid_of(ppid);
}
if (ancestor == NULL) {
//this should never happen! if does, find and correct the bug
fprintf(stderr, "Fatal bug! Process %d is without parent\n", pid);
exit(1);
}
//allocate and insert the process
struct process *p = (struct process*)malloc(sizeof(struct process));
//init process
if (process_init(p, pid) == -1)
{
printf("init process failed\n");
free(p);
continue;
}
if (ancestor->member) {
//add to members
p->member = 1;
add_elem(&(f->members), p);
ret++;
}
else {
//not a member
p->member = 0;
}
//add to hashtable
hash_process(f, p);
}
if (iter.dip != NULL)
closedir(iter.dip);
if (iter.current != NULL)
free(iter.current);
// remove non-member process if exited
struct list pid_list;
init_list(&pid_list, 0);
int i;
struct list_node *node = NULL;
int size = sizeof(f->proctable) / sizeof(struct process*);
for (i=0; i<size; i++) {
if (f->proctable[i] != NULL) {
for (node=f->proctable[i]->first; node!=NULL; node=node->next) {
struct process *p = (struct process*)(node->data);
if (!p->member && !process_exists(p->pid))
add_elem(&pid_list, &p->pid);
}
}
}
for (node=pid_list.first; node!=NULL; node=node->next) {
pid_t * p = (pid_t *)(node->data);
remove_process_from_family(f, *p);
}
flush_list(&pid_list);
return ret;
}
// removes a process from the family by its pid
void remove_process_from_family(struct process_family *f, pid_t pid)
{
struct list_node *node = locate_node(&(f->members), &pid);
if (node != NULL) {
// struct process *p = (struct process*)(node->data);
// free(p->history);
// p->history = NULL;
delete_node(&(f->members), node);
}
unhash_process(f, pid);
}
// free the heap memory used by a process family
void cleanup_process_family(struct process_family *f)
{
int i;
int size = sizeof(f->proctable) / sizeof(struct process*);
for (i=0; i<size; i++) {
if (f->proctable[i] != NULL) {
//free() history for each process
struct list_node *node = NULL;
for (node=f->proctable[i]->first; node!=NULL; node=node->next) {
// struct process *p = (struct process*)(node->data);
// free(p->history);
// p->history = NULL;
}
destroy_list(f->proctable[i]);
free(f->proctable[i]);
f->proctable[i] = NULL;
}
}
flush_list(&(f->members));
f->count = 0;
f->father = 0;
}
// look for a process by pid
// search_pid : pid of the wanted process
// return: pid of the found process, if it is found
// 0, if it's not found
// negative pid, if it is found but it's not possible to control it
int look_for_process_by_pid(pid_t pid)
{
if (process_exists(pid))
return (kill(pid,0)==0) ? pid : -pid;
return 0;
}
// look for a process with a given name
// process: the name of the wanted process. it can be an absolute path name to the executable file
// or just the file name
// return: pid of the found process, if it is found
// 0, if it's not found
// negative pid, if it is found but it's not possible to control it
int look_for_process_by_name(const char *process_name)
{
//whether the variable process_name is the absolute path or not
int is_absolute_path = process_name[0] == '/';
//flag indicating if the a process with given name was found
int found = 0;
//process iterator
struct process_iterator iter;
if (init_process_iterator(&iter) == -1)
return -1;
pid_t pid = 0;
printf("name\n");
while (read_next_process(&iter)==0) {
pid = iter.current->pid;
int size = strlen(iter.current->command);
found = 0;
if (is_absolute_path && strncmp(iter.current->command, process_name, size)==0 && size==strlen(process_name)) {
//process found
found = 1;
}
else {
//process found
if (strncmp(iter.current->command + size - strlen(process_name), process_name, strlen(process_name))==0) {
found = 1;
}
}
if (found==1) {
if (kill(pid,SIGCONT)==0) {
//process is ok!
break;
}
else {
//we don't have permission to send signal to that process
//so, don't exit from the loop and look for another one with the same name
found = -1;
}
}
}
if (iter.dip != NULL)
closedir(iter.dip);
if (iter.current != NULL)
free(iter.current);
if (found == 1) {
//ok, the process was found
return pid;
}
else if (found == 0) {
//no process found
return 0;
}
else if (found == -1) {
//the process was found, but we haven't permission to control it
return -pid;
}
//this MUST NOT happen
return 0;
}

View File

@ -0,0 +1,47 @@
Cpulimit 1.2
=======
About
=======
Cpulimit is a program that attempts to limit the cpu usage of a process (expressed in percentage, not in cpu time). It is useful to control batch jobs, when you don't want they eat too much cpu. The goal it to not let a proces run for more than a specified time ratio. It does not act on the nice value or other scheduling priority stuff, but on the real cpu usage. Also, it is able to adapt itself to the overall system load, dynamically and quickly.
The control of the used cpu amount is done sending properly SIGSTOP and SIGCONT POSIX signals to processes.
All the children processes and threads of the specified process will share the same percent of cpu.
Developed by Angelo Marletta.
Please send your feedback, bug reports, feature requests or just thanks :) to marlonx80@hotmail.com.
=====================
Changelog since 1.1
=====================
- reorganization of the code, splitted in more source files
- cpu count detection, i.e. if you have 4 cpu, it is possible to limit up to 400%
- in order to avoid deadlocks, cpulimit now prevents to limit itself
- option --path eliminated, use --exe instead both for absolute path and file name
- call setpriority() just once
- no more segmentation fault when processes exit
- no more memory corruption when processes exit
- cpulimit exits if --lazy option is specified and the process terminates
- target process can be created on-fly given command line
- light and scalable algorithm for subprocesses detection and limitation
- mac os support
- minor enhancements and bugfixes
============================
Get the latest source code
============================
You can checkout the latest code from sourceforge Subversion repository, running:
svn checkout https://cpulimit.svn.sourceforge.net/svnroot/cpulimit cpulimit
Of course this is the development version, so you may experience bugs (please signal them and your soul will be saved!)
==============
Installation
==============
Run 'make' and place the executable file 'cpulimit' wherever you want.
Type 'cpulimit --help' to get documentation on available options.

Binary file not shown.

View File

@ -0,0 +1,76 @@
##############################################
# OpenWrt Makefile for cpulimit-ng program
#
#
# Most of the variables used here are defined in
# the include directives below. We just need to
# specify a basic description of the package,
# where to build our program, where to find
# the source files, and where to install the
# compiled program on the router.
#
# Be very careful of spacing in this file.
# Indents should be tabs, not spaces, and
# there should be no trailing whitespace in
# lines that are not commented.
#
##############################################
include $(TOPDIR)/rules.mk
# Name and release number of this package
PKG_NAME:=cpulimit-ng
PKG_VERSION:=1.2
PKG_RELEASE:=1
# This specifies the directory where we're going to build the program.
# The root build directory, $(BUILD_DIR), is by default the build_mipsel
# directory in your OpenWrt SDK directory
PKG_BUILD_DIR:=$(BUILD_DIR)/$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
# Specify package information for this program.
# The variables defined here should be self explanatory.
define Package/cpulimit-ng
SECTION:=utils
CATEGORY:=Utilities
TITLE:=CPU Usage Limiter for Linux
description:=\
cpulimit-ng is a simple program which attempts to \\\
limit the cpu usage of a process (expressed in \\\
percentage, not in cpu time).
endef
# Specify what needs to be done to prepare for building the package.
# In our case, we need to copy the source files to the build directory.
# This is NOT the default. The default uses the PKG_SOURCE_URL and the
# PKG_SOURCE which is not defined here to download the source from the web.
# In order to just build a simple program that we have just written, it is
# much easier to do it this way.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
# We do not need to define Build/Configure or Build/Compile directives
# The defaults are appropriate for compiling a simple program such as this one
# Specify where and how to install the program. Since we only have one file,
# the cpulimit-ng executable, install it by copying it to the /bin directory on
# the router. The $(1) variable represents the root directory on the router running
# OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install
# directory if it does not already exist. Likewise $(INSTALL_BIN) contains the
# command to copy the binary file from its current location (in our case the build
# directory) to the install directory.
define Package/cpulimit-ng/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/cpulimit-ng $(1)/bin/
endef
# This line executes the necessary commands to compile our program.
# The above define directives specify all the information needed, but this
# line calls BuildPackage which in turn actually uses this information to
# build a package.
$(eval $(call BuildPackage,cpulimit-ng))

View File

@ -0,0 +1,2 @@
based on cpulimit@sf svn version revision 41
Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>

View File

@ -0,0 +1,20 @@
###############################################################################
# Gather all flags.
#
CFLAGS+=-DPOSIXLY_CORRECT -Wall -g
TARGET=cpulimit-ng
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
SOURCES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o, $(SOURCES))
$(TARGET) : $(OBJS)
$(CC) `for X in $(OBJS) ; do echo "$$X"; done` -o $(TARGET) $(LIBS) $(LDFLAGS)
all: $(TARGET)
clean:
rm -f *.o $(TARGET)

View File

@ -0,0 +1,47 @@
Cpulimit 1.2
=======
About
=======
Cpulimit is a program that attempts to limit the cpu usage of a process (expressed in percentage, not in cpu time). It is useful to control batch jobs, when you don't want they eat too much cpu. The goal it to not let a proces run for more than a specified time ratio. It does not act on the nice value or other scheduling priority stuff, but on the real cpu usage. Also, it is able to adapt itself to the overall system load, dynamically and quickly.
The control of the used cpu amount is done sending properly SIGSTOP and SIGCONT POSIX signals to processes.
All the children processes and threads of the specified process will share the same percent of cpu.
Developed by Angelo Marletta.
Please send your feedback, bug reports, feature requests or just thanks :) to marlonx80@hotmail.com.
=====================
Changelog since 1.1
=====================
- reorganization of the code, splitted in more source files
- cpu count detection, i.e. if you have 4 cpu, it is possible to limit up to 400%
- in order to avoid deadlocks, cpulimit now prevents to limit itself
- option --path eliminated, use --exe instead both for absolute path and file name
- call setpriority() just once
- no more segmentation fault when processes exit
- no more memory corruption when processes exit
- cpulimit exits if --lazy option is specified and the process terminates
- target process can be created on-fly given command line
- light and scalable algorithm for subprocesses detection and limitation
- mac os support
- minor enhancements and bugfixes
============================
Get the latest source code
============================
You can checkout the latest code from sourceforge Subversion repository, running:
svn checkout https://cpulimit.svn.sourceforge.net/svnroot/cpulimit cpulimit
Of course this is the development version, so you may experience bugs (please signal them and your soul will be saved!)
==============
Installation
==============
Run 'make' and place the executable file 'cpulimit' wherever you want.
Type 'cpulimit --help' to get documentation on available options.

View File

@ -0,0 +1,601 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2012, by: Gang Liu <gangban.lau@gmail.com>
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*
* This is a simple program to limit the cpu usage of a process
* If you modify this code, send me a copy please
*
* Date: 30/8/2008
* Version: 1.2 beta
* Get the latest version at: http://cpulimit.sourceforge.net
*
* Changelog from 1.1:
* - reorganization of the code, splitted in more source files
* - cpu count detection, i.e. if you have 4 cpu, it is possible to limit up to 400%
* - in order to avoid deadlocks, cpulimit now prevents to limit itself
* - option --path eliminated, use --exe instead both for absolute path and file name
* - call setpriority() just once in limit_process()
* - no more segmentation fault when processes exit
* - no more memory corruption when processes exit
* - cpulimit exits if --lazy option is specified and the process terminates
* - target process can be created on-fly given command line
* - light and scalable algorithm for subprocesses detection and limitation
* - mac os support
* - minor enhancements and bugfixes
*
*/
#include <getopt.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include "process.h"
#include "procutils.h"
#include "list.h"
//some useful macro
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
//control time slot in microseconds
//each slot is splitted in a working slice and a sleeping slice
//TODO: make it adaptive, based on the actual system load
#define TIME_SLOT 100000
#define MAX_PRIORITY -10
/* GLOBAL VARIABLES */
//the "family"
struct process_family pf;
//pid of cpulimit
pid_t cpulimit_pid;
//name of this program (maybe cpulimit...)
char *program_name;
//number of cpu
int NCPU;
/* CONFIGURATION VARIABLES */
//verbose mode
int verbose = 0;
//lazy mode (exits if there is no process)
int lazy = 0;
static void *memrchr(const void *s, int c, size_t n)
{
const unsigned char *start = (const unsigned char*)s;
const unsigned char *end = (const unsigned char*)s;
end+=n-1;
while(end>=start) {
if(*end==c)
return (void *)end;
else
end--;
}
return NULL;
}
//SIGINT and SIGTERM signal handler
static void quit(int sig)
{
//let all the processes continue if stopped
struct list_node *node = NULL;
for (node=pf.members.first; node!= NULL; node=node->next) {
struct process *p = (struct process*)(node->data);
kill(p->pid, SIGCONT);
process_close(p);
}
//free all the memory
cleanup_process_family(&pf);
//fix ^C little problem
printf("\r");
fflush(stdout);
exit(0);
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2)
{
return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec);
}
static void print_usage(FILE *stream, int exit_code)
{
fprintf(stream, "Usage: %s [OPTIONS...] TARGET\n", program_name);
fprintf(stream, " OPTIONS\n");
fprintf(stream, " -l, --limit=N percentage of cpu allowed from 0 to %d (required)\n", 100*NCPU);
fprintf(stream, " -v, --verbose show control statistics\n");
fprintf(stream, " -z, --lazy exit if there is no target process, or if it dies\n");
fprintf(stream, " -i, --ignore-children don't limit children processes\n");
fprintf(stream, " -h, --help display this help and exit\n");
fprintf(stream, " TARGET must be exactly one of these:\n");
fprintf(stream, " -p, --pid=N pid of the process (implies -z)\n");
fprintf(stream, " -e, --exe=FILE name of the executable program file or path name\n");
fprintf(stream, " COMMAND [ARGS] run this command and limit it (implies -z)\n");
fprintf(stream, "\nReport bugs to <marlonx80@hotmail.com>.\n");
exit(exit_code);
}
static void increase_priority() {
//find the best available nice value
errno = 0; // clear errno first
int old_priority = getpriority(PRIO_PROCESS, 0);
if (errno)
{
perror("getpriority failed");
return;
}
int priority = old_priority;
while (priority > MAX_PRIORITY && setpriority(PRIO_PROCESS, 0, priority-1) == 0) {
priority--;
}
if (priority != old_priority) {
if (verbose) printf("Priority changed to %d\n", priority);
}
else {
if (verbose) printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
}
}
/* Get the number of CPUs */
static int get_ncpu() {
int ncpu = -1;
#ifdef _SC_NPROCESSORS_ONLN
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
#elif defined __APPLE__
int mib[2] = {CTL_HW, HW_NCPU};
size_t len = sizeof(ncpu);
sysctl(mib, 2, &ncpu, &len, NULL, 0);
#endif
return ncpu;
}
#ifdef __linux__
#include <sys/vfs.h>
static int check_proc()
{
struct statfs mnt;
if (statfs("/proc", &mnt) < 0)
return 0;
if (mnt.f_type!=0x9fa0)
return 0;
return 1;
}
#endif
void limit_process(pid_t pid, double limit, int ignore_children)
{
//slice of the slot in which the process is allowed to run
struct timespec twork;
//slice of the slot in which the process is stopped
struct timespec tsleep;
//when the last twork has started
struct timeval startwork;
//when the last twork has finished
struct timeval endwork;
//initialization
memset(&twork, 0, sizeof(struct timespec));
memset(&tsleep, 0, sizeof(struct timespec));
memset(&startwork, 0, sizeof(struct timeval));
memset(&endwork, 0, sizeof(struct timeval));
//last working time in microseconds
unsigned long workingtime = 0;
//generic list item
struct list_node *node;
//counter
int c = 0;
//get a better priority
//increase_priority();
//build the family
if (create_process_family(&pf, pid) == -1)
{
printf("create process family failed");
return ;
}
if (ignore_children) {
//delete any process with a different pid than the father
node = pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (proc->pid != pid)
{
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
node = node->next;
}
}
if (!ignore_children && verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.count);
//rate at which we are keeping active the processes (range 0-1)
//1 means that the process are using all the twork slice
double workingrate = -1;
while(1) {
if (!ignore_children && c%10==0) {
//update the process family (checks only for new members)
int new_children = update_process_family(&pf);
if (verbose && new_children) {
printf("%d new children processes detected (", new_children);
int j;
node = pf.members.last;
for (j=0; j<new_children; j++) {
printf("%d", ((struct process*)(node->data))->pid);
if (j<new_children-1) printf(" ");
node = node->previous;
}
printf(")\n");
}
}
if (pf.members.count==0) {
if (verbose) printf("No more processes.\n");
break;
}
//total cpu actual usage (range 0-1)
//1 means that the processes are using 100% cpu
double pcpu = -1;
//estimate how much the controlled processes are using the cpu in the working interval
node = pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (proc->is_zombie) {
//process is zombie, remove it from family
fprintf(stderr,"Process %d is zombie!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
if (process_monitor(proc) != 0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
node = node->next;
if (proc->cpu_usage<0) {
continue;
}
if (pcpu<0) pcpu = 0;
pcpu += proc->cpu_usage;
}
//adjust work and sleep time slices
if (pcpu < 0) {
//it's the 1st cycle, initialize workingrate
pcpu = limit;
workingrate = limit;
twork.tv_nsec = TIME_SLOT*limit*1000;
}
else {
//adjust workingrate
workingrate = MIN(workingrate / pcpu * limit, 1);
twork.tv_nsec = TIME_SLOT*1000*workingrate;
}
tsleep.tv_nsec = TIME_SLOT*1000-twork.tv_nsec;
if (verbose) {
if (c%200==0)
printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
if (c%10==0 && c>0)
printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100);
}
//resume processes
node = pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGCONT)!=0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node = pf.members.first;
continue;
}
node=node->next;
}
//now processes are free to run (same working slice for all)
gettimeofday(&startwork, NULL);
nanosleep(&twork,NULL);
gettimeofday(&endwork, NULL);
workingtime = timediff(&endwork,&startwork);
long delay = workingtime-twork.tv_nsec/1000;
if (c>0 && delay>10000) {
//delay is too much! signal to user?
//fprintf(stderr, "%d %ld us\n", c, delay);
}
if (tsleep.tv_nsec>0) {
//stop only if tsleep>0, instead it's useless
node=pf.members.first;
while (node!=NULL) {
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGSTOP)!=0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
node=pf.members.first;
continue;
}
node=node->next;
}
//now the processes are sleeping
nanosleep(&tsleep,NULL);
}
c++;
}
cleanup_process_family(&pf);
}
int main(int argc, char **argv) {
//argument variables
const char *exe = NULL;
int perclimit = 0;
int exe_ok = 0;
int pid_ok = 0;
int limit_ok = 0;
pid_t pid = 0;
int ignore_children = 0;
//get program name
char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
program_name = p==NULL?argv[0]:(p+1);
//get current pid
cpulimit_pid = getpid();
//get cpu count
NCPU = get_ncpu();
//parse arguments
int next_option;
int option_index = 0;
//A string listing valid short options letters
const char* short_options = "+p:e:l:vzih";
//An array describing valid long options
const struct option long_options[] = {
{ "pid", required_argument, NULL, 'p' },
{ "exe", required_argument, NULL, 'e' },
{ "limit", required_argument, NULL, 'l' },
{ "verbose", no_argument, NULL, 'v' },
{ "lazy", no_argument, NULL, 'z' },
{ "ignore-children", no_argument, NULL, 'i' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
do {
next_option = getopt_long(argc, argv, short_options,long_options, &option_index);
switch(next_option) {
case 'p':
pid = atoi(optarg);
pid_ok = 1;
break;
case 'e':
exe = optarg;
exe_ok = 1;
break;
case 'l':
perclimit = atoi(optarg);
limit_ok = 1;
break;
case 'v':
verbose = 1;
break;
case 'z':
lazy = 1;
break;
case 'i':
ignore_children = 1;
break;
case 'h':
print_usage(stdout, 1);
break;
case '?':
print_usage(stderr, 1);
break;
case -1:
break;
default:
abort();
}
} while(next_option != -1);
if (pid_ok && (pid<=1 || pid>=65536)) {
fprintf(stderr,"Error: Invalid value for argument PID\n");
print_usage(stderr, 1);
exit(1);
}
if (pid!=0) {
lazy = 1;
}
if (!limit_ok) {
fprintf(stderr,"Error: You must specify a cpu limit percentage\n");
print_usage(stderr, 1);
exit(1);
}
double limit = perclimit/100.0;
if (limit<0 || limit >NCPU) {
fprintf(stderr,"Error: limit must be in the range 0-%d00\n", NCPU);
print_usage(stderr, 1);
exit(1);
}
int command_mode = optind<argc;
if (exe_ok + pid_ok + command_mode == 0) {
fprintf(stderr,"Error: You must specify one target process, either by name, pid, or command line\n");
print_usage(stderr, 1);
exit(1);
}
if (exe_ok + pid_ok + command_mode > 1) {
fprintf(stderr,"Error: You must specify exactly one target process, either by name, pid, or command line\n");
print_usage(stderr, 1);
exit(1);
}
//all arguments are ok!
signal(SIGINT, quit);
signal(SIGTERM, quit);
//print the number of available cpu
if (verbose) printf("%d cpu detected\n", NCPU);
#ifdef __linux__
if (!check_proc()) {
fprintf(stderr, "procfs is not mounted!\nAborting\n");
exit(-2);
}
#endif
if (command_mode) {
int i;
//executable file
const char *cmd = argv[optind];
//command line arguments
char **cmd_args = (char**)malloc((argc-optind+1)*sizeof(char*));
if (cmd_args==NULL) exit(2);
for (i=0; i<argc-optind; i++) {
cmd_args[i] = argv[i+optind];
}
cmd_args[i] = NULL;
if (verbose) {
printf("Running command: '%s", cmd);
for (i=1; i<argc-optind; i++) {
printf(" %s", cmd_args[i]);
}
printf("'\n");
}
int child = fork();
if (child < 0) {
exit(EXIT_FAILURE);
}
else if (child > 0) {
//parent code
int limiter = fork();
if (limiter < 0) {
exit(EXIT_FAILURE);
}
else if (limiter > 0) {
//parent
int status_process;
int status_limiter;
waitpid(child, &status_process, 0);
waitpid(limiter, &status_limiter, 0);
if (WIFEXITED(status_process)) {
if (verbose) printf("Process %d terminated with exit status %d\n", child, (int)WEXITSTATUS(status_process));
exit(WEXITSTATUS(status_process));
}
printf("Process %d terminated abnormally\n", child);
exit(status_process);
}
else {
//limiter code
if (verbose) printf("Limiting process %d\n",child);
limit_process(child, limit, ignore_children);
exit(0);
}
}
else {
//target process code
int ret = execvp(cmd, cmd_args);
//if we are here there was an error, show it
perror("Error");
exit(ret);
}
}
while(1) {
//look for the target process..or wait for it
pid_t ret = 0;
if (pid_ok) {
//search by pid
ret = look_for_process_by_pid(pid);
if (ret == 0) {
printf("No process found\n");
}
else if (ret < 0) {
printf("Process found but you aren't allowed to control it\n");
}
}
else {
//search by file or path name
ret = look_for_process_by_name(exe);
if (ret == 0) {
printf("No process found\n");
}
else if (ret < 0) {
printf("Process found but you aren't allowed to control it\n");
}
else {
pid = ret;
}
}
if (ret > 0) {
if (ret == cpulimit_pid) {
printf("Process %d is cpulimit itself! Aborting to avoid deadlock\n", ret);
exit(1);
}
printf("Process %d found\n", pid);
//control
limit_process(pid, limit, ignore_children);
}
if (lazy) break;
sleep(2);
};
exit(0);
}

View File

@ -0,0 +1,154 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*
* Dynamic list implementation
*
*/
#include <stdlib.h>
#include <string.h>
#include "list.h"
#define EMPTYLIST NULL
void init_list(struct list *l,int keysize) {
l->first=l->last=NULL;
l->keysize=keysize;
l->count=0;
}
struct list_node *add_elem(struct list *l,void *elem) {
struct list_node *newnode=(struct list_node*)malloc(sizeof(struct list_node));
newnode->data=elem;
newnode->previous=l->last;
newnode->next=NULL;
if (l->count==0) {
l->first=l->last=newnode;
}
else {
l->last->next=newnode;
l->last=newnode;
}
l->count++;
return newnode;
}
void delete_node(struct list *l,struct list_node *node) {
if (l->count==1) {
l->first=l->last=NULL;
}
else if (node==l->first) {
node->next->previous=NULL;
l->first=node->next;
}
else if (node==l->last) {
node->previous->next=NULL;
l->last=node->previous;
}
else {
node->previous->next=node->next;
node->next->previous=node->previous;
}
l->count--;
free(node);
node = NULL;
}
void destroy_node(struct list *l,struct list_node *node) {
free(node->data);
node->data=NULL;
delete_node(l,node);
}
int is_EMPTYLIST_list(struct list *l) {
return (l->count==0?TRUE:FALSE);
}
int get_list_count(struct list *l) {
return l->count;
}
void *first_elem(struct list *l) {
return l->first->data;
}
struct list_node *first_node(struct list *l) {
return l->first;
}
void *last_elem(struct list *l) {
return l->last->data;
}
struct list_node *last_node(struct list *l) {
return l->last;
}
struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length) {
struct list_node *tmp;
tmp=l->first;
while(tmp!=NULL) {
if(!memcmp((char*)tmp->data+offset,elem,length==0?l->keysize:length)) return (tmp);
tmp=tmp->next;
}
return EMPTYLIST;
}
struct list_node *locate_node(struct list *l,void *elem) {
return(xlocate_node(l,elem,0,0));
}
void *xlocate_elem(struct list *l,void *elem,int offset,int length) {
struct list_node *node=xlocate_node(l,elem,offset,length);
return(node==NULL?NULL:node->data);
}
void *locate_elem(struct list *l,void *elem) {
return(xlocate_elem(l,elem,0,0));
}
void flush_list(struct list *l) {
struct list_node *tmp;
while(l->first!=EMPTYLIST) {
tmp=l->first;
l->first=l->first->next;
free(tmp);
tmp=NULL;
}
l->last=EMPTYLIST;
l->count=0;
}
void destroy_list(struct list *l) {
struct list_node *tmp;
while(l->first!=EMPTYLIST) {
tmp=l->first;
l->first=l->first->next;
free(tmp->data);
tmp->data=NULL;
free(tmp);
tmp=NULL;
}
l->last=EMPTYLIST;
l->count=0;
}

View File

@ -0,0 +1,143 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*
* Dynamic list interface
*
*/
#ifndef __LIST__
#define __LIST__
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
struct list_node {
//pointer to the content of the node
void *data;
//pointer to previous node
struct list_node *previous;
//pointer to next node
struct list_node *next;
};
struct list {
//first node
struct list_node *first;
//last node
struct list_node *last;
//size of the search key in bytes
int keysize;
//element count
int count;
};
/*
* Initialize a list, with a specified key size
*/
void init_list(struct list *l,int keysize);
/*
* Add a new element at the end of the list
* return the pointer to the new node
*/
struct list_node *add_elem(struct list *l,void *elem);
/*
* Delete a node
*/
void delete_node(struct list *l,struct list_node *node);
/*
* Delete a node from the list, even the content pointed by it
* Use only when the content is a dynamically allocated pointer
*/
void destroy_node(struct list *l,struct list_node *node);
/*
* Check whether a list is empty or not
*/
int is_empty_list(struct list *l);
/*
* Return the element count of the list
*/
int get_list_count(struct list *l);
/*
* Return the first element (content of the node) from the list
*/
void *first_elem(struct list *l);
/*
* Return the first node from the list
*/
struct list_node *first_node(struct list *l);
/*
* Return the last element (content of the node) from the list
*/
void *last_elem(struct list *l);
/*
* Return the last node from the list
*/
struct list_node *last_node(struct list *l);
/*
* Search an element of the list by content
* the comparison is done from the specified offset and for a specified length
* if offset=0, the comparison starts from the address pointed by data
* if length=0, default keysize is used for length
* if the element is found, return the node address
* else return NULL
*/
struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length);
/*
* The same of xlocate_node(), but return the content of the node
*/
void *xlocate_elem(struct list *l,void *elem,int offset,int length);
/*
* The same of calling xlocate_node() with offset=0 and length=0
*/
struct list_node *locate_node(struct list *l,void *elem);
/*
* The same of locate_node, but return the content of the node
*/
void *locate_elem(struct list *l,void *elem);
/*
* Delete all the elements in the list
*/
void flush_list(struct list *l);
/*
* Delete every element in the list, and free the memory pointed by all the node data
*/
void destroy_list(struct list *l);
#endif

View File

@ -0,0 +1,283 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2012, by: Gang Liu <gangban.lau@gmail.com>
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//TODO: add documentation to public functions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <time.h>
#include <sys/utsname.h>
#include "process.h"
#ifdef __APPLE__
#include <sys/sysctl.h>
#include <errno.h>
#endif
#ifdef __linux__
int get_proc_info(struct process *p, pid_t pid) {
/* static char statfile[20];
static char buffer[64];
int ret;
sprintf(statfile, "/proc/%d/stat", pid);
FILE *fd = fopen(statfile, "r");
if (fd==NULL) return -1;
fgets(buffer, sizeof(buffer), fd);
fclose(fd);
char state;
int n = sscanf(buffer, "%d %s %c %d %d %d %d %d "
"%lu %lu %lu %lu %lu %lu %lu "
"%ld %ld %ld %ld %ld %ld "
"%lu ",
&p->pid,
&p->command,
&state,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
&utime,&stime,&cutime,&cstime,
NULL,NULL,NULL,NULL,
&starttime,
);*/
return 0;
}
#elif defined __APPLE__
int get_proc_info(struct process *p, pid_t pid) {
int err;
struct kinfo_proc *result = NULL;
size_t length;
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
/* We start by calling sysctl with result == NULL and length == 0.
That will succeed, and set length to the appropriate length.
We then allocate a buffer of that size and call sysctl again
with that buffer.
*/
length = 0;
err = sysctl(mib, 4, NULL, &length, NULL, 0);
if (err == -1) {
err = errno;
}
if (err == 0) {
result = malloc(length);
err = sysctl(mib, 4, result, &length, NULL, 0);
if (err == -1)
err = errno;
if (err == ENOMEM) {
free(result); /* clean up */
result = NULL;
}
}
p->pid = result->kp_proc.p_pid;
p->ppid = result->kp_eproc.e_ppid;
p->starttime = result->kp_proc.p_starttime.tv_sec;
p->last_jiffies = result->kp_proc.p_cpticks;
//p_pctcpu
return 0;
}
#endif
#ifdef __linux__
// TODO man 5 proc, scanf, see above get_proc_info
static char * get_proc_stat_field(const char * statfile, int idx)
{
char buffer[1024];
FILE *fd = fopen(statfile, "r");
if (fd==NULL)
{
perror("open process stat file failed");
return NULL;
}
if (fgets(buffer, sizeof(buffer), fd) == NULL)
{
perror("read process stat file failed");
fclose(fd);
return NULL;
}
fclose(fd);
char *p = buffer;
int slen = strlen(buffer);
int sp = idx;
while (sp-- && p != NULL && (p+1) < (buffer + slen))
p = strchr(p+1, ' ');
if (p==NULL || (p+1) >= (buffer + slen))
{
printf("process stat file format error");
return NULL;
}
char *q = strchr(p+1, ' ');
if (q==NULL)
{
printf("process stat file format error");
return NULL;
}
*q = '\0';
char *item = (char *)malloc(strlen(p+1) + 1);
if (item != NULL)
{
snprintf(item, strlen(p+1) + 1, "%s", p+1);
}
return item;
}
#endif
// returns the start time of a process (used with pid to identify a process)
static unsigned long long get_starttime(pid_t pid)
{
#ifdef __linux__
char file[20];
snprintf(file, sizeof(file), "/proc/%d/stat", pid);
//start time of the process
char *tbuf = get_proc_stat_field(file, 21);
if (tbuf == NULL)
return -1;
unsigned long long starttime = 0;
sscanf(tbuf, "%llu", &starttime);
free(tbuf);
return starttime;
#elif defined __APPLE__
struct process proc;
get_proc_info(&proc, pid);
return proc.starttime;
#endif
}
static int get_jiffies(struct process *proc) {
#ifdef __linux__
//user mode jiffies
char *tbuf = get_proc_stat_field(proc->stat_file, 13);
if (tbuf==NULL)
return -1;
unsigned long utime = 0;
sscanf(tbuf, "%lu", &utime);
free(tbuf);
//kernel mode jiffies
tbuf = get_proc_stat_field(proc->stat_file, 14);
if (tbuf==NULL)
return -1;
unsigned long stime = 0;
sscanf(tbuf, "%lu", &stime);
free(tbuf);
return utime+stime;
#elif defined __APPLE__
struct process proc2;
get_proc_info(&proc2, proc->pid);
return proc2.last_jiffies;
#endif
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2)
{
return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec);
}
/*static int*/ int process_update(struct process *proc) {
//TODO: get any process statistic here
//check that starttime is not changed(?), update jiffies, parent, zombie status
return 0;
}
int process_init(struct process *proc, int pid)
{
//general members
proc->pid = pid;
proc->starttime = get_starttime(pid);
if (proc->starttime == -1)
return -1;
//printf("process starttime %d\n", proc->starttime);
proc->cpu_usage = 0;
memset(&(proc->last_sample), 0, sizeof(struct timeval));
proc->last_jiffies = -1;
proc->is_zombie = 0;
//system dependent members
#ifdef __linux__
//TODO: delete these members for the sake of portability?
//test /proc file descriptor for reading
snprintf(proc->stat_file, sizeof(proc->stat_file), "/proc/%d/stat", pid);
// FILE *fd = fopen(proc->stat_file, "r");
// if (fd == NULL) return 1;
// fclose(fd);
#endif
return 0;
}
//parameter in range 0-1
#define ALFA 0.08
int process_monitor(struct process *proc)
{
int j = get_jiffies(proc);
if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead)
struct timeval now;
gettimeofday(&now, NULL);
if (proc->last_jiffies==-1) {
//store current time
proc->last_sample.tv_sec = now.tv_sec;
proc->last_sample.tv_usec = now.tv_usec;
//store current jiffies
proc->last_jiffies = j;
//it's the first sample, cannot figure out the cpu usage
proc->cpu_usage = -1;
return 0;
}
//time from previous sample (in ns)
long dt = timediff(&now, &(proc->last_sample));
//how many jiffies in dt?
double max_jiffies = dt * HZ / 1000000.0;
double sample = (j - proc->last_jiffies) / max_jiffies;
if (proc->cpu_usage == -1) {
//initialization
proc->cpu_usage = sample;
}
else {
//usage adjustment
proc->cpu_usage = (1-ALFA) * proc->cpu_usage + ALFA * sample;
}
//store current time
proc->last_sample.tv_sec = now.tv_sec;
proc->last_sample.tv_usec = now.tv_usec;
//store current jiffies
proc->last_jiffies = j;
return 0;
}
int process_close(struct process *proc)
{
if (kill(proc->pid,SIGCONT)!=0) {
fprintf(stderr,"Process %d is already dead!\n", proc->pid);
}
proc->pid = 0;
return 0;
}

View File

@ -0,0 +1,88 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PROCESS_H
#define __PROCESS_H
#include <sys/time.h>
#include <unistd.h>
#include <limits.h>
//USER_HZ detection, from openssl code
#ifndef HZ
# if defined(_SC_CLK_TCK) \
&& (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000)
# define HZ ((double)sysconf(_SC_CLK_TCK))
# else
# ifndef CLK_TCK
# ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
# define HZ 100.0
# else /* _BSD_CLK_TCK_ */
# define HZ ((double)_BSD_CLK_TCK_)
# endif
# else /* CLK_TCK */
# define HZ ((double)CLK_TCK)
# endif
# endif
#endif
// process descriptor
struct process {
//pid of the process
pid_t pid;
//pid of the process
pid_t ppid;
//start time
int starttime;
//is member of the family?
int member; //TODO: delete this field
//total number of jiffies used by the process at time last_sample
int last_jiffies;
//timestamp when last_jiffies and cpu_usage was calculated
struct timeval last_sample;
//actual cpu usage estimation (value in range 0-1)
double cpu_usage;
//1 if the process is zombie
int is_zombie;
//absolute path of the executable file
char command[PATH_MAX+1];
//system-dependent members
//TODO: delete these members for the sake of portability?
#ifdef __linux__
//preallocate buffers for performance
//name of /proc/PID/stat file
char stat_file[20];
//read buffer for /proc filesystem
char buffer[1024];
#endif
};
int get_proc_info(struct process *p, pid_t pid);
int process_init(struct process *proc, pid_t pid);
int process_monitor(struct process *proc);
int process_close(struct process *proc);
#endif

View File

@ -0,0 +1,544 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2012, by: Gang Liu <gangban.lau@gmail.com>
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "procutils.h"
#ifdef __APPLE__
#include <sys/sysctl.h>
#include <errno.h>
#endif
/* PROCESS STATISTICS FUNCTIONS */
//deprecated
// returns pid of the parent process
static pid_t getppid_of(pid_t pid)
{
#ifdef __linux__
char file[20];
char buffer[1024];
snprintf(file, sizeof(file), "/proc/%d/stat", pid);
FILE *fd = fopen(file, "r");
if (fd==NULL) return -1;
if (fgets(buffer, sizeof(buffer), fd)==NULL)
{
fclose(fd);
return -1;
}
fclose(fd);
char *p = buffer;
p = memchr(p+1,')', sizeof(buffer) - (p-buffer));
int sp = 2;
while (sp--)
p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
//pid of the parent process
pid_t ppid = atoi(p+1);
return ppid;
#elif defined __APPLE__
struct process p;
get_proc_info(&p, pid);
return p.ppid;
#endif
}
#ifdef __linux__
// detects whether a process is a kernel thread or not
static int is_kernel_thread(pid_t pid)
{
char statfile[20];
char buffer[64];
int ret;
snprintf(statfile, sizeof(statfile), "/proc/%d/statm", pid);
FILE *fd = fopen(statfile, "r");
if (fd==NULL)
{
perror("open process statm file failed");
return -1;
}
if (fgets(buffer, sizeof(buffer), fd)==NULL)
{
perror("read process statm file failed");
fclose(fd);
return -1;
}
ret = strncmp(buffer,"0 0 0",3)==0;
fclose(fd);
return ret;
}
#endif
//deprecated
// returns 1 if pid is an existing pid, 0 otherwise
static int process_exists(pid_t pid) {
#ifdef __linux__
char procdir[20];
struct stat procstat;
snprintf(procdir, sizeof(procdir), "/proc/%d", pid);
return stat(procdir, &procstat)==0;
#elif defined __APPLE__
struct process p;
return get_proc_info(&p, pid)==0;
#endif
}
/* PID HASH FUNCTIONS */
static int hash_process(struct process_family *f, struct process *p)
{
int ret;
struct list **l = &(f->proctable[pid_hashfn(p->pid)]);
if (*l == NULL) {
//there is no process in this hashtable item
//allocate the list
*l = (struct list*)malloc(sizeof(struct list));
init_list(*l, 4);
add_elem(*l, p);
ret = 0;
f->count++;
}
else {
//list already exists
struct process *tmp = (struct process*)locate_elem(*l, p);
if (tmp != NULL) {
//update process info
memcpy(tmp, p, sizeof(struct process));
free(p);
p = NULL;
ret = 1;
}
else {
//add new process
add_elem(*l, p);
ret = 0;
f->count++;
}
}
return ret;
}
static void unhash_process(struct process_family *f, pid_t pid) {
//remove process from hashtable
struct list **l = &(f->proctable[pid_hashfn(pid)]);
if (*l == NULL)
return; //nothing done
struct list_node *node = locate_node(*l, &pid);
if (node != NULL)
destroy_node(*l, node);
f->count--;
}
static struct process *seek_process(struct process_family *f, pid_t pid)
{
struct list **l = &(f->proctable[pid_hashfn(pid)]);
return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL;
}
/* PROCESS ITERATOR STUFF */
// creates an object that browse all running processes
int init_process_iterator(struct process_iterator *i) {
#ifdef __linux__
//open a directory stream to /proc directory
if ((i->dip = opendir("/proc")) == NULL) {
perror("opendir");
return -1;
}
#elif defined __APPLE__
int err;
struct kinfo_proc *result = NULL;
size_t length;
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
/* We start by calling sysctl with result == NULL and length == 0.
That will succeed, and set length to the appropriate length.
We then allocate a buffer of that size and call sysctl again
with that buffer.
*/
length = 0;
err = sysctl(mib, 4, NULL, &length, NULL, 0);
if (err == -1) {
err = errno;
}
if (err == 0) {
result = malloc(length);
err = sysctl(mib, 4, result, &length, NULL, 0);
if (err == -1)
err = errno;
if (err == ENOMEM) {
free(result); /* clean up */
result = NULL;
}
}
i->procList = result;
i->count = err == 0 ? length / sizeof *result : 0;
i->c = 0;
#endif
i->current = (struct process*)malloc(sizeof(struct process));
if (i->current == NULL)
{
perror("malloc falied");
closedir(i->dip);
return -1;
}
memset(i->current, 0, sizeof(struct process));
return 0;
}
// reads the next user process from /process
// automatic closing if the end of the list is reached
int read_next_process(struct process_iterator *i) {
#ifdef __linux__
pid_t pid = 0;
//TODO read this to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85
//read in from /proc and seek for process dirs
while ((i->dit = readdir(i->dip)) != NULL) {
if(strtok(i->dit->d_name, "0123456789") != NULL)
continue;
pid = atoi(i->dit->d_name);
if (is_kernel_thread(pid))
{
pid = 0;
continue;
}
//return the first found process
break;
}
if (pid == 0) {
//no more processes
closedir(i->dip);
i->dip = NULL;
free(i->current);
i->current = NULL;
return -1;
}
//read the executable link
char statfile[20];
snprintf(statfile, sizeof(statfile), "/proc/%d/cmdline",pid);
FILE *fd = fopen(statfile, "r");
if (fd == NULL)
{
perror("open process cmdline file failed");
return -1;
}
char buffer[1024];
if (fgets(buffer, sizeof(buffer), fd)==NULL)
{
perror("read process cmdline file falied");
fclose(fd);
return -2;
}
fclose(fd);
sscanf(buffer, "%s", (char*)&i->current->command);
i->current->pid = pid;
#elif defined __APPLE__
if (i->c >= i->count) {
//no more processes
free(i->procList);
i->procList = NULL;
free(i->current);
i->current = NULL;
return -1;
}
i->current->pid = i->procList[i->c].kp_proc.p_pid;
strncpy(i->current->command, i->procList[i->c].kp_proc.p_comm, MAXCOMLEN);
printf("%d %d %s\n", i->c, i->current->pid, i->current->command);//i->procList[i->c].kp_proc.p_comm);
//printf("%d %d %s\n", i->c, i->current->pid, i->proc[i->c].kp_proc.p_comm);
i->c++;
#endif
return 0;
}
/* PUBLIC FUNCTIONS */
// search for all the processes derived from father and stores them
// in the process family struct
int create_process_family(struct process_family *f, pid_t father)
{
//process iterator
struct process_iterator iter;
if (init_process_iterator(&iter) == -1)
return -1;
//process list initialization (4 bytes key)
init_list(&(f->members), 4);
//hashtable initialization
memset(&(f->proctable), 0, sizeof(f->proctable));
f->count = 0;
f->father = father;
int pid = 0;
while (read_next_process(&iter)==0) {
pid = iter.current->pid;
//check if process belongs to the family
int ppid = pid;
//TODO: optimize adding also these parents, and continue if process is already present
while(ppid!=1 && ppid!=father) {
//pid_t f = getppid(ppid);
ppid = getppid_of(ppid);
//printf("p1 %d, p2 %d\n", f, ppid);
}
//allocate process descriptor
struct process *p = (struct process*)malloc(sizeof(struct process));
//init process
if (process_init(p, pid) == -1)
{
printf("init process failed\n");
free(p);
continue;
}
if (ppid==1) {
//the init process
p->member = 0;
}
else if (pid != getpid()) {
//add to members (but exclude the current cpulimit process!)
p->member = 1;
add_elem(&(f->members), p);
}
//add to hashtable
hash_process(f, p);
}
if (iter.dip != NULL)
closedir(iter.dip);
if (iter.current != NULL)
free(iter.current);
return 0;
}
// checks if there are new processes born in the specified family
// if any they are added to the members list
// the number of new born processes is returned
int update_process_family(struct process_family *f)
{
//process iterator
struct process_iterator iter;
if (init_process_iterator(&iter) == -1)
return -1;
int ret = 0;
int pid = 0;
while (read_next_process(&iter)==0) {
pid = iter.current->pid;
struct process *newp = seek_process(f, pid);
if (newp != NULL) continue; //already known //TODO: what if newp is a new process with the same PID??
//the process is new, check if it belongs to the family
int ppid = getppid_of(pid);
//search the youngest known ancestor of the process
struct process *ancestor = NULL;
while((ancestor=seek_process(f, ppid))==NULL) {
ppid = getppid_of(ppid);
}
if (ancestor == NULL) {
//this should never happen! if does, find and correct the bug
fprintf(stderr, "Fatal bug! Process %d is without parent\n", pid);
exit(1);
}
//allocate and insert the process
struct process *p = (struct process*)malloc(sizeof(struct process));
//init process
if (process_init(p, pid) == -1)
{
printf("init process failed\n");
free(p);
continue;
}
if (ancestor->member) {
//add to members
p->member = 1;
add_elem(&(f->members), p);
ret++;
}
else {
//not a member
p->member = 0;
}
//add to hashtable
hash_process(f, p);
}
if (iter.dip != NULL)
closedir(iter.dip);
if (iter.current != NULL)
free(iter.current);
// remove non-member process if exited
struct list pid_list;
init_list(&pid_list, 0);
int i;
struct list_node *node = NULL;
int size = sizeof(f->proctable) / sizeof(struct process*);
for (i=0; i<size; i++) {
if (f->proctable[i] != NULL) {
for (node=f->proctable[i]->first; node!=NULL; node=node->next) {
struct process *p = (struct process*)(node->data);
if (!p->member && !process_exists(p->pid))
add_elem(&pid_list, &p->pid);
}
}
}
for (node=pid_list.first; node!=NULL; node=node->next) {
pid_t * p = (pid_t *)(node->data);
remove_process_from_family(f, *p);
}
flush_list(&pid_list);
return ret;
}
// removes a process from the family by its pid
void remove_process_from_family(struct process_family *f, pid_t pid)
{
struct list_node *node = locate_node(&(f->members), &pid);
if (node != NULL) {
// struct process *p = (struct process*)(node->data);
// free(p->history);
// p->history = NULL;
delete_node(&(f->members), node);
}
unhash_process(f, pid);
}
// free the heap memory used by a process family
void cleanup_process_family(struct process_family *f)
{
int i;
int size = sizeof(f->proctable) / sizeof(struct process*);
for (i=0; i<size; i++) {
if (f->proctable[i] != NULL) {
//free() history for each process
struct list_node *node = NULL;
for (node=f->proctable[i]->first; node!=NULL; node=node->next) {
// struct process *p = (struct process*)(node->data);
// free(p->history);
// p->history = NULL;
}
destroy_list(f->proctable[i]);
free(f->proctable[i]);
f->proctable[i] = NULL;
}
}
flush_list(&(f->members));
f->count = 0;
f->father = 0;
}
// look for a process by pid
// search_pid : pid of the wanted process
// return: pid of the found process, if it is found
// 0, if it's not found
// negative pid, if it is found but it's not possible to control it
int look_for_process_by_pid(pid_t pid)
{
if (process_exists(pid))
return (kill(pid,0)==0) ? pid : -pid;
return 0;
}
// look for a process with a given name
// process: the name of the wanted process. it can be an absolute path name to the executable file
// or just the file name
// return: pid of the found process, if it is found
// 0, if it's not found
// negative pid, if it is found but it's not possible to control it
int look_for_process_by_name(const char *process_name)
{
//whether the variable process_name is the absolute path or not
int is_absolute_path = process_name[0] == '/';
//flag indicating if the a process with given name was found
int found = 0;
//process iterator
struct process_iterator iter;
if (init_process_iterator(&iter) == -1)
return -1;
pid_t pid = 0;
printf("name\n");
while (read_next_process(&iter)==0) {
pid = iter.current->pid;
int size = strlen(iter.current->command);
found = 0;
if (is_absolute_path && strncmp(iter.current->command, process_name, size)==0 && size==strlen(process_name)) {
//process found
found = 1;
}
else {
//process found
if (strncmp(iter.current->command + size - strlen(process_name), process_name, strlen(process_name))==0) {
found = 1;
}
}
if (found==1) {
if (kill(pid,SIGCONT)==0) {
//process is ok!
break;
}
else {
//we don't have permission to send signal to that process
//so, don't exit from the loop and look for another one with the same name
found = -1;
}
}
}
if (iter.dip != NULL)
closedir(iter.dip);
if (iter.current != NULL)
free(iter.current);
if (found == 1) {
//ok, the process was found
return pid;
}
else if (found == 0) {
//no process found
return 0;
}
else if (found == -1) {
//the process was found, but we haven't permission to control it
return -pid;
}
//this MUST NOT happen
return 0;
}

View File

@ -0,0 +1,94 @@
/**
*
* cpulimit - a cpu limiter for Linux
*
* Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PROCUTILS_H
#define __PROCUTILS_H
#include <sys/types.h>
#include <dirent.h>
#include "list.h"
#include "process.h"
#define PIDHASH_SZ 1024
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
// a hierarchy of processes
struct process_family {
//the (god)father of the process family
pid_t father;
//process list (father process is the first element)
//elements are struct process
struct list members;
//non-members list
//hashtable with all the processes (array of struct list of struct process)
struct list *proctable[PIDHASH_SZ];
//total process count
int count;
};
//TODO: use this object in proctable and delete member in struct process
struct table_item {
struct process *proc;
//1 if the process is a member of the family
int member;
};
// object to enumerate running processes
struct process_iterator {
#ifdef __linux__
DIR *dip;
struct dirent *dit;
#elif defined __APPLE__
struct kinfo_proc *procList;
int count;
int c;
#elif defined __hpux
int count;
#endif
struct process *current;
};
// searches for all the processes derived from father and stores them
// in the process family struct
int create_process_family(struct process_family *f, pid_t father);
// checks if there are new processes born in the specified family
// if any they are added to the members list
// the number of new born processes is returned
int update_process_family(struct process_family *f);
// removes a process from the family by its pid
void remove_process_from_family(struct process_family *f, pid_t pid);
// free the heap memory used by a process family
void cleanup_process_family(struct process_family *f);
// searches a process given the name of the executable file, or its absolute path
// returns the pid, or 0 if it's not found
int look_for_process_by_name(const char *process_name);
// searches a process given its pid
// returns the pid, or 0 if it's not found
int look_for_process_by_pid(pid_t pid);
#endif

33
package/jsda/cpulimit/Makefile Executable file
View File

@ -0,0 +1,33 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=cpulimit
PKG_VERSION:=cabeb9947c
PKG_RELEASE:=1
PKG_REV:=cabeb9947ccddd9a6e6ba14503e2a33063ac1b21
#PKG_SOURCE_PROTO:=git
#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
#PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
#PKG_SOURCE_URL:=https://github.com/opsengine/cpulimit.git
#PKG_SOURCE_VERSION:=$(PKG_REV)
include $(INCLUDE_DIR)/package.mk
define Package/cpulimit
CATEGORY:=Utilities
TITLE:=cpulimit
URL:=https://github.com/opsengine/cpulimit.git
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/cpulimit/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/cpulimit $(1)/usr/bin
endef
$(eval $(call BuildPackage,cpulimit))

View File

@ -0,0 +1,49 @@
BINDIR ?= $(PREFIX)/bin
BIN_TARGET = cpulimit
CC ?= gcc
CFLAGS ?= -O2 -Wall -g -D_GNU_SOURCE
HELP2MAN := $(shell which help2man)
LIBS = list.o process_iterator.o process_group.o
MAN_NAME := "CPU Utilization Limiter"
MAN_SEC := 1
MAN_SRC := $(shell git remote get-url origin)
MAN_TARGET = $(BIN_TARGET).$(MAN_SEC)
PREFIX ?= /usr/local
STRIP := $(shell which strip)
SUDO := $(shell which sudo)
TARGETS = $(BIN_TARGET) $(MAN_TARGET)
UNAME := $(shell uname)
ifeq ($(UNAME), FreeBSD)
LIBS += -lkvm
endif
all:: $(TARGETS) $(LIBS)
static:
$(MAKE) all CFLAGS="$(CFLAGS) --static"
strip: $(BIN_TARGET)
$(STRIP) $<
install: $(TARGETS)
$(SUDO) install $^ $(BINDIR)
$(BIN_TARGET): cpulimit.c $(LIBS)
$(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS)
$(MAN_TARGET): $(BIN_TARGET) $(HELP2MAN)
$(HELP2MAN) -n $(MAN_NAME) -s $(MAN_SEC) -s $(MAN_SRC) -N ./$< > $@
process_iterator.o: process_iterator.c process_iterator.h
$(CC) -c process_iterator.c $(CFLAGS)
list.o: list.c list.h
$(CC) -c list.c $(CFLAGS)
process_group.o: process_group.c process_group.h process_iterator.o list.o
$(CC) -c process_group.c $(CFLAGS)
clean:
rm -f *~ *.o $(TARGETS)

View File

@ -0,0 +1,560 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**************************************************************
*
* This is a simple program to limit the cpu usage of a process
* If you modify this code, send me a copy please
*
* Get the latest version at: http://github.com/opsengine/cpulimit
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifndef __sun__
#endif
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#if defined(__APPLE__) || defined(__FREEBSD__)
#include <libgen.h>
#endif
#include "process_group.h"
#include "list.h"
#ifdef HAVE_SYS_SYSINFO_H
#include <sys/sysinfo.h>
#endif
#ifdef __APPLE__
#include "memrchr.c"
#endif
//some useful macro
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
//control time slot in microseconds
//each slot is splitted in a working slice and a sleeping slice
//TODO: make it adaptive, based on the actual system load
#define TIME_SLOT 100000
#define MAX_PRIORITY -10
#define VERSION "0.3"
/* GLOBAL VARIABLES */
//the "family"
struct process_group pgroup;
//pid of cpulimit
pid_t cpulimit_pid;
//name of this program (maybe cpulimit...)
char *program_name;
//number of cpu
int NCPU;
/* CONFIGURATION VARIABLES */
//verbose mode
int verbose = 0;
//lazy mode (exits if there is no process)
int lazy = 0;
//SIGINT and SIGTERM signal handler
static void quit(int sig) {
//let all the processes continue if stopped
struct list_node *node = NULL;
if (pgroup.proclist != NULL) {
for (node = pgroup.proclist->first; node != NULL; node = node->next) {
struct process *p = (struct process *)(node->data);
kill(p->pid, SIGCONT);
}
close_process_group(&pgroup);
}
//fix ^C little problem
printf("\r");
fflush(stdout);
exit(0);
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2) {
return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec);
}
static void print_usage(FILE *stream, int exit_code) {
fprintf(stream, "Usage: %s [OPTIONS...] TARGET\n", program_name);
fprintf(stream, " OPTIONS\n");
fprintf(stream, " -l, --limit=N percentage of cpu allowed from 0 to %d (required)\n", 100*NCPU);
fprintf(stream, " -v, --verbose show control statistics\n");
fprintf(stream, " -V, --version show program version number\n");
fprintf(stream, " -z, --lazy exit if there is no target process, or if it dies\n");
fprintf(stream, " -i, --include-children limit also the children processes\n");
fprintf(stream, " -m, --minimum-limited-cpu=M minimum percentage of cpu of target processes\n");
fprintf(stream, " -h, --help display this help and exit\n");
fprintf(stream, " TARGET must be exactly one of these:\n");
fprintf(stream, " -p, --pid=N pid of the process (implies -z)\n");
fprintf(stream, " -e, --exe=FILE name of the executable program file or path name\n");
fprintf(stream, " COMMAND [ARGS] run this command and limit it (implies -z)\n");
exit(exit_code);
}
static void print_version(FILE *stream, int exit_code) {
fprintf(stream, "%s\n", VERSION);
exit(exit_code);
}
static void increase_priority() {
//find the best available nice value
int old_priority = getpriority(PRIO_PROCESS, 0);
int priority = old_priority;
while (setpriority(PRIO_PROCESS, 0, priority-1) == 0 && priority>MAX_PRIORITY) {
priority--;
}
if (priority != old_priority) {
if (verbose) {
printf("Priority changed to %d\n", priority);
}
} else {
if (verbose) {
printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
}
}
}
/* Get the number of CPUs */
static int get_ncpu() {
int ncpu;
#ifdef _SC_NPROCESSORS_ONLN
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
#elif defined __APPLE__
int mib[2] = {CTL_HW, HW_NCPU};
size_t len = sizeof(ncpu);
sysctl(mib, 2, &ncpu, &len, NULL, 0);
#elif defined _GNU_SOURCE
ncpu = get_nprocs();
#else
ncpu = -1;
#endif
return ncpu;
}
int get_pid_max() {
#ifdef __linux__
//read /proc/sys/kernel/pid_max
static char buffer[1024];
FILE *fd = fopen("/proc/sys/kernel/pid_max", "r");
if (fd==NULL) {
return -1;
}
if (fgets(buffer, sizeof(buffer), fd)==NULL) {
fclose(fd);
return -1;
}
fclose(fd);
return atoi(buffer);
#else
return 99998;
#endif
}
void limit_process(pid_t pid, double limit, int include_children, float minimum_cpu_usage) {
//slice of the slot in which the process is allowed to run
struct timespec twork;
//slice of the slot in which the process is stopped
struct timespec tsleep;
//when the last twork has started
struct timeval startwork;
//when the last twork has finished
struct timeval endwork;
//initialization
memset(&twork, 0, sizeof(struct timespec));
memset(&tsleep, 0, sizeof(struct timespec));
memset(&startwork, 0, sizeof(struct timeval));
memset(&endwork, 0, sizeof(struct timeval));
//last working time in microseconds
unsigned long workingtime = 0;
//generic list item
struct list_node *node;
//counter
int c = 0;
//get a better priority
increase_priority();
//build the family
init_process_group(&pgroup, pid, include_children);
if (verbose) {
printf("Members in the process group owned by %d: %d\n", pgroup.target_pid, pgroup.proclist->count);
}
//rate at which we are keeping active the processes (range 0-1)
//1 means that the process are using all the twork slice
double workingrate = -1;
while (1) {
update_process_group(&pgroup);
if (pgroup.proclist->count==0) {
if (verbose) {
printf("No more processes.\n");
}
break;
}
//total cpu actual usage (range 0-1)
//1 means that the processes are using 100% cpu
double pcpu = -1;
//estimate how much the controlled processes are using the cpu in the working interval
for (node = pgroup.proclist->first; node != NULL; node = node->next) {
struct process *proc = (struct process *)(node->data);
if (proc->cpu_usage < 0) {
continue;
}
if (pcpu < 0) {
pcpu = 0;
}
pcpu += proc->cpu_usage;
}
//adjust work and sleep time slices
if (pcpu < 0) {
//it's the 1st cycle, initialize workingrate
pcpu = limit;
workingrate = limit;
twork.tv_nsec = TIME_SLOT * limit * 1000;
} else {
//adjust workingrate
workingrate = MIN(workingrate / pcpu * limit, 1);
twork.tv_nsec = TIME_SLOT * 1000 * workingrate;
}
tsleep.tv_nsec = TIME_SLOT * 1000 - twork.tv_nsec;
if (verbose) {
if (c%200==0) {
printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
}
if (c%10==0 && c>0) {
printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n", pcpu*100, twork.tv_nsec/1000, tsleep.tv_nsec/1000, workingrate*100);
}
}
//resume processes
node = pgroup.proclist->first;
while (node != NULL) {
struct list_node *next_node = node->next;
struct process *proc = (struct process *)(node->data);
if (kill(proc->pid,SIGCONT) != 0) {
//process is dead, remove it from family
if (verbose) {
fprintf(stderr, "SIGCONT failed. Process %d dead!\n", proc->pid);
}
//remove process from group
delete_node(pgroup.proclist, node);
remove_process(&pgroup, proc->pid);
}
node = next_node;
}
//now processes are free to run (same working slice for all)
gettimeofday(&startwork, NULL);
nanosleep(&twork, NULL);
gettimeofday(&endwork, NULL);
workingtime = timediff(&endwork, &startwork);
long delay = workingtime - twork.tv_nsec/1000;
if (c>0 && delay>10000) {
//delay is too much! signal to user?
//fprintf(stderr, "%d %ld us\n", c, delay);
}
if (tsleep.tv_nsec>0) {
//stop processes only if tsleep>0
node = pgroup.proclist->first;
while (node != NULL) {
struct list_node *next_node = node->next;
struct process *proc = (struct process *)(node->data);
if (proc->cpu_usage > minimum_cpu_usage && kill(proc->pid,SIGSTOP)!=0) {
//process is dead, remove it from family
if (verbose) {
fprintf(stderr, "SIGSTOP failed. Process %d dead!\n", proc->pid);
}
//remove process from group
delete_node(pgroup.proclist, node);
remove_process(&pgroup, proc->pid);
}
node = next_node;
}
//now the processes are sleeping
nanosleep(&tsleep,NULL);
}
c++;
}
close_process_group(&pgroup);
}
int main(int argc, char **argv) {
//argument variables
const char *exe = NULL;
int perclimit = 0;
int exe_ok = 0;
int pid_ok = 0;
int limit_ok = 0;
pid_t pid = 0;
float minimum_cpu_usage=0;
int include_children = 0;
//get program name
#ifdef __sun__
char *p = strrchr(argv[0], (unsigned int)'/');
#else
char *p = (char *)memrchr(argv[0], (unsigned int)'/', strlen(argv[0]));
#endif
program_name = p==NULL ? argv[0] : (p+1);
//get current pid
cpulimit_pid = getpid();
//get cpu count
NCPU = get_ncpu();
//parse arguments
int next_option;
int option_index = 0;
//A string listing valid short options letters
const char *short_options = "+p:e:l:vVzim:h";
//An array describing valid long options
const struct option long_options[] = {
{ "pid", required_argument, NULL, 'p' },
{ "exe", required_argument, NULL, 'e' },
{ "limit", required_argument, NULL, 'l' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ "lazy", no_argument, NULL, 'z' },
{ "include-children", no_argument, NULL, 'i' },
{ "minimum-limited-cpu", no_argument, NULL, 'm' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
do {
next_option = getopt_long(argc, argv, short_options,long_options, &option_index);
switch (next_option) {
case 'p':
pid = atoi(optarg);
pid_ok = 1;
break;
case 'e':
exe = optarg;
exe_ok = 1;
break;
case 'l':
perclimit = atoi(optarg);
limit_ok = 1;
break;
case 'v':
verbose = 1;
break;
case 'V':
print_version(stdout, 0);
break;
case 'z':
lazy = 1;
break;
case 'i':
include_children = 1;
break;
case 'm':
minimum_cpu_usage = atof(optarg);
break;
case 'h':
print_usage(stdout, 1);
break;
case '?':
print_usage(stderr, 1);
break;
case -1:
break;
default:
abort();
}
} while (next_option != -1);
if (pid_ok && (pid <= 1 || pid >= get_pid_max())) {
fprintf(stderr,"Error: Invalid value for argument PID\n");
print_usage(stderr, 1);
exit(1);
}
if (pid != 0) {
lazy = 1;
}
if (!limit_ok) {
fprintf(stderr,"Error: You must specify a cpu limit percentage\n");
print_usage(stderr, 1);
exit(1);
}
double limit = perclimit / 100.0;
if (limit<0 || limit >NCPU) {
fprintf(stderr,"Error: limit must be in the range 0-%d00\n", NCPU);
print_usage(stderr, 1);
exit(1);
}
int command_mode = optind < argc;
if (exe_ok + pid_ok + command_mode == 0) {
fprintf(stderr,"Error: You must specify one target process, either by name, pid, or command line\n");
print_usage(stderr, 1);
exit(1);
}
if (exe_ok + pid_ok + command_mode > 1) {
fprintf(stderr,"Error: You must specify exactly one target process, either by name, pid, or command line\n");
print_usage(stderr, 1);
exit(1);
}
//all arguments are ok!
signal(SIGINT, quit);
signal(SIGTERM, quit);
//print the number of available cpu
if (verbose) {
printf("%d cpu detected\n", NCPU);
}
if (command_mode) {
int i;
//executable file
const char *cmd = argv[optind];
//command line arguments
char **cmd_args = (char **)malloc((argc-optind + 1) * sizeof(char *));
if (cmd_args==NULL) {
exit(2);
}
for (i=0; i<argc-optind; i++) {
cmd_args[i] = argv[i+optind];
}
cmd_args[i] = NULL;
if (verbose) {
printf("Running command: '%s", cmd);
for (i=1; i<argc-optind; i++) {
printf(" %s", cmd_args[i]);
}
printf("'\n");
}
int child = fork();
if (child < 0) {
exit(EXIT_FAILURE);
} else if (child == 0) {
//target process code
int ret = execvp(cmd, cmd_args);
//if we are here there was an error, show it
perror("Error");
exit(ret);
} else {
//parent code
free(cmd_args);
int limiter = fork();
if (limiter < 0) {
exit(EXIT_FAILURE);
} else if (limiter > 0) {
//parent
int status_process;
int status_limiter;
waitpid(child, &status_process, 0);
waitpid(limiter, &status_limiter, 0);
if (WIFEXITED(status_process)) {
if (verbose) {
printf("Process %d terminated with exit status %d\n", child, (int)WEXITSTATUS(status_process));
}
exit(WEXITSTATUS(status_process));
}
printf("Process %d terminated abnormally\n", child);
exit(status_process);
} else {
//limiter code
if (verbose) {
printf("Limiting process %d\n",child);
}
limit_process(child, limit, include_children, minimum_cpu_usage);
exit(0);
}
}
}
while (1) {
//look for the target process..or wait for it
pid_t ret = 0;
if (pid_ok) {
//search by pid
ret = find_process_by_pid(pid);
if (ret == 0) {
printf("No process found\n");
} else if (ret < 0) {
printf("Process found but you aren't allowed to control it\n");
}
} else {
//search by file or path name
ret = find_process_by_name(exe);
if (ret == 0) {
printf("No process found\n");
} else if (ret < 0) {
printf("Process found but you aren't allowed to control it\n");
} else {
pid = ret;
}
}
if (ret > 0) {
if (ret == cpulimit_pid) {
printf("Target process %d is cpulimit itself! Aborting because it makes no sense\n", ret);
exit(1);
}
printf("Process %d found\n", pid);
//control
limit_process(pid, limit, include_children, minimum_cpu_usage);
}
if (lazy) {
break;
}
sleep(2);
};
exit(0);
}

146
package/jsda/cpulimit/src/list.c Executable file
View File

@ -0,0 +1,146 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "list.h"
#define EMPTYLIST NULL
void init_list(struct list *l,int keysize) {
l->first=l->last=NULL;
l->keysize=keysize;
l->count=0;
}
struct list_node *add_elem(struct list *l,void *elem) {
struct list_node *newnode=(struct list_node *)malloc(sizeof(struct list_node));
newnode->data=elem;
newnode->previous=l->last;
newnode->next=NULL;
if (l->count==0) {
l->first=l->last=newnode;
} else {
l->last->next=newnode;
l->last=newnode;
}
l->count++;
return newnode;
}
void delete_node(struct list *l,struct list_node *node) {
if (l->count==1) {
l->first=l->last=NULL;
} else if (node==l->first) {
node->next->previous=NULL;
l->first=node->next;
} else if (node==l->last) {
node->previous->next=NULL;
l->last=node->previous;
} else {
node->previous->next=node->next;
node->next->previous=node->previous;
}
l->count--;
free(node);
}
void destroy_node(struct list *l,struct list_node *node) {
free(node->data);
node->data=NULL;
delete_node(l,node);
}
int is_empty_list(struct list *l) {
return (l->count==0?TRUE:FALSE);
}
int get_list_count(struct list *l) {
return l->count;
}
void *first_elem(struct list *l) {
return l->first->data;
}
struct list_node *first_node(struct list *l) {
return l->first;
}
void *last_elem(struct list *l) {
return l->last->data;
}
struct list_node *last_node(struct list *l) {
return l->last;
}
struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length) {
struct list_node *tmp;
tmp=l->first;
while (tmp!=NULL) {
if (!memcmp((char *)tmp->data+offset,elem,length==0?l->keysize:length)) {
return (tmp);
}
tmp=tmp->next;
}
return EMPTYLIST;
}
struct list_node *locate_node(struct list *l,void *elem) {
return (xlocate_node(l,elem,0,0));
}
void *xlocate_elem(struct list *l,void *elem,int offset,int length) {
struct list_node *node=xlocate_node(l,elem,offset,length);
return (node==NULL?NULL:node->data);
}
void *locate_elem(struct list *l,void *elem) {
return (xlocate_elem(l,elem,0,0));
}
void clear_list(struct list *l) {
while (l->first!=EMPTYLIST) {
struct list_node *tmp;
tmp=l->first;
l->first=l->first->next;
free(tmp);
tmp=NULL;
}
l->last=EMPTYLIST;
l->count=0;
}
void destroy_list(struct list *l) {
while (l->first!=EMPTYLIST) {
struct list_node *tmp;
tmp=l->first;
l->first=l->first->next;
free(tmp->data);
tmp->data=NULL;
free(tmp);
tmp=NULL;
}
l->last=EMPTYLIST;
l->count=0;
}

138
package/jsda/cpulimit/src/list.h Executable file
View File

@ -0,0 +1,138 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __LIST__
#define __LIST__
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
struct list_node {
//pointer to the content of the node
void *data;
//pointer to previous node
struct list_node *previous;
//pointer to next node
struct list_node *next;
};
struct list {
//first node
struct list_node *first;
//last node
struct list_node *last;
//size of the search key in bytes
int keysize;
//element count
int count;
};
/*
* Initialize a list, with a specified key size
*/
void init_list(struct list *l,int keysize);
/*
* Add a new element at the end of the list
* return the pointer to the new node
*/
struct list_node *add_elem(struct list *l,void *elem);
/*
* Delete a node
*/
void delete_node(struct list *l,struct list_node *node);
/*
* Delete a node from the list, even the content pointed by it
* Use only when the content is a dynamically allocated pointer
*/
void destroy_node(struct list *l,struct list_node *node);
/*
* Check whether a list is empty or not
*/
int is_empty_list(struct list *l);
/*
* Return the element count of the list
*/
int get_list_count(struct list *l);
/*
* Return the first element (content of the node) from the list
*/
void *first_elem(struct list *l);
/*
* Return the first node from the list
*/
struct list_node *first_node(struct list *l);
/*
* Return the last element (content of the node) from the list
*/
void *last_elem(struct list *l);
/*
* Return the last node from the list
*/
struct list_node *last_node(struct list *l);
/*
* Search an element of the list by content
* the comparison is done from the specified offset and for a specified length
* if offset=0, the comparison starts from the address pointed by data
* if length=0, default keysize is used for length
* if the element is found, return the node address
* else return NULL
*/
struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length);
/*
* The same of xlocate_node(), but return the content of the node
*/
void *xlocate_elem(struct list *l,void *elem,int offset,int length);
/*
* The same of calling xlocate_node() with offset=0 and length=0
*/
struct list_node *locate_node(struct list *l,void *elem);
/*
* The same of locate_node, but return the content of the node
*/
void *locate_elem(struct list *l,void *elem);
/*
* Delete all the elements in the list
*/
void clear_list(struct list *l);
/*
* Delete every element in the list, and free the memory pointed by all the node data
*/
void destroy_list(struct list *l);
#endif

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
/*
* Reverse memchr()
* Find the last occurrence of 'c' in the buffer 's' of size 'n'.
*/
void *
memrchr(s, c, n)
const void *s;
int c;
size_t n;
{
if (n != 0) {
const unsigned char *cp;
cp = (unsigned char *)s + n;
do {
if (*(--cp) == (unsigned char)c) {
return ((void *)cp);
}
} while (--n != 0);
}
return ((void *)0);
}

View File

@ -0,0 +1,205 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/time.h>
#include <signal.h>
#if defined(__APPLE__) || defined(__FREEBSD__)
#include <libgen.h>
#endif
#include <assert.h>
#ifdef __sun__
#include <libgen.h>
#endif
#include "process_iterator.h"
#include "process_group.h"
#include "list.h"
// look for a process by pid
// search_pid : pid of the wanted process
// return: pid of the found process, if successful
// negative pid, if the process does not exist or if the signal fails
int find_process_by_pid(pid_t pid) {
return (kill(pid,0)==0) ? pid : -pid;
}
// look for a process with a given name
// process: the name of the wanted process. it can be an absolute path name to the executable file
// or just the file name
// return: pid of the found process, if it is found
// 0, if it's not found
// negative pid, if it is found but it's not possible to control it
int find_process_by_name(const char *process_name) {
//pid of the target process
pid_t pid = -1;
//process iterator
struct process_iterator it;
struct process proc;
struct process_filter filter;
filter.pid = 0;
filter.include_children = 0;
init_process_iterator(&it, &filter);
while (get_next_process(&it, &proc) != -1) {
//process found
if (strncmp(basename(proc.command), process_name, strlen(process_name))==0 && kill(pid,SIGCONT)==0) {
//process is ok!
pid = proc.pid;
break;
}
}
if (close_process_iterator(&it) != 0) {
exit(1);
}
if (pid >= 0) {
//ok, the process was found
return pid;
} else {
//process not found
return 0;
}
}
int init_process_group(struct process_group *pgroup, int target_pid, int include_children) {
//hashtable initialization
memset(&pgroup->proctable, 0, sizeof(pgroup->proctable));
pgroup->target_pid = target_pid;
pgroup->include_children = include_children;
pgroup->proclist = (struct list *)malloc(sizeof(struct list));
init_list(pgroup->proclist, 4);
memset(&pgroup->last_update, 0, sizeof(pgroup->last_update));
update_process_group(pgroup);
return 0;
}
int close_process_group(struct process_group *pgroup) {
int i;
int size = sizeof(pgroup->proctable) / sizeof(struct process *);
for (i=0; i<size; i++) {
if (pgroup->proctable[i] != NULL) {
//free() history for each process
destroy_list(pgroup->proctable[i]);
free(pgroup->proctable[i]);
pgroup->proctable[i] = NULL;
}
}
clear_list(pgroup->proclist);
free(pgroup->proclist);
pgroup->proclist = NULL;
return 0;
}
void remove_terminated_processes(struct process_group *pgroup) {
//TODO
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2) {
return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec);
}
//parameter in range 0-1
#define ALFA 0.08
#define MIN_DT 20
void update_process_group(struct process_group *pgroup) {
struct process_iterator it;
struct process tmp_process;
struct process_filter filter;
struct timeval now;
gettimeofday(&now, NULL);
//time elapsed from previous sample (in ms)
long dt = timediff(&now, &pgroup->last_update) / 1000;
filter.pid = pgroup->target_pid;
filter.include_children = pgroup->include_children;
init_process_iterator(&it, &filter);
clear_list(pgroup->proclist);
init_list(pgroup->proclist, 4);
while (get_next_process(&it, &tmp_process) != -1) {
// struct timeval t;
// gettimeofday(&t, NULL);
// printf("T=%ld.%ld PID=%d PPID=%d START=%d CPUTIME=%d\n", t.tv_sec, t.tv_usec, tmp_process.pid, tmp_process.ppid, tmp_process.starttime, tmp_process.cputime);
int hashkey = pid_hashfn(tmp_process.pid);
if (pgroup->proctable[hashkey] == NULL) {
//empty bucket
pgroup->proctable[hashkey] = malloc(sizeof(struct list));
struct process *new_process = malloc(sizeof(struct process));
tmp_process.cpu_usage = -1;
memcpy(new_process, &tmp_process, sizeof(struct process));
init_list(pgroup->proctable[hashkey], 4);
add_elem(pgroup->proctable[hashkey], new_process);
add_elem(pgroup->proclist, new_process);
} else {
//existing bucket
struct process *p = (struct process *)locate_elem(pgroup->proctable[hashkey], &tmp_process);
if (p == NULL) {
//process is new. add it
struct process *new_process = malloc(sizeof(struct process));
tmp_process.cpu_usage = -1;
memcpy(new_process, &tmp_process, sizeof(struct process));
add_elem(pgroup->proctable[hashkey], new_process);
add_elem(pgroup->proclist, new_process);
} else {
assert(tmp_process.pid == p->pid);
assert(tmp_process.starttime == p->starttime);
add_elem(pgroup->proclist, p);
if (dt < MIN_DT) {
continue;
}
//process exists. update CPU usage
double sample = 1.0 * (tmp_process.cputime - p->cputime) / dt;
if (p->cpu_usage == -1) {
//initialization
p->cpu_usage = sample;
} else {
//usage adjustment
p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample;
}
p->cputime = tmp_process.cputime;
}
}
}
close_process_iterator(&it);
if (dt < MIN_DT) {
return;
}
pgroup->last_update = now;
}
int remove_process(struct process_group *pgroup, int pid) {
int hashkey = pid_hashfn(pid);
if (pgroup->proctable[hashkey] == NULL) {
return 1; //nothing to delete
}
struct list_node *node = (struct list_node *)locate_node(pgroup->proctable[hashkey], &pid);
if (node == NULL) {
return 2;
}
delete_node(pgroup->proctable[hashkey], node);
return 0;
}

View File

@ -0,0 +1,54 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PROCESS_GROUP_H
#define __PROCESS_GROUP_H
#include "process_iterator.h"
#include "list.h"
#define PIDHASH_SZ 1024
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
struct process_group {
//hashtable with all the processes (array of struct list of struct process)
struct list *proctable[PIDHASH_SZ];
struct list *proclist;
pid_t target_pid;
int include_children;
struct timeval last_update;
};
int init_process_group(struct process_group *pgroup, int target_pid, int include_children);
void update_process_group(struct process_group *pgroup);
int close_process_group(struct process_group *pgroup);
int find_process_by_pid(pid_t pid);
int find_process_by_name(const char *process_name);
int remove_process(struct process_group *pgroup, int pid);
#endif

View File

@ -0,0 +1,55 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __sun__
#include <procfs.h>
#elif !defined __APPLE__
#include <sys/procfs.h>
#endif
#include <time.h>
#include "process_iterator.h"
//See this link to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85
#ifdef __linux__
#include "process_iterator_linux.c"
#elif defined __FreeBSD__
#include "process_iterator_freebsd.c"
#elif defined __APPLE__
#include "process_iterator_apple.c"
#elif defined __sun__
#include "process_iterator_solaris.c"
#else
#error Platform not supported
#endif

View File

@ -0,0 +1,97 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PROCESS_ITERATOR_H
#define __PROCESS_ITERATOR_H
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
//USER_HZ detection, from openssl code
#ifndef HZ
#if defined(_SC_CLK_TCK) \
&& (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000)
#define HZ ((double)sysconf(_SC_CLK_TCK))
#else
#ifndef CLK_TCK
#ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
#define HZ 100.0
#else /* _BSD_CLK_TCK_ */
#define HZ ((double)_BSD_CLK_TCK_)
#endif
#else /* CLK_TCK */
#define HZ ((double)CLK_TCK)
#endif
#endif
#endif
#ifdef __FreeBSD__
#include <kvm.h>
#endif
// process descriptor
struct process {
//pid of the process
pid_t pid;
//ppid of the process
pid_t ppid;
//start time (unix timestamp)
int starttime;
//cputime used by the process (in milliseconds)
int cputime;
//actual cpu usage estimation (value in range 0-1)
double cpu_usage;
//absolute path of the executable file
char command[PATH_MAX+1];
};
struct process_filter {
int pid;
int include_children;
char program_name[PATH_MAX+1];
};
struct process_iterator {
#if defined __linux__ || defined __sun__
DIR *dip;
int boot_time;
#elif defined __FreeBSD__
kvm_t *kd;
struct kinfo_proc *procs;
int count;
int i;
#elif defined __APPLE__
int i;
int count;
int *pidlist;
#endif
struct process_filter *filter;
};
int init_process_iterator(struct process_iterator *i, struct process_filter *filter);
int get_next_process(struct process_iterator *i, struct process *p);
int close_process_iterator(struct process_iterator *i);
#endif

View File

@ -0,0 +1,154 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Author: Simon Sigurdhsson
*
*/
#include <errno.h>
#include <stdio.h>
#include <libproc.h>
int unique_nonzero_ints(int *arr_in, int len_in, int *arr_out) {
int *source = arr_in;
if (arr_out == NULL) {
return -1;
}
if (arr_in == arr_out) {
source = malloc(sizeof(int)*len_in);
memcpy(source, arr_in, sizeof(int)*len_in);
memset(arr_out, -1, sizeof(int)*len_in);
}
int len_out = 0;
int i, j;
for (i=0; i<len_in; i++) {
int found = 0;
if (source[i] == 0) {
continue;
}
for (j=0; !found && j<len_out; j++) {
found = (source[i] == arr_out[j]) ? 1 : 0;
}
if (!found) {
arr_out[len_out++] = source[i];
}
}
if (arr_in == arr_out) {
free(source);
}
return len_out-1;
}
int init_process_iterator(struct process_iterator *it, struct process_filter *filter) {
it->i = 0;
/* Find out how much to allocate for it->pidlist */
if ((it->count = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)) <= 0) {
fprintf(stderr, "proc_listpids: %s\n", strerror(errno));
return -1;
}
/* Allocate and populate it->pidlist */
if ((it->pidlist = (int *)malloc((it->count)*sizeof(int))) == NULL) {
fprintf(stderr, "malloc: %s\n", strerror(errno));
}
if ((it->count = proc_listpids(PROC_ALL_PIDS, 0, it->pidlist, it->count)) <= 0) {
fprintf(stderr, "proc_listpids: %s\n", strerror(errno));
return -1;
}
it->count = unique_nonzero_ints(it->pidlist, it->count, it->pidlist);
it->filter = filter;
return 0;
}
static int pti2proc(struct proc_taskallinfo *ti, struct process *process) {
int bytes;
process->pid = ti->pbsd.pbi_pid;
process->ppid = ti->pbsd.pbi_ppid;
process->starttime = ti->pbsd.pbi_start_tvsec;
process->cputime = (ti->ptinfo.pti_total_user + ti->ptinfo.pti_total_system) / 1000000;
bytes = strlen(ti->pbsd.pbi_comm);
memcpy(process->command, ti->pbsd.pbi_comm, (bytes < PATH_MAX ? bytes : PATH_MAX) + 1);
return 0;
}
static int get_process_pti(pid_t pid, struct proc_taskallinfo *ti) {
int bytes;
bytes = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, ti, sizeof(*ti));
if (bytes <= 0) {
if (!(errno & (EPERM | ESRCH))) {
fprintf(stderr, "proc_pidinfo: %s\n", strerror(errno));
}
return -1;
} else if (bytes < sizeof(ti)) {
fprintf(stderr, "proc_pidinfo: too few bytes; expected %ld, got %d\n", sizeof(ti), bytes);
return -1;
}
return 0;
}
int get_next_process(struct process_iterator *it, struct process *p) {
if (it->i == it->count) {
return -1;
}
if (it->filter->pid != 0 && !it->filter->include_children) {
struct proc_taskallinfo ti;
if (get_process_pti(it->filter->pid, &ti) != 0) {
it->i = it->count = 0;
return -1;
}
it->i = it->count = 1;
return pti2proc(&ti, p);
}
while (it->i < it->count) {
struct proc_taskallinfo ti;
if (get_process_pti(it->pidlist[it->i], &ti) != 0) {
it->i++;
continue;
}
if (ti.pbsd.pbi_flags & PROC_FLAG_SYSTEM) {
it->i++;
continue;
}
if (it->filter->pid != 0 && it->filter->include_children) {
pti2proc(&ti, p);
it->i++;
if (p->pid != it->pidlist[it->i - 1]) { // I don't know why this can happen
continue;
}
if (p->pid != it->filter->pid && p->ppid != it->filter->pid) {
continue;
}
return 0;
} else if (it->filter->pid == 0) {
pti2proc(&ti, p);
it->i++;
return 0;
}
}
return -1;
}
int close_process_iterator(struct process_iterator *it) {
free(it->pidlist);
it->pidlist = NULL;
it->filter = NULL;
it->count = 0;
it->i = 0;
return 0;
}

View File

@ -0,0 +1,111 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/sysctl.h>
#include <sys/user.h>
#include <fcntl.h>
#include <paths.h>
int init_process_iterator(struct process_iterator *it, struct process_filter *filter) {
char errbuf[_POSIX2_LINE_MAX];
it->i = 0;
/* Open the kvm interface, get a descriptor */
if ((it->kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) {
fprintf(stderr, "kvm_open: %s\n", errbuf);
return -1;
}
/* Get the list of processes. */
if ((it->procs = kvm_getprocs(it->kd, KERN_PROC_PROC, 0, &it->count)) == NULL) {
kvm_close(it->kd);
// fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(it->kd));
return -1;
}
it->filter = filter;
return 0;
}
static int kproc2proc(kvm_t *kd, struct kinfo_proc *kproc, struct process *proc) {
proc->pid = kproc->ki_pid;
proc->ppid = kproc->ki_ppid;
proc->cputime = kproc->ki_runtime / 1000;
proc->starttime = kproc->ki_start.tv_sec;
char **args = kvm_getargv(kd, kproc, sizeof(proc->command));
if (args == NULL) {
return -1;
}
memcpy(proc->command, args[0], strlen(args[0]) + 1);
return 0;
}
static int get_single_process(kvm_t *kd, pid_t pid, struct process *process) {
int count;
struct kinfo_proc *kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, &count);
if (count == 0 || kproc == NULL) {
// fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd));
return -1;
}
kproc2proc(kd, kproc, process);
return 0;
}
int get_next_process(struct process_iterator *it, struct process *p) {
if (it->i == it->count) {
return -1;
}
if (it->filter->pid != 0 && !it->filter->include_children) {
if (get_single_process(it->kd, it->filter->pid, p) != 0) {
it->i = it->count = 0;
return -1;
}
it->i = it->count = 1;
return 0;
}
while (it->i < it->count) {
struct kinfo_proc *kproc = &(it->procs[it->i]);
if (kproc->ki_flag & P_SYSTEM) {
// skip system processes
it->i++;
continue;
}
if (it->filter->pid != 0 && it->filter->include_children) {
kproc2proc(it->kd, kproc, p);
it->i++;
if (p->pid != it->filter->pid && p->ppid != it->filter->pid) {
continue;
}
return 0;
} else if (it->filter->pid == 0) {
kproc2proc(it->kd, kproc, p);
it->i++;
return 0;
}
}
return -1;
}
int close_process_iterator(struct process_iterator *it) {
if (kvm_close(it->kd) == -1) {
fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(it->kd));
return -1;
}
return 0;
}

View File

@ -0,0 +1,188 @@
/**
*
* cpulimit - a CPU limiter for Linux
*
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/vfs.h>
static int get_boot_time() {
int uptime = 0;
FILE *fp = fopen("/proc/uptime", "r");
if (fp != NULL) {
char buf[BUFSIZ];
char *b = fgets(buf, BUFSIZ, fp);
if (b == buf) {
char *end_ptr;
double upsecs = strtod(buf, &end_ptr);
uptime = (int)upsecs;
}
fclose(fp);
}
time_t now = time(NULL);
return now - uptime;
}
static int check_proc() {
struct statfs mnt;
if (statfs("/proc", &mnt) < 0) {
return 0;
}
if (mnt.f_type!=0x9fa0) {
return 0;
}
return 1;
}
int init_process_iterator(struct process_iterator *it, struct process_filter *filter) {
if (!check_proc()) {
fprintf(stderr, "procfs is not mounted!\nAborting\n");
exit(-2);
}
//open a directory stream to /proc directory
if ((it->dip = opendir("/proc")) == NULL) {
perror("opendir");
return -1;
}
it->filter = filter;
it->boot_time = get_boot_time();
return 0;
}
static int read_process_info(pid_t pid, struct process *p) {
static char buffer[1024];
static char statfile[32];
static char exefile[1024];
p->pid = pid;
//read stat file
sprintf(statfile, "/proc/%d/stat", p->pid);
FILE *fd = fopen(statfile, "r");
if (fd==NULL) {
return -1;
}
if (fgets(buffer, sizeof(buffer), fd)==NULL) {
fclose(fd);
return -1;
}
fclose(fd);
char *token = strtok(buffer, " ");
int i;
for (i=0; i<3; i++) {
token = strtok(NULL, " ");
}
p->ppid = atoi(token);
for (i=0; i<10; i++) {
token = strtok(NULL, " ");
}
p->cputime = atoi(token) * 1000 / HZ;
token = strtok(NULL, " ");
p->cputime += atoi(token) * 1000 / HZ;
for (i=0; i<7; i++) {
token = strtok(NULL, " ");
}
p->starttime = atoi(token) / sysconf(_SC_CLK_TCK);
//read command line
sprintf(exefile,"/proc/%d/cmdline", p->pid);
fd = fopen(exefile, "r");
if (fd==NULL) {
return -1;
}
if (fgets(buffer, sizeof(buffer), fd)==NULL) {
fclose(fd);
return -1;
}
fclose(fd);
strcpy(p->command, buffer);
return 0;
}
static pid_t getppid_of(pid_t pid) {
char statfile[20];
char buffer[1024];
sprintf(statfile, "/proc/%d/stat", pid);
FILE *fd = fopen(statfile, "r");
if (fd==NULL) {
return -1;
}
if (fgets(buffer, sizeof(buffer), fd)==NULL) {
fclose(fd);
return -1;
}
fclose(fd);
char *token = strtok(buffer, " ");
int i;
for (i=0; i<3; i++) {
token = strtok(NULL, " ");
}
return atoi(token);
}
static int is_child_of(pid_t child_pid, pid_t parent_pid) {
int ppid = child_pid;
while (ppid > 1 && ppid != parent_pid) {
ppid = getppid_of(ppid);
}
return ppid == parent_pid;
}
int get_next_process(struct process_iterator *it, struct process *p) {
if (it->dip == NULL) {
//end of processes
return -1;
}
if (it->filter->pid != 0 && !it->filter->include_children) {
int ret = read_process_info(it->filter->pid, p);
//p->starttime += it->boot_time;
closedir(it->dip);
it->dip = NULL;
if (ret != 0) {
return -1;
}
return 0;
}
struct dirent *dit = NULL;
//read in from /proc and seek for process dirs
while ((dit = readdir(it->dip)) != NULL) {
if (strtok(dit->d_name, "0123456789") != NULL) {
continue;
}
p->pid = atoi(dit->d_name);
if (it->filter->pid != 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) {
continue;
}
read_process_info(p->pid, p);
//p->starttime += it->boot_time;
break;
}
if (dit == NULL) {
//end of processes
closedir(it->dip);
it->dip = NULL;
return -1;
}
return 0;
}
int close_process_iterator(struct process_iterator *it) {
if (it->dip != NULL && closedir(it->dip) == -1) {
perror("closedir");
return 1;
}
it->dip = NULL;
return 0;
}

View File

@ -0,0 +1,118 @@
/**
*
* process_iterator_solaris.c
* Copyright (C) 2016 by Jim Mason <jmason at ibinx dot com>
*
* Adapted from process_iterator_linux.c
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
int init_process_iterator(struct process_iterator *it, struct process_filter *filter) {
// open a directory stream to /proc directory
if (!(it->dip = opendir("/proc"))) {
perror("opendir");
return -1;
}
it->filter = filter;
return 0;
}
static int read_process_info(pid_t pid, struct process *p) {
psinfo_t psinfo;
char statfile[32];
p->pid = pid;
sprintf(statfile, "/proc/%ld/psinfo", (long)pid);
FILE *fd = fopen(statfile, "r");
if (!fd) return -1;
if (!fread(&psinfo, sizeof(psinfo), 1, fd)) {
fclose(fd);
return -1;
}
fclose(fd);
p->ppid = psinfo.pr_ppid;
p->cputime = psinfo.pr_time.tv_sec * 1.0e03 + psinfo.pr_time.tv_nsec / 1.0e06;
p->starttime = psinfo.pr_start.tv_sec * 1.0e03 + psinfo.pr_start.tv_nsec / 1.0e06;
strcpy(p->command, psinfo.pr_psargs);
return 0;
}
static pid_t getppid_of(pid_t pid) {
psinfo_t psinfo;
char statfile[32];
sprintf(statfile, "/proc/%ld/psinfo", (long)pid);
FILE *fd = fopen(statfile, "r");
if (!fd) return -1;
if (!fread(&psinfo, sizeof(psinfo), 1, fd)) {
fclose(fd);
return -1;
}
fclose(fd);
return psinfo.pr_ppid;
}
static int is_child_of(pid_t child_pid, pid_t parent_pid) {
int ppid = child_pid;
while(ppid > 1 && ppid != parent_pid)
ppid = getppid_of(ppid);
return ppid == parent_pid;
}
int get_next_process(struct process_iterator *it, struct process *p) {
if (!it->dip) {
// end of processes
return -1;
}
if (it->filter->pid != 0 && !it->filter->include_children) {
int ret = read_process_info(it->filter->pid, p);
closedir(it->dip);
it->dip = NULL;
return ret;
}
// read in from /proc and seek for process dirs
struct dirent *dit;
while ((dit = readdir(it->dip))) {
p->pid = atoi(dit->d_name);
if (it->filter->pid != 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) continue;
read_process_info(p->pid, p);
break;
}
if (!dit) {
// end of processes
closedir(it->dip);
it->dip = NULL;
return -1;
}
return 0;
}
int close_process_iterator(struct process_iterator *it) {
if (it->dip && closedir(it->dip) == -1) {
perror("closedir");
return 1;
}
it->dip = NULL;
return 0;
}

View File

@ -0,0 +1,40 @@
#
# Copyright (C) 2017 McMCC
#
include $(TOPDIR)/rules.mk
PKG_NAME:=dvb-firmware
PKG_VERSION:=1.0
PKG_RELEASE:=2
include $(INCLUDE_DIR)/package.mk
define Package/dvb-firmware
SECTION:=dvb-firmware
CATEGORY:=Firmware
TITLE:=dvb-firmware megapack
endef
define Package/dvb-firmware/description
dvb-firmware is specialised software that is both specific to some hardware
and also integral for its proper functioning.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)/firmware
$(CP) ./src/* $(PKG_BUILD_DIR)/firmware
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/dvb-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware
$(CP) $(PKG_BUILD_DIR)/firmware/* $(1)/lib/firmware
endef
$(eval $(call BuildPackage,dvb-firmware))

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,57 @@
#
# Copyright (C) 2014 nanpuyue <nanpuyue@gmail.com>
# Copyright (C) 2017 Tomasz Maciej Nowak <tomek_n@o2.pl>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME := libdvbcsa
PKG_RELEASE := 1
PKG_SOURCE_PROTO := git
PKG_SOURCE_URL := https://github.com/glenvt18/libdvbcsa.git
PKG_SOURCE_VERSION := 2a1e61e569a621c55c2426f235f42c2398b7f18f
PKG_VERSION := 1.1.0-$(shell printf '%.8s' $(PKG_SOURCE_VERSION))
#PKG_SOURCE := $(PKG_NAME)-$(PKG_VERSION).tar.gz
#PKG_SOURCE_URL := http://download.videolan.org/pub/videolan/libdvbcsa/$(PKG_VERSION)/
#PKG_HASH := 4db78af5cdb2641dfb1136fe3531960a477c9e3e3b6ba19a2754d046af3f456d
PKG_LICENSE := GPL-2.0
PKG_LICENSE_FILE := COPYING
PKG_MAINTAINER := Tomasz Maciej Nowak <tomek_n@o2.pl>
PKG_INSTALL := 1
include $(INCLUDE_DIR)/package.mk
define Package/libdvbcsa
SECTION := libs
CATEGORY := Libraries
TITLE := DVB Common Scrambling Algorithm library
URL := https://www.videolan.org/developers/libdvbcsa.html
endef
define Package/libdvbcsa/description
libdvbcsa is a free implementation of the DVB Common Scrambling
Algorithm - DVB/CSA - with encryption and decryption capabilities
endef
define Build/Configure
(cd $(PKG_BUILD_DIR); ./bootstrap)
$(call Build/Configure/Default)
endef
define Build/InstallDev
$(CP) $(PKG_INSTALL_DIR)/usr $(1)/
endef
define Package/libdvbcsa/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libdvbcsa.so* $(1)/usr/lib/
endef
$(eval $(call BuildPackage,libdvbcsa))

45
package/jsda/fcgiwrap/Makefile Executable file
View File

@ -0,0 +1,45 @@
#
# Copyright (C) 2008-2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=fcgiwrap
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=net
CATEGORY:=Network
TITLE:=FCGI wrapper for CGI
DEPENDS:=+libpcre +spawn-fcgi +fcgi
MAINTAINER:=Tobias Waldvogel <tobias.waldvogel@gmail.com>
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(TARGET_CC) \
-I$(STAGING_DIR)/usr/include $(TARGET_CFLAGS) -Wall -Werror \
-L$(STAGING_DIR)/usr/lib -lfcgi \
-o$(PKG_BUILD_DIR)/$(PKG_NAME) $(PKG_BUILD_DIR)/$(PKG_NAME).c
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/fcgiwrap.init $(1)/etc/init.d/fcgiwrap
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -0,0 +1,62 @@
#!/bin/sh /etc/rc.common
#by guogh
USE_PROCD=1
START=99
SPAWN_FCGI="/usr/bin/spawn-fcgi"
DAEMON="/usr/sbin/fcgiwrap"
NAME="fcgiwrap"
PIDFILE="/var/run/$NAME.pid"
FCGI_SOCKET="/tmp/$NAME.socket"
FCGI_USER="www"
FCGI_GROUP="www"
FORK_NUM=2
start_service() {
echo -e "Starting $NAME ..."
#procd_set_param command $SPAWN_FCGI -u $FCGI_USER -g $FCGI_GROUP -s $FCGI_SOCKET -P $PIDFILE -F $FORK_NUM -f $DAEMON
$SPAWN_FCGI -a 127.0.0.1 -p 9000 -f $DAEMON -F $FORK_NUM
}
stop_service(){
PID=`pidof $NAME`
#i=1
#for p in $PID
#do
# if [ $i -eq 1 ]; then
# let i++
# continue
# fi
# echo -n "$p "
#done
#因为脚本执行时第一个pid是脚本的所以要去除
if [ -n "`echo $PID | grep ' '`" ]; then
SPID=${PID#* }
echo -e "Kill $NAME (PID: $SPID)."
kill -9 $SPID
else
echo -e "Warning: $NAME is not runing."
fi
exit 0
}
restart(){
PID=`pidof $NAME`
#因为脚本执行时第一个pid是脚本的所以要去除
if [ -n "`echo $PID | grep ' '`" ]; then
SPID=${PID#* }
echo -e "Kill $NAME (PID: $SPID)."
kill -9 $SPID
else
echo -e "Warning: $NAME is not runing."
fi
start_service
}

View File

@ -0,0 +1,901 @@
/*
* Copyright (c) 2007-2013 Grzegorz Nosek
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#define NO_FCGI_DEFINES
#include <stdarg.h>
#include <fcgi_stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/types.h>
#include <grp.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
/* glibc doesn't seem to export it */
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX 108
#endif
extern char **environ;
static char * const * inherited_environ;
static const char **allowed_programs;
static size_t allowed_programs_count;
static const char * blacklisted_env_vars[] = {
"AUTH_TYPE",
"CONTENT_LENGTH",
"CONTENT_TYPE",
"GATEWAY_INTERFACE",
"PATH_INFO",
"PATH_TRANSLATED",
"QUERY_STRING",
"REMOTE_ADDR",
"REMOTE_HOST",
"REMOTE_IDENT",
"REMOTE_USER",
"REQUEST_METHOD",
"SCRIPT_NAME",
"SERVER_NAME",
"SERVER_PORT",
"SERVER_PROTOCOL",
"SERVER_SOFTWARE",
NULL,
};
static int stderr_to_fastcgi = 0;
#define FCGI_BUF_SIZE 4096
static int write_all(int fd, char *buf, size_t size)
{
size_t nleft = size;
while (nleft > 0) {
ssize_t nwritten = write(fd, buf, nleft);
if (nwritten < 0)
return nleft - size; /* zero or negative to indicate error */
buf += nwritten;
nleft -= nwritten;
}
return size;
}
#define MAX_VA_SENTINEL INT_MIN
static int max_va(int p1, ...)
{
va_list va;
int max = p1;
int p;
va_start(va, p1);
do {
p = va_arg(va, int);
if (p > max)
max = p;
} while (p != MAX_VA_SENTINEL);
va_end(va);
return max;
}
enum reply_state_t {
REPLY_STATE_INIT,
REPLY_STATE_HEADER,
REPLY_STATE_CR,
REPLY_STATE_LF,
REPLY_STATE_2CR,
REPLY_STATE_2LF,
REPLY_STATE_BODY,
REPLY_STATE_MAX
};
enum char_class_t {
CC_NORMAL,
CC_CR,
CC_LF,
CC_MAX
};
#define ACTION_MASK (15 << 4)
#define ACTION_EMIT 0
#define ACTION_ERROR (1 << 4)
#define ACTION_END (2 << 4)
#define ACTION_SKIP (3 << 4)
#define ACTION_EXTRA_CR (4 << 4)
#define ACTION_EXTRA_LF (5 << 4)
static const unsigned char header_state_machine[REPLY_STATE_MAX][CC_MAX] = {
[REPLY_STATE_INIT] = {
[CC_NORMAL] = REPLY_STATE_HEADER,
[CC_CR] = ACTION_ERROR,
[CC_LF] = ACTION_ERROR,
},
[REPLY_STATE_HEADER] = {
[CC_NORMAL] = REPLY_STATE_HEADER,
[CC_CR] = REPLY_STATE_CR,
[CC_LF] = REPLY_STATE_LF | ACTION_EXTRA_CR,
},
[REPLY_STATE_CR] = {
[CC_NORMAL] = REPLY_STATE_HEADER | ACTION_EXTRA_LF,
[CC_CR] = REPLY_STATE_CR | ACTION_SKIP,
[CC_LF] = REPLY_STATE_LF,
},
[REPLY_STATE_LF] = {
[CC_NORMAL] = REPLY_STATE_HEADER,
[CC_CR] = REPLY_STATE_2CR,
[CC_LF] = REPLY_STATE_2LF | ACTION_EXTRA_CR,
},
[REPLY_STATE_2CR] = {
[CC_NORMAL] = REPLY_STATE_BODY | ACTION_EXTRA_LF,
[CC_CR] = REPLY_STATE_CR | ACTION_SKIP,
[CC_LF] = REPLY_STATE_2LF,
},
[REPLY_STATE_2LF] = {
[CC_NORMAL] = REPLY_STATE_BODY | ACTION_END,
[CC_CR] = REPLY_STATE_BODY | ACTION_END,
[CC_LF] = REPLY_STATE_BODY | ACTION_END,
},
[REPLY_STATE_BODY] = {
[CC_NORMAL] = REPLY_STATE_BODY | ACTION_END,
[CC_CR] = REPLY_STATE_BODY | ACTION_END,
[CC_LF] = REPLY_STATE_BODY | ACTION_END,
},
};
struct fcgi_context {
int fd_stdin;
int fd_stdout;
int fd_stderr;
unsigned int reply_state;
pid_t cgi_pid;
};
static void fcgi_finish(struct fcgi_context *fc, const char* msg)
{
if (fc->reply_state == REPLY_STATE_INIT) {
FCGI_puts("Status: 502 Bad Gateway\nContent-type: text/plain\n");
FCGI_printf("An error occurred while %s\n", msg);
}
if (fc->fd_stdin >= 0) close(fc->fd_stdin);
if (fc->fd_stdout >= 0) close(fc->fd_stdout);
if (fc->fd_stderr >= 0) close(fc->fd_stderr);
if (fc->cgi_pid)
kill(SIGTERM, fc->cgi_pid);
}
static const char * fcgi_pass_fd(struct fcgi_context *fc, int *fdp, FCGI_FILE *ffp, char *buf, size_t bufsize)
{
ssize_t nread;
char *p = buf;
unsigned char cclass, next_state;
nread = read(*fdp, buf, bufsize);
if (nread > 0) {
while (p < buf + nread) {
if (*p == '\r') {
cclass = CC_CR;
} else if (*p == '\n') {
cclass = CC_LF;
} else {
cclass = CC_NORMAL;
}
next_state = header_state_machine[fc->reply_state][cclass];
fc->reply_state = next_state & ~ACTION_MASK;
switch(next_state & ACTION_MASK) {
case ACTION_ERROR:
return "parsing CGI reply";
case ACTION_END:
goto out_of_loop;
case ACTION_SKIP:
goto next_char;
case ACTION_EXTRA_CR:
if (FCGI_fputc('\r', ffp) == EOF) return "writing CGI reply";
break;
case ACTION_EXTRA_LF:
if (FCGI_fputc('\n', ffp) == EOF) return "writing CGI reply";
break;
}
if (FCGI_fputc(*p, ffp) == EOF) {
return "writing CGI reply";
}
next_char:
p++;
}
out_of_loop:
if (p < buf + nread) {
if (FCGI_fwrite(p, 1, buf + nread - p, ffp) != (size_t)(buf + nread - p)) {
return "writing CGI reply";
}
}
} else {
if (nread < 0) {
return "reading CGI reply";
}
close(*fdp);
*fdp = -1;
}
return NULL;
}
static const char * fcgi_pass_raw_fd(int *fdp, int fd_out, char *buf, size_t bufsize)
{
ssize_t nread;
nread = read(*fdp, buf, bufsize);
if (nread > 0) {
if (write_all(fd_out, buf, nread) != nread) {
return "writing CGI reply";
}
} else {
if (nread < 0) {
return "reading CGI reply";
}
close(*fdp);
*fdp = -1;
}
return NULL;
}
static bool fcgi_pass_request(struct fcgi_context *fc)
{
char buf[FCGI_BUF_SIZE];
ssize_t nread;
/* eat the whole request and pass it to CGI */
while ((nread = FCGI_fread(buf, 1, sizeof(buf), FCGI_stdin)) > 0) {
if (write_all(fc->fd_stdin, buf, nread) <= 0) {
fcgi_finish(fc, "reading the request");
return false;
}
}
close(fc->fd_stdin);
fc->fd_stdin = -1;
return true;
}
static void fcgi_pass(struct fcgi_context *fc)
{
char buf[FCGI_BUF_SIZE];
fd_set rset;
int maxfd = 1 + max_va(fc->fd_stdout, fc->fd_stderr, MAX_VA_SENTINEL);
int nready;
const char *err;
if (!fcgi_pass_request(fc))
return;
/* now pass CGI reply back */
while (fc->fd_stdout >= 0 || fc->fd_stderr >= 0) {
FD_ZERO(&rset);
if (fc->fd_stdout >= 0) FD_SET(fc->fd_stdout, &rset);
if (fc->fd_stderr >= 0) FD_SET(fc->fd_stderr, &rset);
nready = select(maxfd, &rset, NULL, NULL, NULL);
if (nready < 0) {
if (errno == EAGAIN) continue;
fcgi_finish(fc, "waiting for CGI reply");
return;
}
if (fc->fd_stdout >= 0 && FD_ISSET(fc->fd_stdout, &rset)) {
err = fcgi_pass_fd(fc, &fc->fd_stdout, FCGI_stdout, buf, sizeof(buf));
if (err) {
fcgi_finish(fc, err);
return;
}
}
if (fc->fd_stderr >= 0 && FD_ISSET(fc->fd_stderr, &rset)) {
if (stderr_to_fastcgi)
err = fcgi_pass_fd(fc, &fc->fd_stderr, FCGI_stderr, buf, sizeof(buf));
else
err = fcgi_pass_raw_fd(&fc->fd_stderr, 2, buf, sizeof(buf));
if (err) {
fcgi_finish(fc, err);
return;
}
}
}
fc->cgi_pid = 0;
fcgi_finish(fc, "reading CGI reply (no response received)");
}
static int check_file_perms(const char *path)
{
struct stat ls;
struct stat fs;
if (lstat(path, &ls) < 0) {
return -ENOENT;
} else if (S_ISREG(ls.st_mode)) {
if (ls.st_mode & S_IXUSR) {
return 0;
} else {
return -EACCES;
}
} else if (!S_ISLNK(ls.st_mode)) {
return -EACCES;
}
if (stat(path, &fs) < 0) {
return -ENOENT;
} else if (S_ISREG(fs.st_mode)) {
if (fs.st_mode & S_IXUSR) {
return 0;
} else {
return -EACCES;
}
} else {
return -EACCES;
}
}
static char *get_cgi_filename(void) /* and fixup environment */
{
int buflen = 1, docrootlen;
char *buf = NULL;
char *docroot, *scriptname, *p;
int rf_len;
char *pathinfo = NULL;
if ((p = getenv("SCRIPT_FILENAME"))) {
if (check_file_perms(p) != 0)
goto err;
return strdup(p);
}
if ((p = getenv("DOCUMENT_ROOT"))) {
docroot = p;
docrootlen = strlen(p);
buflen += docrootlen;
} else {
goto err;
}
if ((p = getenv("SCRIPT_NAME"))) {
buflen += strlen(p);
scriptname = p;
} else {
goto err;
}
buf = malloc(buflen);
if (!buf) goto err;
strcpy(buf, docroot);
strcpy(buf + docrootlen, scriptname);
pathinfo = strdup(buf);
if (!pathinfo) {
goto err;
}
while(1) {
switch(check_file_perms(buf)) {
case -EACCES:
goto err;
case 0:
rf_len = strlen(buf);
if (rf_len < buflen - 1) {
setenv("PATH_INFO", pathinfo + rf_len, 1);
setenv("SCRIPT_NAME", buf + docrootlen, 1);
} else {
unsetenv("PATH_INFO");
}
free(pathinfo);
return buf;
default:
p = strrchr(buf, '/');
if (!p) goto err;
*p = 0;
}
}
err:
free(pathinfo);
free(buf);
return NULL;
}
static int blacklisted_env(const char *var_name, const char *var_name_end)
{
const char **p;
if (var_name_end - var_name > 4 && !strncmp(var_name, "HTTP", 4)) {
/* HTTP_*, HTTPS */
return 1;
}
for (p = blacklisted_env_vars; *p; p++) {
if (!strcmp(var_name, *p)) {
return 1;
}
}
return 0;
}
static void inherit_environment(void)
{
char * const * p;
char *q;
for (p = inherited_environ; *p; p++) {
q = strchr(*p, '=');
if (!q) {
fprintf(stderr, "Suspect value in environment: %s\n", *p);
continue;
}
*q = 0;
if (!getenv(*p) && !blacklisted_env(*p, q)) {
*q = '=';
putenv(*p);
}
*q = '=';
}
}
static bool is_allowed_program(const char *program) {
size_t i;
if (!allowed_programs_count)
return true;
for (i = 0; i < allowed_programs_count; i++) {
if (!strcmp(allowed_programs[i], program))
return true;
}
return false;
}
static void cgi_error(const char *message, const char *reason, const char *filename)
{
printf("Status: %s\r\nContent-Type: text/plain\r\n\r\n%s\r\n",
message, message);
fflush(stdout);
if (filename) {
fprintf(stderr, "%s (%s)\n", reason, filename);
} else {
fputs(reason, stderr);
fputc('\n', stderr);
}
_exit(99);
}
static void handle_fcgi_request(void)
{
int pipe_in[2];
int pipe_out[2];
int pipe_err[2];
char *filename;
char *last_slash;
char *p;
pid_t pid;
struct fcgi_context fc;
if (pipe(pipe_in) < 0) goto err_pipein;
if (pipe(pipe_out) < 0) goto err_pipeout;
if (pipe(pipe_err) < 0) goto err_pipeerr;
switch((pid = fork())) {
case -1:
goto err_fork;
case 0: /* child */
close(pipe_in[1]);
close(pipe_out[0]);
close(pipe_err[0]);
dup2(pipe_in[0], 0);
dup2(pipe_out[1], 1);
dup2(pipe_err[1], 2);
close(pipe_in[0]);
close(pipe_out[1]);
close(pipe_err[1]);
close(FCGI_fileno(FCGI_stdout));
signal(SIGCHLD, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
filename = get_cgi_filename();
inherit_environment();
if (!filename)
cgi_error("403 Forbidden", "Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?", NULL);
if (!is_allowed_program(filename))
cgi_error("403 Forbidden", "The given script is not allowed to execute", filename);
p = getenv("FCGI_CHDIR");
if (p == NULL) {
last_slash = strrchr(filename, '/');
if (!last_slash)
cgi_error("403 Forbidden", "Script name must be a fully qualified path", filename);
*last_slash = 0;
if (chdir(filename) < 0)
cgi_error("403 Forbidden", "Cannot chdir to script directory", filename);
*last_slash = '/';
} else if (strcmp(p, "-") != 0) {
if (chdir(p) < 0) {
cgi_error("403 Forbidden", "Cannot chdir to FCGI_CHDIR directory", p);
}
}
execl(filename, filename, (void *)NULL);
cgi_error("502 Bad Gateway", "Cannot execute script", filename);
default: /* parent */
close(pipe_in[0]);
close(pipe_out[1]);
close(pipe_err[1]);
fc.fd_stdin = pipe_in[1];
fc.fd_stdout = pipe_out[0];
fc.fd_stderr = pipe_err[0];
fc.reply_state = REPLY_STATE_INIT;
fc.cgi_pid = pid;
fcgi_pass(&fc);
}
return;
err_fork:
close(pipe_err[0]);
close(pipe_err[1]);
err_pipeerr:
close(pipe_out[0]);
close(pipe_out[1]);
err_pipeout:
close(pipe_in[0]);
close(pipe_in[1]);
err_pipein:
FCGI_puts("Status: 502 Bad Gateway\nContent-type: text/plain\n");
FCGI_puts("System error");
}
static volatile sig_atomic_t sigint_received ;
static void sigint_handler(int __attribute__((__unused__))dummy)
{
sigint_received = 1;
FCGX_ShutdownPending(); // Or we could send SIGUSR1
}
static void fcgiwrap_main(void)
{
struct sigaction a;
signal(SIGCHLD, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
// Use sigaction for SIGINT so we can avoid SA_RESTART and actually react
a.sa_handler = sigint_handler;
a.sa_flags = 0;
sigemptyset( &a.sa_mask );
sigaction( SIGINT, &a, NULL );
sigaction( SIGTERM, &a, NULL );
inherited_environ = environ;
while (FCGI_Accept() >= 0 && !sigint_received) {
handle_fcgi_request();
}
}
static volatile sig_atomic_t nrunning;
static void sigchld_handler(int dummy)
{
int status;
while ((dummy = waitpid(-1, &status, WNOHANG)) > 0) {
/* sanity check */
if (nrunning > 0)
nrunning--;
/* we _should_ print something about the exit code
* but the sighandler context is _very_ bad for this
*/
}
}
static void prefork(int nchildren)
{
int startup = 1;
if (nchildren == 1) {
return;
}
signal(SIGCHLD, sigchld_handler);
while (1) {
while (nrunning < nchildren) {
pid_t pid = fork();
if (pid == 0) {
return;
} else if (pid != -1) {
nrunning++;
} else {
if (startup) {
fprintf(stderr, "Failed to prefork: %s\n", strerror(errno));
exit(1);
} else {
fprintf(stderr, "Failed to fork: %s\n", strerror(errno));
break;
}
}
}
startup = 0;
pause();
}
}
static int listen_on_fd(int fd) {
int one = 1;
if (listen(fd, 511) < 0) {
perror("Failed to listen");
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) < 0) {
perror("Failed to enable SO_REUSEADDR");
return -1;
}
if (dup2(fd, 0) < 0) {
perror("Failed to move socket to fd 0");
return -1;
}
if (close(fd) < 0) {
perror("Failed to close original socket");
return -1;
}
return 0;
}
static int setup_socket(char *url, gid_t grp) {
char *p = url;
char *q;
int fd;
int port;
size_t sockaddr_size;
union {
struct sockaddr sa;
struct sockaddr_un sa_un;
struct sockaddr_in sa_in;
struct sockaddr_in6 sa_in6;
} sa;
if (!strncmp(p, "unix:", sizeof("unix:") - 1)) {
p += sizeof("unix:") - 1;
if (strlen(p) >= UNIX_PATH_MAX) {
fprintf(stderr, "Socket path too long, exceeds %d characters\n",
UNIX_PATH_MAX);
return -1;
}
sockaddr_size = sizeof sa.sa_un;
sa.sa_un.sun_family = AF_UNIX;
strcpy(sa.sa_un.sun_path, p);
} else if (!strncmp(p, "tcp:", sizeof("tcp:") - 1)) {
p += sizeof("tcp:") - 1;
q = strchr(p, ':');
if (!q) {
goto invalid_url;
}
port = atoi(q+1);
if (port <= 0 || port > 65535) {
goto invalid_url;
}
sockaddr_size = sizeof sa.sa_in;
sa.sa_in.sin_family = AF_INET;
sa.sa_in.sin_port = htons(port);
*q = 0;
if (inet_pton(AF_INET, p, &sa.sa_in.sin_addr) < 1) {
goto invalid_url;
}
} else if (!strncmp(p, "tcp6:[", sizeof("tcp6:[") - 1)) {
p += sizeof("tcp6:[") - 1;
q = strchr(p, ']');
if (!q || !q[0] || q[1] != ':') {
goto invalid_url;
}
port = atoi(q+2);
if (port <= 0 || port > 65535) {
goto invalid_url;
}
sockaddr_size = sizeof sa.sa_in6;
sa.sa_in6.sin6_family = AF_INET6;
sa.sa_in6.sin6_port = htons(port);
*q = 0;
if (inet_pton(AF_INET6, p, &sa.sa_in6.sin6_addr) < 1) {
goto invalid_url;
}
} else {
invalid_url:
fprintf(stderr, "Valid socket URLs are:\n"
"unix:/path/to/socket for Unix sockets\n"
"tcp:dot.ted.qu.ad:port for IPv4 sockets\n"
"tcp6:[ipv6_addr]:port for IPv6 sockets\n");
return -1;
}
fd = socket(sa.sa.sa_family, SOCK_STREAM, 0);
if (fd < 0) {
perror("Failed to create socket");
return -1;
}
if (bind(fd, &sa.sa, sockaddr_size) < 0) {
perror("Failed to bind");
return -1;
}
if (listen_on_fd(fd) < 0) {
return -1;
}
if (sa.sa.sa_family == AF_UNIX && grp != -1) {
chmod(sa.sa_un.sun_path, S_IRUSR | S_IWUSR | S_IXUSR |
S_IRGRP | S_IWGRP | S_IXGRP);
if (chown(sa.sa_un.sun_path, -1, grp))
perror("Could not change owner of socket");
}
return fd;
}
int main(int argc, char **argv)
{
int nchildren = 1;
char *socket_url = NULL;
gid_t gid = -1;
struct group *grp;
int fd = 0;
int c;
while ((c = getopt(argc, argv, "c:hfs:p:g:")) != -1) {
switch (c) {
case 'f':
stderr_to_fastcgi++;
break;
case 'h':
printf("Usage: %s [OPTION]\nInvokes CGI scripts as FCGI.\n\n"
"Options are:\n"
" -f\t\t\tSend CGI's stderr over FastCGI\n"
" -c <number>\t\tNumber of processes to prefork\n"
" -s <socket_url>\tSocket to bind to (say -s help for help)\n"
" -h\t\t\tShow this help message and exit\n"
" -p <path>\t\tRestrict execution to this script. (repeated options will be merged)\n"
" -g group\t\tGrant this group access to unix sockets\n",
argv[0]
);
return 0;
case 'c':
nchildren = atoi(optarg);
break;
case 's':
socket_url = strdup(optarg);
break;
case 'g':
grp = getgrnam(optarg);
if (grp == NULL) {
printf("Group %s does not exist\n", optarg);
abort();
}
gid = grp->gr_gid;
break;
case 'p':
allowed_programs = realloc(allowed_programs, (allowed_programs_count + 1) * sizeof (char *));
if (!allowed_programs)
abort();
allowed_programs[allowed_programs_count++] = strdup(optarg);
break;
case '?':
if (optopt == 'c' || optopt == 's' || optopt == 'p')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf(stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort();
}
}
#ifdef HAVE_SYSTEMD
if (sd_listen_fds(true) > 0) {
/* systemd woke us up. we should never see more than one FD passed to us. */
if (listen_on_fd(SD_LISTEN_FDS_START) < 0) {
return 1;
}
} else
#endif
if (socket_url) {
fd = setup_socket(socket_url, gid);
if (fd < 0) {
return 1;
}
}
prefork(nchildren);
fcgiwrap_main();
if (fd) {
const char *p = socket_url;
close(fd);
if (socket_url) {
if (!strncmp(p, "unix:", sizeof("unix:") - 1)) {
p += sizeof("unix:") - 1;
unlink(p);
}
}
}
return 0;
}

View File

@ -0,0 +1,15 @@
#
#-- Copyright (C) 2018 dz <dingzhong110@gmail.com>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI Support for advancedsetting
LUCI_DEPENDS:=
PKG_VERSION:=1.1
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,13 @@
#-- Copyright (C) 2018 dz <dingzhong110@gmail.com>
module("luci.controller.advancedsetting", package.seeall)
function index()
if not nixio.fs.access("/etc/config/advancedsetting") then
return
end
local page
page = entry({"admin", "system", "advancedsetting"}, cbi("advancedsetting"), _("Advanced Setting"), 60)
page.dependent = true
end

View File

@ -0,0 +1,75 @@
#-- Copyright (C) 2018 dz <dingzhong110@gmail.com>
local fs = require "nixio.fs"
local sys = require "luci.sys"
m = Map("advancedsetting", translate("Advanced Setting"), translate("Direct editing of built-in Script Documents for various services, unless you know what you are doing, do not easily modify these configuration documents"))
s = m:section(TypedSection, "advancedsetting")
s.anonymous=true
--dnsmasq
if nixio.fs.access("/etc/dnsmasq.conf") then
s:tab("config1", translate("dnsmasq"),translate("This page is the document content for configuring /etc/dnsmasq.conf. Restart takes effect after application is saved"))
conf = s:taboption("config1", Value, "editconf1", nil, translate("Each line of the opening numeric symbol (#) or semicolon (;) is considered a comment; delete (;) and enable the specified option."))
conf.template = "cbi/tvalue"
conf.rows = 20
conf.wrap = "off"
function conf.cfgvalue(self, section)
return fs.readfile("/etc/dnsmasq.conf") or ""
end
function conf.write(self, section, value)
if value then
value = value:gsub("\r\n?", "\n")
fs.writefile("/tmp/dnsmasq.conf", value)
if (luci.sys.call("cmp -s /tmp/dnsmasq.conf /etc/dnsmasq.conf") == 1) then
fs.writefile("/etc/dnsmasq.conf", value)
luci.sys.call("/etc/init.d/dnsmasq restart >/dev/null")
end
fs.remove("/tmp/dnsmasq.conf")
end
end
end
--network
if nixio.fs.access("/etc/config/network") then
s:tab("config2", translate("network"),translate("This page is the document content for configuring /etc/config/network. Restart takes effect after application is saved"))
conf = s:taboption("config2", Value, "editconf2", nil, translate("Each line of the opening numeric symbol (#) or semicolon (;) is considered a comment; delete (;) and enable the specified option."))
conf.template = "cbi/tvalue"
conf.rows = 20
conf.wrap = "off"
function conf.cfgvalue(self, section)
return fs.readfile("/etc/config/network") or ""
end
function conf.write(self, section, value)
if value then
value = value:gsub("\r\n?", "\n")
fs.writefile("/tmp/netwok", value)
if (luci.sys.call("cmp -s /tmp/network /etc/config/network") == 1) then
fs.writefile("/etc/config/network", value)
luci.sys.call("/etc/init.d/network restart >/dev/null")
end
fs.remove("/tmp/network")
end
end
end
--hosts
if nixio.fs.access("/etc/hosts") then
s:tab("config3", translate("hosts"),translate("This page is the document content for configuring /etc/hosts. Restart takes effect after application is saved"))
conf = s:taboption("config3", Value, "editconf3", nil, translate("Each line of the opening numeric symbol (#) or semicolon (;) is considered a comment; delete (;) and enable the specified option."))
conf.template = "cbi/tvalue"
conf.rows = 20
conf.wrap = "off"
function conf.cfgvalue(self, section)
return fs.readfile("/etc/hosts") or ""
end
function conf.write(self, section, value)
if value then
value = value:gsub("\r\n?", "\n")
fs.writefile("/tmp/etc/hosts", value)
if (luci.sys.call("cmp -s /tmp/etc/hosts /etc/hosts") == 1) then
fs.writefile("/etc/hosts", value)
luci.sys.call("/etc/init.d/dnsmasq restart >/dev/null")
end
fs.remove("/tmp/etc/hosts")
end
end
end
return m

View File

@ -0,0 +1,21 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "Advanced Setting"
msgstr "高级设置"
msgid "Direct editing of built-in Script Documents for various services, unless you know what you are doing, do not easily modify these configuration documents"
msgstr "各类服务内置脚本文档的直接编辑,除非你知道自己在干什么,否则请不要轻易修改这些配置文档"
msgid "This page is the document content for configuring /etc/dnsmasq.conf. Restart takes effect after application is saved"
msgstr "本页是配置/etc/dnsmasq.conf的文档内容。应用保存后重启生效"
msgid "Each line of the opening numeric symbol (#) or semicolon (;) is considered a comment; delete (;) and enable the specified option."
msgstr "开头的数字符号(#)或分号的每一行(;)被视为注释;删除(;)启用指定选项。"
msgid "This page is the document content for configuring /etc/config/network. Restart takes effect after application is saved"
msgstr "本页是配置/etc/config/network的文档内容。"
msgid "This page is the document content for configuring /etc/hosts. Restart takes effect after application is saved"
msgstr "本页是配置/etc/hosts的文档内容。"

View File

@ -0,0 +1 @@
config advancedsetting

View File

@ -0,0 +1,84 @@
#
# Copyright (C) 2018 chenhw2 <https://github.com/chenhw2/>
#
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-aliddns
PKG_VERSION:=0.3.0
PKG_RELEASE:=1
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=chenhw2 <https://github.com/chenhw2/>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/luci-app-aliddns
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=3. Applications
TITLE:=LuCI Support for aliddns
PKGARCH:=all
DEPENDS:=+openssl-util +curl
endef
define Package/luci-app-aliddns/description
LuCI Support for ALiDDNS.
endef
define Build/Prepare
$(foreach po,$(wildcard ${CURDIR}/files/luci/i18n/*.po), \
po2lmo $(po) $(PKG_BUILD_DIR)/$(patsubst %.po,%.lmo,$(notdir $(po)));)
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/luci-app-aliddns/postinst
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
if [ -f /etc/uci-defaults/luci-aliddns ]; then
( . /etc/uci-defaults/luci-aliddns ) && \
rm -f /etc/uci-defaults/luci-aliddns
fi
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
fi
exit 0
endef
define Package/luci-app-aliddns/prerm
#!/bin/sh
/etc/init.d/aliddns stop
exit 0
endef
define Package/luci-app-aliddns/conffiles
/etc/config/aliddns
endef
define Package/luci-app-aliddns/install
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
$(INSTALL_DATA) $(PKG_BUILD_DIR)/aliddns.*.lmo $(1)/usr/lib/lua/luci/i18n/
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
$(INSTALL_DATA) ./files/luci/controller/*.lua $(1)/usr/lib/lua/luci/controller/
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi/aliddns
$(INSTALL_DATA) ./files/luci/model/cbi/*.lua $(1)/usr/lib/lua/luci/model/cbi/
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/root/etc/config/aliddns $(1)/etc/config/aliddns
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/root/etc/init.d/aliddns $(1)/etc/init.d/aliddns
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/root/etc/uci-defaults/luci-aliddns $(1)/etc/uci-defaults/luci-aliddns
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/root/usr/sbin/aliddns $(1)/usr/sbin/aliddns
endef
$(eval $(call BuildPackage,luci-app-aliddns))

View File

@ -0,0 +1,4 @@
module("luci.controller.aliddns",package.seeall)
function index()
entry({"admin","services","aliddns"},cbi("aliddns"),_("AliDDNS"),58)
end

View File

@ -0,0 +1,44 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "AliDDNS"
msgstr "阿里DDNS"
msgid "enable"
msgstr "启用"
msgid "Clean Before Update"
msgstr "清除所有同名记录"
msgid "Base"
msgstr "基本设置"
msgid "WAN-IP Source"
msgstr "WAN-IP来源"
msgid "Select WAN-IP Source"
msgstr "选择WAN-IP来源"
msgid "Select the WAN-IP Source for AliDDNS, like wan/internet"
msgstr "动态域名的IP来源如wan/internet"
msgid "Main Domain"
msgstr "主域名"
msgid "Sub Domain"
msgstr "子域名"
msgid "For example: test.github.com -> github.com"
msgstr "例如: test.github.com 则填: github.com"
msgid "For example: test.github.com -> test"
msgstr "例如: test.github.com, 则填: test"
msgid "Inspection Time"
msgstr "检查时间"
msgid "Unit: Minute, Range: 1-59"
msgstr "域名检查间隔时间单位分钟范围1-59"
msgid "Update Log"
msgstr "更新记录"

View File

@ -0,0 +1,56 @@
local a=require"luci.sys"
local e=luci.model.uci.cursor()
local e=require"nixio.fs"
require("luci.sys")
local t,e,o
t=Map("aliddns",translate("AliDDNS"))
e=t:section(TypedSection,"base",translate("Base"))
e.anonymous=true
enable=e:option(Flag,"enable",translate("enable"))
enable.rmempty=false
enable=e:option(Flag,"clean",translate("Clean Before Update"))
enable.rmempty=false
token=e:option(Value,"app_key",translate("Access Key ID"))
email=e:option(Value,"app_secret",translate("Access Key Secret"))
iface=e:option(ListValue,"interface",translate("WAN-IP Source"),translate("Select the WAN-IP Source for AliDDNS, like wan/internet"))
iface:value("",translate("Select WAN-IP Source"))
iface:value("internet")
iface:value("wan")
iface.rmempty=false
main=e:option(Value,"main_domain",translate("Main Domain"),translate("For example: test.github.com -> github.com"))
main.rmempty=false
sub=e:option(Value,"sub_domain",translate("Sub Domain"),translate("For example: test.github.com -> test"))
sub.rmempty=false
time=e:option(Value,"time",translate("Inspection Time"),translate("Unit: Minute, Range: 1-59"))
time.rmempty=false
e=t:section(TypedSection,"base",translate("Update Log"))
e.anonymous=true
local a="/var/log/aliddns.log"
tvlog=e:option(TextValue,"sylogtext")
tvlog.rows=16
tvlog.readonly="readonly"
tvlog.wrap="off"
function tvlog.cfgvalue(e,e)
sylogtext=""
if a and nixio.fs.access(a) then
sylogtext=luci.sys.exec("tail -n 100 %s"%a)
end
return sylogtext
end
tvlog.write=function(e,e,e)
end
local e=luci.http.formvalue("cbi.apply")
if e then
io.popen("/etc/init.d/aliddns restart")
end
return t

View File

@ -0,0 +1,4 @@
config base 'base'
option enable '0'
option time '10'

View File

@ -0,0 +1,64 @@
#!/bin/sh /etc/rc.common
START=80
NAME=aliddns
NE_TIPS='AliDDNS NOT ENABLED'
restart() {
start
}
uci_get_by_name() {
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
echo ${ret:=$3}
}
uci_bool_by_name() {
case "$(uci_get_by_name $1 $2)" in
1|on|true|yes|enabled) return 0;;
esac
return 1
}
add_hotplug() {
cat <<EOF > "/etc/hotplug.d/iface/${START}-${NAME}"
#!/bin/sh /etc/rc.common
[ "Z\$ACTION" = "Zifup" -a "Z\$INTERFACE" = "Zwan" ] || exit 0
DATE=\$(date +'%Y-%m-%d %H:%M:%S')
( sleep 10 && ( echo "\$DATE IFUP-WAN" && /usr/sbin/aliddns ) >> /var/log/aliddns.log 2>&1 ) &
exit 0
EOF
chmod +x "/etc/hotplug.d/iface/${START}-${NAME}"
}
start() {
$(uci_bool_by_name base enable) || {
stop
return 0
}
add_hotplug
sed -i "/${NE_TIPS}/d" /var/log/aliddns.log
time=$(uci_get_by_name base time 10)
[ 0 -lt $time -a $time -lt 60 ] || time=10
[ -f /etc/crontabs/root ] || mkdir -p /etc/crontabs && touch /etc/crontabs/root
sed -i '/aliddns/d' /etc/crontabs/root
echo "*/$time * * * * /usr/sbin/aliddns >> /var/log/aliddns.log 2>&1" >> /etc/crontabs/root
/etc/init.d/cron restart
( /usr/sbin/aliddns >> /var/log/aliddns.log 2>&1 ) &
}
stop() {
rm -rf "/etc/hotplug.d/iface/${START}-${NAME}"
sed -i '/aliddns/d' /etc/crontabs/root >/dev/null 2>&1
/etc/init.d/cron restart
echo "${NE_TIPS}" > /var/log/aliddns.log
}

View File

@ -0,0 +1,10 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@aliddns[-1]
add ucitrack aliddns
set ucitrack.@aliddns[-1].init=aliddns
commit ucitrack
EOF
exit 0

View File

@ -0,0 +1,164 @@
#!/bin/sh
NAME=aliddns
log_file=/var/log/$NAME.log
uci_get_by_name() {
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
echo ${ret:=$3}
}
uci_bool_by_name() {
case "$(uci_get_by_name $1 $2)" in
1|on|true|yes|enabled) return 0;;
esac
return 1
}
intelnetip() {
tmp_ip=`curl -sL --connect-timeout 3 ns1.dnspod.net:6666`
if [ "Z$tmp_ip" == "Z" ]; then
tmp_ip=`curl -sL --connect-timeout 3 members.3322.org/dyndns/getip`
fi
if [ "Z$tmp_ip" == "Z" ]; then
tmp_ip=`curl -sL --connect-timeout 3 14.215.150.17:6666`
fi
if [ "Z$tmp_ip" == "Z" ]; then
tmp_ip=`curl -sL --connect-timeout 3 whatismyip.akamai.com`
fi
echo -n $tmp_ip
}
resolve2ip() {
# resolve2ip domain<string>
domain=$1
tmp_ip=`nslookup $domain ns1.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
if [ "Z$tmp_ip" == "Z" ]; then
tmp_ip=`nslookup $domain ns2.alidns.com 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
fi
if [ "Z$tmp_ip" == "Z" ]; then
tmp_ip=`nslookup $domain 114.114.115.115 2>/dev/null | sed '/^Server/d; /#53$/d' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n1`
fi
if [ "Z$tmp_ip" == "Z" ]; then
tmp_ip=`curl -sL --connect-timeout 3 "119.29.29.29/d?dn=$domain"`
fi
echo -n $tmp_ip
}
check_aliddns() {
echo "$DATE WAN-IP: ${ip}"
if [ "Z$ip" == "Z" ]; then
echo "$DATE ERROR, cant get WAN-IP..."
return 0
fi
current_ip=$(resolve2ip "$sub_dm.$main_dm")
if [ "Z$current_ip" == "Z" ]; then
rrid='' # NO Resolve IP Means new Record_ID
fi
echo "$DATE DOMAIN-IP: ${current_ip}"
if [ "Z$ip" == "Z$current_ip" ]; then
echo "$DATE IP dont need UPDATE..."
return 0
else
echo "$DATE UPDATING..."
return 1
fi
}
urlencode() {
# urlencode url<string>
out=''
for c in $(echo -n $1 | sed 's/[^\n]/&\n/g'); do
case $c in
[a-zA-Z0-9._-]) out="$out$c" ;;
*) out="$out$(printf '%%%02X' "'$c")" ;;
esac
done
echo -n $out
}
send_request() {
# send_request action<string> args<string>
local args="AccessKeyId=$ak_id&Action=$1&Format=json&$2&Version=2015-01-09"
local hash=$(urlencode $(echo -n "GET&%2F&$(urlencode $args)" | openssl dgst -sha1 -hmac "$ak_sec&" -binary | openssl base64))
curl -sSL --connect-timeout 5 "http://alidns.aliyuncs.com/?$args&Signature=$hash"
}
get_recordid() {
sed 's/RR/\n/g' | sed -n 's/.*RecordId[^0-9]*\([0-9]*\).*/\1\n/p' | sort -ru | sed /^$/d
}
query_recordid() {
send_request "DescribeSubDomainRecords" "SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&SubDomain=$sub_dm.$main_dm&Timestamp=$timestamp"
}
update_record() {
send_request "UpdateDomainRecord" "RR=$sub_dm&RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=A&Value=$ip"
}
add_record() {
send_request "AddDomainRecord&DomainName=$main_dm" "RR=$sub_dm&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp&Type=A&Value=$ip"
}
del_record() {
send_request "DeleteDomainRecord" "RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$timestamp&SignatureVersion=1.0&Timestamp=$timestamp"
}
do_ddns_record() {
if uci_bool_by_name base clean ; then
query_recordid | get_recordid | while read rr; do
echo "$DATE Clean record $sub_dm.$main_dm: $rr"
del_record $rr >/dev/null
timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ")
done
rrid=''
fi
if [ "Z$rrid" == "Z" ]; then
rrid=`query_recordid | get_recordid`
fi
if [ "Z$rrid" == "Z" ]; then
rrid=`add_record | get_recordid`
echo "$DATE ADD record $rrid"
else
update_record $rrid >/dev/null 2>&1
echo "$DATE UPDATE record $rrid"
fi
if [ "Z$rrid" == "Z" ]; then
# failed
echo "$DATE # ERROR, Please Check Config/Time"
else
# save rrid
uci set aliddns.base.record_id=$rrid
uci commit aliddns
echo "$DATE # UPDATED($ip)"
fi
}
clean_log() {
if [ $(cat $log_file 2>/dev/null | wc -l) -ge 16 ]; then
rm -f $log_file && touch $log_file
echo "$DATE Log Cleaned"
fi
}
[ -x /usr/bin/openssl -a -x /usr/bin/curl -a -x /bin/sed ] ||
( echo "Need [ openssl + curl + sed ]" && exit 1 )
ak_id=$(uci_get_by_name base app_key)
ak_sec=$(uci_get_by_name base app_secret)
rrid=$(uci_get_by_name base record_id)
main_dm=$(uci_get_by_name base main_domain)
sub_dm=$(uci_get_by_name base sub_domain)
iface=$(uci_get_by_name base interface)
if [ "Z$iface" == "Zinternet" -o "Z$iface" == "Z" ]; then
ip=$(intelnetip)
else
ip=$(ubus call network.interface.$iface status | grep '"address"' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
fi
DATE=$(date +'%Y-%m-%d %H:%M:%S')
timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ")
clean_log
check_aliddns || do_ddns_record

Some files were not shown because too many files have changed in this diff Show More